I am setting FK to an object from a previous form submission, but I can't seem to figure out why I am getting a null constraint error. I have scoured SO and reddit for similar issues, but I think that I am missing something simple here (or I just can't wrap my brain around the FK concept).
error:
Internal Server Error: /district/
Traceback (most recent call last):
File "/root/areports/venv/lib/python3.6/site-packages/django/db/backends/utils.py", line 85, in _execute
return self.cursor.execute(sql, params)
File "/root/areports/venv/lib/python3.6/site-packages/django/db/backends/sqlite3/base.py", line 296, in execute
return Database.Cursor.execute(self, query, params)
sqlite3.IntegrityError: NOT NULL constraint failed: reports_attendance_entry.event_id
The above exception was the direct cause of the following exception:
Traceback (most recent call last):
File "/root/areports/venv/lib/python3.6/site-packages/django/core/handlers/exception.py", line 34, in inner
response = get_response(request)
File "/root/areports/venv/lib/python3.6/site-packages/django/core/handlers/base.py", line 126, in _get_response
response = self.process_exception_by_middleware(e, request)
File "/root/areports/venv/lib/python3.6/site-packages/django/core/handlers/base.py", line 124, in _get_response
response = wrapped_callback(request, *callback_args, **callback_kwargs)
File "/root/areports/reports/views.py", line 39, in new_district_view
new_district.save()
File "/root/areports/venv/lib/python3.6/site-packages/django/forms/models.py", line 458, in save
self.instance.save()
File "/root/areports/venv/lib/python3.6/site-packages/django/db/models/base.py", line 718, in save
force_update=force_update, update_fields=update_fields)
File "/root/areports/venv/lib/python3.6/site-packages/django/db/models/base.py", line 748, in save_base
updated = self._save_table(raw, cls, force_insert, force_update, using, update_fields)
File "/root/areports/venv/lib/python3.6/site-packages/django/db/models/base.py", line 831, in _save_table
result = self._do_insert(cls._base_manager, using, fields, update_pk, raw)
File "/root/areports/venv/lib/python3.6/site-packages/django/db/models/base.py", line 869, in _do_insert
using=using, raw=raw)
File "/root/areports/venv/lib/python3.6/site-packages/django/db/models/manager.py", line 82, in manager_method
return getattr(self.get_queryset(), name)(*args, **kwargs)
File "/root/areports/venv/lib/python3.6/site-packages/django/db/models/query.py", line 1136, in _insert
return query.get_compiler(using=using).execute_sql(return_id)
File "/root/areports/venv/lib/python3.6/site-packages/django/db/models/sql/compiler.py", line 1289, in execute_sql
cursor.execute(sql, params)
File "/root/areports/venv/lib/python3.6/site-packages/django/db/backends/utils.py", line 100, in execute
return super().execute(sql, params)
File "/root/areports/venv/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 "/root/areports/venv/lib/python3.6/site-packages/django/db/backends/utils.py", line 77, in _execute_with_wrappers
return executor(sql, params, many, context)
File "/root/areports/venv/lib/python3.6/site-packages/django/db/backends/utils.py", line 85, in _execute
return self.cursor.execute(sql, params)
File "/root/areports/venv/lib/python3.6/site-packages/django/db/utils.py", line 89, in __exit__
raise dj_exc_value.with_traceback(traceback) from exc_value
File "/root/areports/venv/lib/python3.6/site-packages/django/db/backends/utils.py", line 85, in _execute
return self.cursor.execute(sql, params)
File "/root/areports/venv/lib/python3.6/site-packages/django/db/backends/sqlite3/base.py", line 296, in execute
return Database.Cursor.execute(self, query, params)
django.db.utils.IntegrityError: NOT NULL constraint failed: reports_attendance_entry.event_id
models.py
class Event_Profile(models.Model):
content_area = models.CharField(max_length=120) #max_length = required
event_date = models.DateField(default=datetime.date.today) # Need to make this more flexible
event_location = models.CharField(max_length=120)
workshop_number = models.CharField(max_length=15)
cost_per_person = models.DecimalField(max_digits=10,decimal_places=2)
#def __str__(self):
#return self.name
# Create an attendance listing for an existing event
class Attendance_Entry(models.Model):
event = models.ForeignKey('Event_Profile', on_delete=models.CASCADE)
district_name = models.CharField(max_length=120)
number_registered = models.PositiveIntegerField()
number_of_noshows = models.PositiveIntegerField()
#def __str__(self):
#return self.name
forms.py
# Create a new event with the below fields
class New_Event_Form(forms.ModelForm):
content_area = forms.ModelChoiceField(
queryset=Content_Area.objects.all(),
required=True)
event_date = forms.DateField(
label = 'Event Date',
required=True,
initial=datetime.datetime.today().strftime('%Y-%m-%d'))
event_location = forms.ChoiceField(
choices = location_list,
required=True,
widget = forms.RadioSelect())
workshop_number = forms.CharField(
required=False)
cost_per_person = forms.DecimalField(
required=True,
decimal_places=2,
label='Cost/Person',
initial="0.00")
class Meta:
model = Event_Profile
fields = [
'content_area',
'event_date',
'event_location',
'workshop_number',
'cost_per_person'
]
# Add a district to a corresponding event and carry over the id from the event listing to event_id
class New_District_Form(forms.ModelForm):
district_name = forms.ModelChoiceField(
queryset = District.objects.all(),
required=True)
number_registered = forms.IntegerField(
help_text = 'Input the total number registered for this workshop / event.',
required = True,
label = "Number Registered",
validators=[MinValueValidator(0)])
number_of_noshows = forms.IntegerField(
help_text = 'Input the total number of no-shows from this district.',
label = "Number No-Shows")
class Meta:
model = Attendance_Entry
fields = [
'district_name',
'number_registered',
'number_of_noshows'
]
# Validation to make certain that the reg value is not greater than no-shows
def clean(self):
cleaned_data = super().clean()
registered = cleaned_data.get("number_registered")
noshows = cleaned_data.get("number_of_noshows")
if registered and noshows:
# Only do something if both fields are valid so far.
if noshows > registered:
# If the number of no-shows is greater than registrants, then raise a non_field_error
raise forms.ValidationError(
"The number of registered participants cannot exceed "
"the number of no-shows for the event."
)
views.py
from django.http import HttpResponseRedirect
from django.shortcuts import render
from django.urls import reverse
from .forms import New_Event_Form, New_District_Form
from .models import Event_Profile, Attendance_Entry
def entry_create_view(request):
form = New_Event_Form(request.POST or None)
if form.is_valid():
entry = form.save()
# if the form data passes validation, save the form and add id to request session
request.session['event_id'] = entry.id
# reverse to a new view - add a district view
return HttpResponseRedirect(reverse('new_district_view'))
else:
# used as a signal to indicate an invalid form submission attempt
print('Invalid')
context = {
'form': form,
}
return render(request, "entry_create.html", context)
def new_district_view(request):
# Need to get the event details from the associated event entry
try:
profile = Event_Profile.objects.get(id = request.session['event_id'])
except:
print("Couldn't create the event")
try:
districts = Attendance_Entry.objects.all().filter(event_id = request.session['event_id'])
except:
districts = []
new_district = New_District_Form(request.POST or None)
if new_district.is_valid():
new_district.save(commit=False)
new_district.event = profile
new_district.save()
new_district = New_District_Form()
context = {
"new_district": new_district,
"profile": profile,
"districts": districts
}
return render(request, "new_district.html", context)
else:
print('Invalid')
context = {
"new_district": new_district,
"profile": profile,
"districts": districts
}
return render(request, "new_district.html", context)
# Junk view assignment until I can replace it with a proper menu
def home_view(request):
return render(request, "home.html", {})
答案 0 :(得分:0)
我假设您没有从clean
方法返回任何内容。您需要这样做:
def clean(self):
cleaned_data = super().clean()
registered = cleaned_data.get("number_registered")
noshows = cleaned_data.get("number_of_noshows")
if registered and noshows:
# Only do something if both fields are valid so far.
if noshows > registered:
# If the number of no-shows is greater than registrants, then raise a non_field_error
raise forms.ValidationError(
"The number of registered participants cannot exceed "
return cleaned_data # <-- Here
实际上问题出在这里
new_district.save(commit=False) # <- here
new_district.event = profile
new_district.save()
应该是这样的:
instance = new_district.save(commit=False)
instance.event = profile
instance.save()
发生的事情是,表单的save(...)
函数返回实例(已保存或未保存)。您需要将其存储在变量中,并在需要时向其添加更多属性,然后再次保存以将其提交到数据库。