skip to Main Content

(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


  1. The error state the problem, you are sending text instead of Author object in books object.

    The issue is in this line

    saverecord.author=request.POST.get('author')
    

    There can be two ways to fix this.

    1. 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’))

    2. 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

    Login or Signup to reply.
  2. The issue happens because when creating a Book instance the model expects a reference to an instance of the Author model. Yet, what you are trying to assign is a plain string retrieved from the request data request.POST.get('author').

    As pointed out by @Art in the comments, you need to retrieve the Author instance first and then set at the Book instance field.

    author = get_object_or_404(Author, name=request.POST.get('author'))
    ...
    saverecord.author = author
    

    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

    class BookForm(forms.ModelForm):
        book_id = forms.IntegerField(
            widget=forms.NumberInput(attrs={"placeholder": "Enter book ID..."})
        )
        author = forms.ModelChoiceField(
            Author.objects.all(),
            empty_label="Select an Author...",
            widget=forms.Select(attrs={"style": "width: 100%"}),
        )
    
        class Meta:
            model = Book
            fields = "__all__"
            widgets = {
                "title": forms.TextInput(attrs={"placeholder": "Enter Book Title..."}),
                "isbn": forms.TextInput(attrs={"placeholder": "Enter ISBN..."}),
                "publisher": forms.TextInput(attrs={"placeholder": "Enter Publisher..."}),
                "genre": forms.TextInput(attrs={"placeholder": "WHAT", "value": ""}),
            }
            labels = {
                "book_id": "Book ID",
                "isbn": "ISBN",
            }
    

    views.py

    def Insertbook(request):
        form = BookForm()
        if request.method == "POST":
            form = BookForm(request.POST)
            if form.is_valid():
                # Create manually instead of form.save() because of ID field.
                instance = Book.objects.create(**form.cleaned_data)
                messages.success(
                    request, "Book " + instance.title + " Is Saved Successfully..!"
                )
    
        return render(request, "Insert_book.html", {"form": form})
    
    
    def Updatebook(request, book_id):
        """This view does not update the ID field"""
    
        book = Book.objects.get(book_id=book_id)
        if request.method == "POST":
            form = BookForm(request.POST, instance=book)
            if form.is_valid():
                form.save()
                messages.success(request, "Record Update Successfully..!")
    
        form = BookForm(instance=book)
        return render(request, "Update_book.html", {"form": form, "book": book})
    

    Update_book.html

    <body>
      <style>
        .container {
          display: flex;
          flex-flow: column nowrap;
          justify-content: center;
          align-items: center;
        }
    
        table, th, td {
          border: 1px solid rgba(255, 255, 255, 0.5);
        }
    
        hr {
          width: 100%;
        }
      </style>
    
      <div class="container">
        <h1>DjangoBookStore</h1>
        <hr />
        {% if messages %}
        <ul class="messages">
          {% for message in messages %}
          <li {% if message.tags %} class="{{ message.tags }}" {% endif %}>
            {{ message }}
          </li>
          {% endfor %}
        </ul>
        {% endif %}
    
        <form
          method="POST"
          action="{% url 'Updatebook' book.book_id %}"
          style="text-align: center"
        >
          {% csrf_token %}
          <table>
            {{ form.as_table }}
            <tr>
              <th colspan="2">
                <button style="width: 100%">Insert</button>
              </th>
            </tr>
          </table>
          <a href="{% url 'index' %}">Home Page</a>
        </form>
    
      </div>
    </body>
    

    <center> tag and table border attribute are deprecated and must be replaced by CSS.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search