I'm creating a school, kinda, and I get NOT NULL constraint failed: courses_course.owner_id
whenever I try to create a course via the URL http://127.0.0.1:8000/course/create/
. Here are my files:
models.py
from django.db import models
from django.contrib.auth.models import User
from django.contrib.contenttypes.models import ContentType
from django.contrib.contenttypes.fields import GenericForeignKey
from .fields import OrderField
class Subject(models.Model):
title = models.CharField(max_length=200)
slug = models.SlugField(max_length=200, unique=True)
class Meta:
ordering = ('title',)
def __str__(self):
return self.title
class Course(models.Model):
owner = models.ForeignKey(User, on_delete=models.CASCADE, related_name='courses_created')
subject = models.ForeignKey(Subject, on_delete=models.CASCADE, related_name='courses')
title = models.CharField(max_length=200)
slug = models.SlugField(max_length=200, unique=True)
overview = models.TextField()
created = models.DateTimeField(auto_now_add=True)
class Meta:
ordering = ('-created',)
def __str__(self):
return self.title
class Module(models.Model):
course = models.ForeignKey(Course, on_delete=models.CASCADE, related_name='modules')
title = models.CharField(max_length=200)
description = models.TextField(blank=True)
order = OrderField(blank=True, for_fields=['course'])
class Meta:
ordering = ['order']
def __str__(self):
return '{}. {}'.format(self.order, self.title)
class Content(models.Model):
module = models.ForeignKey(Module, on_delete=models.CASCADE, related_name='contents')
content_type = models.ForeignKey(ContentType, on_delete=models.CASCADE, limit_choices_to={
'model__in':('text', 'video', 'image', 'file')
})
object_id = models.PositiveIntegerField()
item = GenericForeignKey('content_type', 'object_id')
order = OrderField(blank=True, for_fields=['module'])
class Meta:
ordering = ['order']
class ItemBase(models.Model):
owner = models.ForeignKey(User, on_delete=models.CASCADE, related_name='%(class)s_related')
title = models.CharField(max_length=200)
created = models.DateTimeField(auto_now_add=True)
updated = models.DateTimeField(auto_now=True)
class Meta:
abstract = True
def __str__(self):
return self.title
class Text(ItemBase):
content = models.TextField()
class File(ItemBase):
file = models.FileField(upload_to='files')
class Image(ItemBase):
file = models.FileField(upload_to='images')
class Video(ItemBase):
url = models.URLField()
urls.py (in the courses app)
from django.urls import path
from . import views
urlpatterns = [
path('mine/', views.ManageCourseListView.as_view(),
name='manage_course_list'),
path('create/', views.CourseCreateView.as_view(),
name='course_create'),
path('<int:pk>/edit', views.CourseUpdateView.as_view(),
name='course_edit'),
path('<int:pk>/delete', views.CourseDeleteView.as_view(),
name='course_delete'),
]
urls.py (base)
from django.contrib import admin
from django.urls import include, path
from django.contrib.auth import views as auth_views
from courses import views
urlpatterns = [
path('', views.home, name='home'),
path('login/', auth_views.login, name='login'),
path('logout/', auth_views.logout, name='logout'),
path('admin/', admin.site.urls),
path('course/', include('courses.urls')),
]
'views.py'
from django.shortcuts import render
from django.urls import reverse_lazy
from django.views.generic.list import ListView
from django.views.generic.edit import CreateView, UpdateView, DeleteView
from django.contrib.auth.mixins import LoginRequiredMixin, PermissionRequiredMixin
from .models import Subject, Course
def home(request):
subjects = Subjects.objects.all()
return render(request, 'home.html', {'subjects' : subjects})
class OwnerMixin(object):
def get_queryset(self):
qs = super(OwnerMixin, self).get_queryset()
return qs.filter(owner=self.request.user)
class OwnerEditMixin(object):
def form_valid(self, form):
form.instance.owner = self.request.user
return super(OwnerEditMixin, self).form_valid(form)
class OwnerCourseMixin(OwnerMixin, LoginRequiredMixin):
model = Course
fields = ['subject', 'title', 'slug', 'overview']
success_url = reverse_lazy('manage_course_list')
class OwnerCourseEditMixin(OwnerCourseMixin, OwnerEditMixin):
fields = ['subject', 'title', 'slug', 'overview']
success_url = reverse_lazy('manage_course_list')
template_name = 'courses/manage/course/form.html'
class ManageCourseListView(OwnerCourseMixin, ListView):
template_name = 'courses/manage/course/list.html'
class CourseCreateView(OwnerCourseEditMixin, CreateView, PermissionRequiredMixin):
template_name = 'courses/manage/course/form.html'
permission_required = 'courses.can_add'
class CourseUpdateView(OwnerCourseEditMixin, UpdateView, PermissionRequiredMixin):
template_name = 'courses/manage/course/form.html'
permission_required = 'courses.can_change'
class CourseDeleteView(OwnerCourseMixin, DeleteView, PermissionRequiredMixin):
template_name = 'courses/manage/course/delete.html'
success_url = reverse_lazy('manage_course_list')
permission_required = 'courses.can_delete'
And the traceback from the terminal:
Internal Server Error: /course/create/
Traceback (most recent call last):
File "/home/caspian/Documents/Programming/Websites/school/schenv/lib/python3.6/site-packages/django/db/backends/utils.py", line 85, in _execute
return self.cursor.execute(sql, params)
File "/home/caspian/Documents/Programming/Websites/school/schenv/lib/python3.6/site-packages/django/db/backends/sqlite3/base.py", line 303, in execute
return Database.Cursor.execute(self, query, params)
sqlite3.IntegrityError: NOT NULL constraint failed: courses_course.owner_id
The above exception was the direct cause of the following exception:
Traceback (most recent call last):
File "/home/caspian/Documents/Programming/Websites/school/schenv/lib/python3.6/site-packages/django/core/handlers/exception.py", line 35, in inner
response = get_response(request)
File "/home/caspian/Documents/Programming/Websites/school/schenv/lib/python3.6/site-packages/django/core/handlers/base.py", line 128, in _get_response
response = self.process_exception_by_middleware(e, request)
File "/home/caspian/Documents/Programming/Websites/school/schenv/lib/python3.6/site-packages/django/core/handlers/base.py", line 126, in _get_response
response = wrapped_callback(request, *callback_args, **callback_kwargs)
File "/home/caspian/Documents/Programming/Websites/school/schenv/lib/python3.6/site-packages/django/views/generic/base.py", line 69, in view
return self.dispatch(request, *args, **kwargs)
File "/home/caspian/Documents/Programming/Websites/school/schenv/lib/python3.6/site-packages/django/contrib/auth/mixins.py", line 52, in dispatch
return super().dispatch(request, *args, **kwargs)
File "/home/caspian/Documents/Programming/Websites/school/schenv/lib/python3.6/site-packages/django/views/generic/base.py", line 89, in dispatch
return handler(request, *args, **kwargs)
File "/home/caspian/Documents/Programming/Websites/school/schenv/lib/python3.6/site-packages/django/views/generic/edit.py", line 172, in post
return super().post(request, *args, **kwargs)
File "/home/caspian/Documents/Programming/Websites/school/schenv/lib/python3.6/site-packages/django/views/generic/edit.py", line 142, in post
return self.form_valid(form)
File "/home/caspian/Documents/Programming/Websites/school/schenv/lib/python3.6/site-packages/django/views/generic/edit.py", line 125, in form_valid
self.object = form.save()
File "/home/caspian/Documents/Programming/Websites/school/schenv/lib/python3.6/site-packages/django/forms/models.py", line 456, in save
self.instance.save()
File "/home/caspian/Documents/Programming/Websites/school/schenv/lib/python3.6/site-packages/django/db/models/base.py", line 729, in save
force_update=force_update, update_fields=update_fields)
File "/home/caspian/Documents/Programming/Websites/school/schenv/lib/python3.6/site-packages/django/db/models/base.py", line 759, in save_base
updated = self._save_table(raw, cls, force_insert, force_update, using, update_fields)
File "/home/caspian/Documents/Programming/Websites/school/schenv/lib/python3.6/site-packages/django/db/models/base.py", line 842, in _save_table
result = self._do_insert(cls._base_manager, using, fields, update_pk, raw)
File "/home/caspian/Documents/Programming/Websites/school/schenv/lib/python3.6/site-packages/django/db/models/base.py", line 880, in _do_insert
using=using, raw=raw)
File "/home/caspian/Documents/Programming/Websites/school/schenv/lib/python3.6/site-packages/django/db/models/manager.py", line 82, in manager_method
return getattr(self.get_queryset(), name)(*args, **kwargs)
File "/home/caspian/Documents/Programming/Websites/school/schenv/lib/python3.6/site-packages/django/db/models/query.py", line 1125, in _insert
return query.get_compiler(using=using).execute_sql(return_id)
File "/home/caspian/Documents/Programming/Websites/school/schenv/lib/python3.6/site-packages/django/db/models/sql/compiler.py", line 1280, in execute_sql
cursor.execute(sql, params)
File "/home/caspian/Documents/Programming/Websites/school/schenv/lib/python3.6/site-packages/django/db/backends/utils.py", line 100, in execute
return super().execute(sql, params)
File "/home/caspian/Documents/Programming/Websites/school/schenv/lib/python3.6/site-packages/django/db/backends/utils.py", line 68, in execute
return self._execute_with_wrappers(sql, params, many=False, executor=self._execute)
File "/home/caspian/Documents/Programming/Websites/school/schenv/lib/python3.6/site-packages/django/db/backends/utils.py", line 77, in _execute_with_wrappers
return executor(sql, params, many, context)
File "/home/caspian/Documents/Programming/Websites/school/schenv/lib/python3.6/site-packages/django/db/backends/utils.py", line 85, in _execute
return self.cursor.execute(sql, params)
File "/home/caspian/Documents/Programming/Websites/school/schenv/lib/python3.6/site-packages/django/db/utils.py", line 89, in __exit__
raise dj_exc_value.with_traceback(traceback) from exc_value
File "/home/caspian/Documents/Programming/Websites/school/schenv/lib/python3.6/site-packages/django/db/backends/utils.py", line 85, in _execute
return self.cursor.execute(sql, params)
File "/home/caspian/Documents/Programming/Websites/school/schenv/lib/python3.6/site-packages/django/db/backends/sqlite3/base.py", line 303, in execute
return Database.Cursor.execute(self, query, params)
django.db.utils.IntegrityError: NOT NULL constraint failed: courses_course.owner_id
[02/Feb/2018 14:15:29] "POST /course/create/ HTTP/1.1" 500 180238
I already tried recreating my database and it's still not working
If you try to print CourseCreateView's MRO you will see this:
(<class 'test.CourseCreateView'>, <class 'test.OwnerCourseEditMixin'>, <class 'test.OwnerCourseMixin'>, <class 'test.OwnerMixin'>, <class 'django.contrib.auth.mixins.LoginRequiredMixin'>, <class 'django.views.generic.edit.CreateView'>, <class 'django.views.generic.detail.SingleObjectTemplateResponseMixin'>, <class 'django.views.generic.base.TemplateResponseMixin'>, <class 'django.views.generic.edit.BaseCreateView'>, <class 'django.views.generic.edit.ModelFormMixin'>, <class 'django.views.generic.edit.FormMixin'>, <class 'django.views.generic.detail.SingleObjectMixin'>, <class 'django.views.generic.base.ContextMixin'>, <class 'django.views.generic.edit.ProcessFormView'>, <class 'django.views.generic.base.View'>, <class 'django.contrib.auth.mixins.PermissionRequiredMixin'>, <class 'django.contrib.auth.mixins.AccessMixin'>, <class 'test.OwnerEditMixin'>, <class 'object'>)
As you can see OwnerEditMixin
located after generic CreateView
so your custom form_valid
is never called. To fix this you can separate OwnerCourseEditMixin
and OwnerEditMixin
:
class OwnerCourseEditMixin(OwnerCourseMixin):
fields = ['subject', 'title', 'slug', 'overview']
template_name = 'courses/manage/course/form.html'
And add OwnerEditMixin
to the View's parents before CreateView
:
class CourseCreateView(OwnerCourseEditMixin, OwnerEditMixin, CreateView, PermissionRequiredMixin):
template_name = 'courses/manage/course/form.html'
permission_required = 'courses.can_add'