(https://i.sstatic.net/EiBqboZP.png)
In the browser, I’m trying to add a new book to my books table but I keep receiving a Value error from django where for example I can’t assign "’Virginia Woolf’": "Book.author" must be a "Author" instance. After I enter all the fields to add a new book and then click the Insert button in the browser, I receive the Value error. Below is the structure of my sql table as well as related python scripts for reference:
--Create the books table
CREATE TABLE books (
book_id SERIAL PRIMARY KEY,
title VARCHAR(200) NOT NULL,
author_id INTEGER REFERENCES authors(author_id),
genre VARCHAR(50),
price DECIMAL(10, 2),
publisher VARCHAR(100),
--Adding the column for the ISBN to populate the table with an extra instance
isbn VARCHAR(20)
);
--Create the videos table
CREATE TABLE videos (
video_id SERIAL PRIMARY KEY,
title VARCHAR(200) NOT NULL,
genre VARCHAR(50),
price DECIMAL(10, 2),
publisher VARCHAR(100),
release_date DATE
);
views.py:
from django.shortcuts import render
from bookstore.models import Author, Book
from django.contrib import messages
from bookstore.forms import Authorforms, Bookforms
def index(request):
return render(request, 'index.html')
def author(request):
allauthor=Author.objects.all()
return render(request, 'author_list.html', {'authors': allauthor})
def Insertauthor(request):
if request.method=="POST":
if request.POST.get('author_id') and request.POST.get('name') and request.POST.get('birthdate') and request.POST.get('nationality'):
saverecord=Author()
saverecord.author_id=request.POST.get('author_id')
saverecord.name=request.POST.get('name')
saverecord.birthdate=request.POST.get('birthdate')
saverecord.nationality=request.POST.get('nationality')
saverecord.save()
messages.success(request,'author ' +saverecord.author_id+ ' Is Saved Successfully..!')
return render(request,'Insert_author.html')
else:
return render(request,'Insert_author.html')
def Editauthor(request, author_id):
editauthorobj=Author.objects.get(author_id=author_id)
return render(request, 'Edit_author.html',{"Author": editauthorobj})
def Updateauthor(request, author_id):
updateauthorobj=Author.objects.get(author_id=author_id)
form=Authorforms(request.POST,instance=updateauthorobj)
if form.is_valid():
form.save()
messages.success(request, 'Record Update Successfully..!')
return render(request, 'Edit_author.html',{"Author" :updateauthorobj})
def Deleteauthor(request, author_id):
deleteauthor=Author.objects.get(author_id=author_id)
deleteauthor.delete()
showdata=Author.objects.all()
return render(request,"author_list.html",{"Author": showdata})
##################################################################################
def book(request):
allbooks=Book.objects.all()
return render(request, 'book_list.html', {'books': allbooks})
def Insertbook(request):
if request.method=="POST":
if request.POST.get('book_id') and request.POST.get('title') and request.POST.get('author') and request.POST.get('isbn') and request.POST.get('publisher') and request.POST.get('genre') and request.POST.get('price'):
saverecord=Book()
saverecord.book_id=request.POST.get('book_id')
saverecord.title=request.POST.get('title')
saverecord.author=request.POST.get('author')
saverecord.isbn=request.POST.get('isbn')
saverecord.publisher=request.POST.get('publisher')
saverecord.genre=request.POST.get('genre', 'unknown')
saverecord.price=request.POST.get('price', 0.0)
saverecord.save()
messages.success(request,'Book ' + saverecord.title + ' Is Saved Successfully..!')
return render(request,'Insert_book.html')
else:
return render(request,'Insert_book.html')
def Editbook(request, book_id):
editbookobj=Book.objects.get(book_id=book_id)
return render(request, 'Edit_book.html',{"Book": editbookobj})
def Updatebook(request, book_id):
updatebookobj=Book.objects.get(book_id=book_id)
form=Bookforms(request.POST,instance=updatebookobj)
if form.is_valid():
form.save()
messages.success(request, 'Record Update Successfully..!')
return render(request, 'Edit_book.html',{"Book" :updatebookobj})
def Deletebook(request, book_id):
deletebook=Book.objects.get(book_id=book_id)
deletebook.delete()
showdata=Book.objects.all()
return render(request,"book_list.html",{"Book": showdata})
urls.py:
from django.contrib import admin
from django.urls import path
from . import views
urlpatterns = [
path('admin/', admin.site.urls),
path('', views.index, name='index'),
path('author/',views.author,name="author"),
path('author/Insert/',views.Insertauthor,name="Insertauthor"),
path('author/Edit/<int:author_id>/',views.Editauthor,name="Editauthor"),
path('author/Update/<int:author_id>/',views.Updateauthor,name="Updateauthor"),
path('author/Delete/<int:author_id>/',views.Deleteauthor,name="Deleteauthor"),
path('book/',views.book,name="book"),
path('book/Insert/',views.Insertbook,name="Insertbook"),
path('book/Edit/<int:book_id>/',views.Editbook,name="Editbook"),
path('book/Update/<int:book_id>/',views.Updatebook,name="Updatebook"),
path('book/Delete/<int:book_id>/',views.Deletebook,name="Deletebook"),
]
models.py:
from django.db import models
class Author(models.Model):
author_id = models.AutoField(primary_key=True)
name = models.CharField(max_length=100)
birthdate = models.DateField(default='1900-01-01')
nationality = models.CharField(max_length=100, default="Unknown")
class Meta:
db_table = 'authors'
class Book(models.Model):
book_id = models.AutoField(primary_key=True)
title = models.CharField(max_length=200)
author = models.ForeignKey(Author, on_delete=models.CASCADE)
isbn = models.CharField(max_length=13, unique=True)
publisher = models.CharField(max_length=100)
genre = models.CharField(max_length=50, default="Unknown")
price = models.DecimalField(max_digits=8, decimal_places=2, default=0.00)
class Meta:
db_table = 'books'
admin.py:
from django.contrib import admin
from .models import Author, Book
# Register your models here.
admin.site.register(Author)
admin.site.register(Book)
Insert_book.html
<!DOCTYPE html>
<html>
<head>
<title>DjangoBookStore</title>
</head>
<body>
<center>
<h1>DjangoBookStore</h1>
<hr/>
<form method="POST">
{% csrf_token %}
<table border="1">
<tr>
<td>Book ID</td>
<td><input type="text" placeholder="Enter Book ID.." name="book_id"></td>
</tr>
<tr>
<td>Title</td>
<td><input type="text" placeholder="Enter Book Title.." name="title"></td>
</tr>
<tr>
<td>Author</td>
<td><input type="text" placeholder="Enter Author.." name="author"></td>
</tr>
<tr>
<td>ISBN</td>
<td><input type="text" placeholder="Enter ISBN.." name="isbn"></td>
</tr>
<tr>
<td>Publisher</td>
<td><input type="text" placeholder="Enter Publisher.." name="publisher"></td>
</tr>
<tr>
<td>Genre</td>
<td><input type="text" placeholder="Enter Genre.." name="genre"></td>
</tr>
<tr>
<td>Price</td>
<td><input type="text" placeholder="Enter Price.." name="price"></td>
</tr>
<tr>
<td><input type="submit" value="Insert"></td>
<td> {% if messages %}
{% for mess in messages %}
<b style="color: green;">{{mess}}</b>
{% endfor %}
{% endif %}
</td>
</tr>
</table>
<a href="{% url 'index' %}">Home Page</a>
</form>
</center>
</body>
</html>
book_list.html
<!DOCTYPE html>
<html>
<head>
<title>DjangoBookStore</title>
</head>
<body>
<center>
<h1>DjangoBookStore</h1>
<hr/>
<a href="{% url 'Insertbook' %}">Create New Book</a>
<table border = "1">
<tr>
<th>Book ID</th>
<th>Title</th>
<th>Author</th>
<th>ISBN</th>
<th>Publisher</th>
<th>Genre</th>
<th>Price</th>
</tr>
{% for book in books %}
<tr>
<td>{{book.book_id}}</td>
<td>{{book.title}}</td>
<td>{{book.author}}</td>
<td>{{book.isbn}}</td>
<td>{{book.publisher}}</td>
<td>{{book.genre}}</td>
<td>{{book.price}}</td>
<td><a href="Edit/{{book.book_id}}">Edit</a></td>
<td><a href="Delete/{{book.book_id}}" onclick="return confirmation('Are You Sure You Want To Delete The Record?')">Delete</a></td>
</tr>
{% endfor %}
</table>
</center>
</body>
</html>
To resovle the issue I’ve tried changing the reference in the views.py Insertbook function from saverecord.author=request.POST.get(‘author’) to saverecord.author.name=request.POST.get(‘author’) which shows another error that author is not a column in the books table.
2
Answers
The error state the problem, you are sending text instead of Author object in books object.
The issue is in this line
There can be two ways to fix this.
Dirty way, this will work with minimal changes, but you need to type author name exactly same as it is saved in DB. Just changes the line no 59 like this
saverecord.author=Author.objects.get(name=request.POST.get(‘author’))
Better Approach, change the auther from text field to drop down, this will ensure that only existing author can be selected.
for implementing this approach you need to send author list to html and render as dropdown
Best way to use django form link
The issue happens because when creating a
Book
instance the model expects a reference to an instance of theAuthor
model. Yet, what you are trying to assign is a plain string retrieved from the request datarequest.POST.get('author')
.As pointed out by @Art in the comments, you need to retrieve the
Author
instance first and then set at theBook
instance field.Although, I need to point out that besides overworking yourself you are missing some core features by not using the full potential of the framework. In this case the
Forms
, despite the fact that you have them (from bookstore.forms import Authorforms, Bookforms
) they are not being used properly.An example on how to adapt your code:
forms.py
views.py
Update_book.html
<center>
tag and tableborder
attribute are deprecated and must be replaced by CSS.