Home > Back-end >  Django: Why my objects do not add database correctly?
Django: Why my objects do not add database correctly?

Time:11-12

I am working on a simple Django project and suffice to say I am just a beginner. I have 2 classes in models.py:

from django.db import models
from django.db.models.deletion import CASCADE

class Category(models.Model):
    category_name=models.CharField(max_length=225,null=True)
    def __str__(self):
        return f"ID: {self.category_name}"

class Book(models.Model):
    cover_img = models.URLField(max_length=200, null=True)
    author=models.CharField(max_length=128,null=True)
    summery=models.TextField(max_length=1000,null=True)
    category = models.ForeignKey(Category,related_name="book_categories",on_delete=CASCADE,null=True)

    def __str__(self):
        return f"{self.cover_img} ,{self.author},{self.summery}"

On the first page of my website(Menu.html), I create a button for each category using jinja:

<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="UTF-8">
        <meta http-equiv="X-UA-Compatible" content="IE=edge">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <link href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-1BmE4kWBq78iYhFldvKuhfTAU6auU8tT94WrHftjDbrCEXSU1oBoqyl2QvZ6jIW3" crossorigin="anonymous">
        <script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/js/bootstrap.bundle.min.js" integrity="sha384-ka7Sk0Gln4gmtz2MlQnikT1wXgYsOg OMhuP IlRH9sENBO0LRn5q 8nbTov4 1p" crossorigin="anonymous"></script>
        <script src="https://cdn.jsdelivr.net/npm/@popperjs/[email protected]/dist/umd/popper.min.js" integrity="sha384-7 zCNj/IqJ95wo16oMtfsKbZ9ccEh31eOz1HGyDuCQ6wgnyJNSYdrPa03rtR1zdB" crossorigin="anonymous"></script>
        <script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/js/bootstrap.min.js" integrity="sha384-QJHtvGhmr9XOIpI6YVutG 2QOK9T ZnN4kzFN1RtK3zEFEIsxhlmWl5/YESvpZ13" crossorigin="anonymous"></script>
        <title>Menu</title>
    </head>
    <body>
        {% for cat in categories %}
        <a type="button" class="btn btn-danger" href="{% url 'cat_detail' cat.id %}">
            <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-book" viewBox="0 0 16 16">
                <path d="M1 2.828c.885-.37 2.154-.769 3.388-.893 1.33-.134 2.458.063 3.112.752v9.746c-.935-.53-2.12-.603-3.213-.493-1.18.12-2.37.461-3.287.811V2.828zm7.5-.141c.654-.689 1.782-.886 3.112-.752 1.234.124 2.503.523 3.388.893v9.923c-.918-.35-2.107-.692-3.287-.81-1.094-.111-2.278-.039-3.213.492V2.687zM8 1.783C7.015.936 5.587.81 4.287.94c-1.514.153-3.042.672-3.994 1.105A.5.5 0 0 0 0 2.5v11a.5.5 0 0 0 .707.455c.882-.4 2.303-.881 3.68-1.02 1.409-.142 2.59.087 3.223.877a.5.5 0 0 0 .78 0c.633-.79 1.814-1.019 3.222-.877 1.378.139 2.8.62 3.681 1.02A.5.5 0 0 0 16 13.5v-11a.5.5 0 0 0-.293-.455c-.952-.433-2.48-.952-3.994-1.105C10.413.809 8.985.936 8 1.783z"/>
            </svg>{{cat.category_name}}
        </a>
        {% endfor %}
    </body>
</html>

Then If the user clicks on one of these buttons he/she will be redirected to a page that contains all the books with the same category. In the second part of my project, I want to implement a method for adding objects to my Database. my views.py:

from django.shortcuts import redirect, render
from .models import *

# Create your views here.


def first_page(request):
    context = {"categories" : Category.objects.all}
    return render(request, 'Menu.html', context)

def category_detail(request, id):
    try:
        my_object_base_category = Book.objects.filter(category__id=id)
    except Book.DoesNotExist:
        my_object_base_category = None
    return render(request, "Book.html", {'key':my_object_base_category})


def add_a_new_book(request):
    context = {"categories" : Category.objects.all}
    if request.method == "POST":
        cover_img = request.POST.get('cover_img')
        author = request.POST.get('author')
        summery = request.POST.get('summery')
        category = request.POST.get('category__category_name')
        myobj = Book(cover_img = cover_img , author = author , summery = summery, category = category)

        myobj.save()
        return render(request, "Menu.html")
    elif request.method == "GET":
        # print("Get in Create")
        return render(request, 'AddBook.html',context)

And here is my form in AddBook.html:

<form action="{% url 'Blog:add_book' %}" method="POST">
    {% csrf_token %}
    <div class="form-row">
        <div class="form-group col-md-6">
            <label for="author">Author</label>
            <input type="text" class="form-control" id="author" placeholder="Author">
        </div>
        <div class="form-group col-md-6">
            <label for="cover_img">Cover Image Link</label>
            <input type="url" class="form-control" id="cover_img" placeholder="Cover Image Link">
        </div>
    </div>
    <div class="form-group">
        <label for="summery">Summary</label>
        <input type="text" class="form-control" id="summery" placeholder="Summary">
    </div>
    <div class="form-group col-md-4">
        <label for="category">Category</label>
        <select id="category" class="form-control">
            {% for i in categories %}
            <option value="{{ i.category_name }}">{{ i.category_name }}</option>
            {% endfor %}
        </select>
    </div>
    <br><br><br><br><br><br><br><br><br>
    <input type="submit" class="btn btn-primary" value="add">
</form>

But there are two problems with my codes. The first one is that after I add a new object, it saves all the values equal to NULL. And the second one is that after clicking on the add button, it does not redirect to another page. Here is my urls.py file in my application:

from django.urls import path
from . import views

app_name = 'Blog'

urlpatterns = [
    path('Menu/', views.first_page, name='category_buttons'),
    path('<int:id>/', views.category_detail, name='cat_detail'),
    path('add', views.add_a_new_book, name='add_book')
]

I will be really grateful for any help or advice. Thanks.

CodePudding user response:

Your html form input fields all need to have a name attribute in order to get their values from a POST request. If an input in your form does not have a name attribute its value isn't even passed along in the request at all.

For example your author input field should be something like:

<input type="text" class="form-control" id="author" name="author" placeholder="Author">

The reason why all the values are being stored as Null in your database is because when you are trying to get a value from your request in the view, the request can't find a value for the key you are looking for so it returns None. For example, your line in your view

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

is returning None because it cannot find a key that has the name 'author' because none of your inputs in the html are named 'author'.

Edit to answer your other question from the comments:

This is assuming your category names are all unique. In your form you need to change your select option to have a name. Something like this:

<select id="category" class="form-control" name="category">

In your view to get the category object that you want you should do something like this:

category = request.POST.get('category')
category_object = Category.objects.get(category_name=category)

Then you pass the category_object variable in to your new book object when you are creating it.

myobj = Book(cover_img = cover_img , author = author , summery = summery, category = category_object)
myobj.save()
  • Related