Get category id for item from Django url

It looks like something simple and common, but I can’t find what’s wrong in my implementation.

I create a simple item add/edit form in my Django project for items by categories. The form will be located at /<category_id>/add. After filling data on form, it can just get category from category_id.

I try to fill this data in form_valid method of FormView, but all I got is error:

IntegrityError at /1/add NOT NULL constraint failed: megashop_item.category_id

I’ve tried print(“boo”) in my form_valid method - nothing is printed, looks like a validation throws exception before. Looks like it’s ItemCreateView validation, but how to fix it?

How to fix it? All examples are about using functions, not views.

models.py

class Category(models.Model):
    title = models.CharField(max_length=200)

class Item (models.Model):
    category = models.ForeignKey(Category, on_delete=models.CASCADE)
    title = models.CharField(max_length=200)

forms.py

class ItemForm(forms.ModelForm):
    class Meta:
        model = Story
        fields = ["title", "category"]

urls.py

urlpatterns = [
    path("<int:category_id>/add", ItemCreateView.as_view(), name="item-add"),
]

views.py

class ItemCreateView(LoginRequiredMixin, CreateView):
    model = Category
    form_class = ItemForm

class ItemFormView(LoginRequiredMixin, FormView):
    template_name = "megashop/item_form.html"
    form_class = ItemForm
    success_url = reverse_lazy("catalog:index")
    def form_valid(self, form):
        instance = form.save(commit=False)
        instance.category= Category.objects.get(pk=self.kwargs.get('category_id'))
        form.save()
        return HttpResponseRedirect(self.get_success_url())

Please post the complete error with the traceback.

If the issue is being caused in ItemCreateView, also please post CategoryForm.

I’m sorry, I made some erratas when I’ve simplified my models.
ItemCreateView uses ItemForm, of course.

  • /home/rikki/dev/thermophore/.venv/lib/python3.10/site-packages/django/db/backends/utils.py, line 89, in _execute
    return self.cursor.execute(sql, params)

  • /home/rikki/dev/thermophore/.venv/lib/python3.10/site-packages/django/db/backends/sqlite3/base.py, line 328, in execute

    1. return super().execute(query, params)

Looks like form.save(commit=False) calls it, but sounds like I’m wrong.

def form_valid(self, form):
    print('before save')
    instance = form.save(commit=False)
    print('after save')
    print(self.kwargs.get('category_id'))
    instance.category_id = self.kwargs.get('category_id')
    instance.category = Category.objects.get(pk=self.kwargs.get('category_id'))
    form.save()
    return HttpResponseRedirect(self.get_success_url())

But I don’t see “before save” or “after save” in log

Please post the complete view in question.

Also, that seems to be extremely short for a full traceback in this situation. Please post the complete traceback.

Finally, depending upon how you’re running your project, output from a print call is usually buffered. When an exception is thrown, the buffers aren’t necessarily flushed. You either need to indicate that the buffer needs to be flushed in every print call, or run python using unbuffered output, otherwise, you have no guarantees that the output from print will be written.

I’m sorry, it was my fault. I’ve put def form_valid to ItemFormView, but linked POST url with CategoryFormView