Django - NOT NULL constraint failed - python

I'm currently working on a Django app that will parse the contents of an uploaded log file to the associated database in my Django project. I've managed to get it all running as expected except it won't associate my uploaded data with the model's ForeignKey. I can assign null=True which resolves the integrity error but then of course, it doesn't assign any of the uploaded data to that ForeignKey. Here's the code:
models.py
class Case(models.Model):
case_ref = models.CharField(max_length=8)
oic = models.CharField(max_length=50)
subject = models.CharField(max_length=100)
submitted_date = models.DateTimeField(default=datetime.now, blank=True)
def get_absolute_url(self):
return reverse('case_list', kwargs={'pk': self.pk})
def __str__(self):
return self.case_ref + " " + self.subject
class TeamviewerLogs(models.Model):
case = models.ForeignKey(Case, on_delete=models.DO_NOTHING)
teamviewer_id = models.IntegerField()
teamviewer_name = models.TextField()
connection_start = models.TextField()
connection_end = models.TextField()
local_user = models.TextField()
connection_type = models.TextField()
unique_id = models.TextField()
def get_absolute_url(self):
return reverse('case_list', kwargs={'pk': self.pk})
def __str__(self):
return str(self.teamviewer_id) + " - " + str(self.teamviewer_id)
forms.py
class UploadLog(forms.ModelForm):
file = forms.FileField()
class Meta:
model = TeamviewerLogs
fields = [
'file'
]
views.py
def add_logs(request, pk):
case = get_object_or_404(Case, pk=pk)
if request.method == 'POST':
form = UploadLog(request.POST, request.FILES)
if form.is_valid():
teamviewer = form.save(commit=False)
teamviewer.case = case
log_file = request.FILES['file']
log_file = filter(None, (line.rstrip() for line in log_file))
for lines in log_file:
split = lines.decode('utf-8').split('\t')
teamviewer_id = split[0]
teamviewer_name = split[1]
connection_start = split[2]
connection_end = split[3]
local_user = split[4]
connection_type = split[5]
unique_id = split[6]
teamviewer = TeamviewerLogs(teamviewer_id=teamviewer_id, teamviewer_name=teamviewer_name,
connection_start=connection_start, connection_end=connection_end,
local_user=local_user, connection_type=connection_type, unique_id=unique_id)
teamviewer.save()
return redirect('tv_log_details', pk=case.pk)
form.save()
else:
form = UploadLog()
return render(request, 'teamviewer/add_logs.html', {'form': form})
But when I click to upload the file I'm hit with:
When it tries to execute teamviewer.save().
I've been trying to resolve this issue for hours and have tried so many different variations of answers from Stackoverflow or previous code I've used that has worked for different models but I've hit a brick wall...hard!
Any help anyone can offer would be greatly appreciated.

Ok, so here's an example of the concept I've suggested in the comments.
I've got a view which passes some data to the a form;
class ListingDetailView(DetailView):
""" Listing detail page """
model = Listing
template_name = 'listing.html'
def get_form_kwargs(self):
"""Return the kwargs for the form"""
kwargs = {}
initial = {
'listing': self.object,
}
kwargs['initial'] = initial
return kwargs
def get_form(self):
form = ApplicationSignupForm(
**self.get_form_kwargs()
)
return form
def get_context_data(self, **kwargs):
""" Add our form to the context """
context = super().get_context_data(**kwargs)
context['form'] = self.get_form()
return context
The form then makes use of that initial data and sets the field it relates to as hidden. I don't validate this data, but I'll try to show how you might do that;
class ApplicationSignupForm(forms.ModelForm):
class Meta:
""" Setup the form """
fields = (
'listing',
...
)
model = Application
widgets = {
'listing': forms.HiddenInput()
}
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
initial_data = kwargs['initial']
self.listing = initial_data.get('listing')
def clean(self):
"""
Custom form cleaning
"""
cleaned_data = super().clean()
listing = cleaned_data.get('listing')
if listing != self.listing:
self.add_error('listing', "You can't modify this value")
return cleaned_data

Related

Django ModelForm not getting instance data

I have a model form that have multiple choice fields. using AJAX to update form choic fields upon changed field.
Model:
class Student(models.Model):
CLASSROOM = 0
GROUPROOM = 1
HOMEROOM = 3
STUDENT_RECORD_TYPES = [
(CLASSROOM,_("Classroom")),
(GROUPROOM,_("Group")),
(HOMEROOM,_("Home Edu")),
]
school = models.ForeignKey(School,on_delete=models.CASCADE,blank=False,related_name='student_records')
grade = models.ForeignKey(Grade,on_delete=models.CASCADE,blank=False,related_name="student_records")
record_type = models.PositiveSmallIntegerField(_("Record Type"),choices=STUDENT_RECORD_TYPES,default=0)
class Meta:
constraints = [
models.UniqueConstraint(
fields=['school','grade', 'record_type'],
name='unique_school_grade_record'
),
]
def __str__(self):
return "Record ID: {}".format(self.pk)
Views.py:
def update_students(request,pk):
updated_table=None
student_record = get_object_or_404(Student,pk=pk)
if request.POST:
form = StudentForm(request.POST or None,instance=student_record)
if form.is_valid():
form.save()
messages.success(request,_("Student record Updated Successfully!"))
#Getting data for view
updated_table = update_students_table(request)
else:
messages.error(request,_("Invalid Input, Please check!"))
else:
form = StudentForm(request.GET or None,instance=student_record)
context = {}
# load form template
context['form'] = form
form_template_path = "components/forms/student_update.html"
html_form = loader.render_to_string(form_template_path, context, request)
context['form'] = html_form
return JsonResponse(context)
Forms.py:
class StudentForm(forms.ModelForm):
def __init__(self, *args, **kwargs):
super(StudentForm, self).__init__(*args, **kwargs)
for visible in self.visible_fields():
visible.field.widget.attrs['class'] = 'form-control'
self.fields['school'].widget.attrs['class'] += ' select2'
#the issue stands here
#self.data.get('school') returns none even if its exist in form data
if self.data.get('school'):
self.fields['grade'].queryset = Grade.objects.filter(school=self.data.get('school'))
else:
self.fields['grade'].queryset = Grade.objects.none()
class Meta:
model = Student
fields = '__all__'
the strange behavior drives me crazy because when I reselect the school it updates the grade choices normally (with no option selected!), but when I open edit instance form the data is there but grade field have no options in it!

Passing logged in user to form

I am trying to pass logged in user to form that i would like to save.
forms.py
class SpotForm(ModelForm):
def __init__(self, *args, **kwargs):
super(SpotForm, self).__init__(*args, **kwargs)
self.fields['gross_weight'].widget = forms.NumberInput(attrs={'min':0})
self.fields['volume'].widget = forms.NumberInput(attrs={'min': 0})
class Meta:
model = Spot
fields = [
'gross_weight','volume','origin_country','origin_port',
'dest_country','dest_port','ship_week','requestor'
]
models.py
class Stakeholder(models.Model):
user = models.OneToOneField(User,null=True,blank=True,on_delete=models.CASCADE)
company_name = models.CharField(max_length=15)
mail = models.CharField(max_length=40)
def __str__(self):
return self.mail
class Spot(models.Model):
STATUSES = (
('Open','Open'),
('Closed','Closed')
)
gross_weight = models.FloatField(null=False,default=0,validators=[MinValueValidator(0)])
volume = models.FloatField(null=False,default=0,validators=[MinValueValidator(0)])
origin_country = models.CharField(
validators=[RegexValidator(regex='[A-Z]{2}', message='Country code is two letters')], max_length=2,null=True)
origin_port = models.CharField(
validators=[RegexValidator(regex='[A-Z]{3}', message='Port code is three letters')], max_length=3,null=True)
dest_country = models.CharField(
validators=[RegexValidator(regex='[A-Z]{2}', message='Country code is two letters')], max_length=2,null=True)
dest_port = models.CharField(
validators=[RegexValidator(regex='[A-Z]{3}', message='Port code is three letters')], max_length=3,null=True)
time_registered = models.DateField(default=timezone.now)
spot_status = models.CharField(max_length=6,default='Open', choices=STATUSES)
ship_week = models.CharField(max_length=2,null=True)
requestor = models.ForeignKey(Stakeholder,null = True,on_delete=models.CASCADE)
def __str__(self):
return self.origin_country + self.origin_port + '-' + self.dest_country +self.dest_port + '-' + self.ship_week
views.py
def register_spot(request):
my_user = Stakeholder.objects.get(user=request.user)
form = SpotForm()
if request.method =='POST':
print("print",request.POST)
form = SpotForm(request.POST)
if form.is_valid():
form.save()
return redirect('/')
else:
print(form.errors)
context = {'form': form}
return render(request, 'spotrequesting/register_spot.html', context)
When i submit the form i am getting an error in command prompt stating "This field is required" for "requestor". After that - dropdown list for this field come up on screen and i can select out of two registered users i have. But even selecting something from this list and again submitting the form is giving me the same error.
Checking "my_user" variable - it is showing me that i am logged in.
Is there a way to pass to "requestor" field currently logged in user?
I was able to get the form saved only by deleting "requestor" from "fields" in SpotForm (which gave me "None" in the end for this field in database) but that's not the desired outcome.
Any suggestion would be highly appreciated.
You are not really passing the stakeholder instance to the requestor field in the form are you? So you will have to do:
form = SpotForm(requestor = my_user)

How to change ForeignKey value using inlineformset?

I have two models and forms linked by the ForeignKey 'squad'. In my templates I have the user first typing the Squad name and then the shooters. I am trying to hardcode the 'squad' field of my Shooters with the 'squad_name' of my ShooterSquad so the user doesn't have to type the squad name every time for every shooter.
models.py
class ShooterSquad(models.Model):
squad_name = models.CharField(unique=True, max_length=100)
school = models.CharField(max_length=100, null=False)
def __str__(self):
return self.squad_name
class Shooter(models.Model):
name = models.CharField(max_length=100)
squad = models.ForeignKey(ShooterSquad, to_field='squad_name', related_name='squad', on_delete=models.PROTECT)
def __str__(self):
return self.name
forms.py
class ShooterSquadForm(forms.ModelForm):
class Meta:
model = ShooterSquad
fields = ['squad_name', 'squad_total_score', ]
class ShooterForm(forms.ModelForm):
class Meta:
model = Shooter
fields = '__all__'
class BaseShooterFormSet(BaseModelFormSet):
def __init__(self, *args, **kwargs):
super(BaseShooterFormSet, self).__init__(*args, **kwargs)
self.queryset = Shooter.objects.none()
ShooterFormSet = inlineformset_factory(
ShooterSquad, Shooter,
form=ShooterForm,
formset=BaseShooterFormSet,
extra=1,
max_num=3,
exclude=('squad',)
)
views.py
def add_multiple_shooters(request):
if request.method == 'POST':
squad_form = ShooterSquadForm(request.POST)
formset = ShooterFormSet(request.POST)
if squad_form.is_valid() and formset.is_valid():
set_squad = squad_form.cleaned_data.get('squad_name')
for f in formset.forms:
f.cleaned_data['squad_id'] = set_squad
f.cleaned_data['squad'] = set_squad
print(formset.cleaned_data)
squad_form.save()
formset.save()
return redirect('anasp:mainpage')
else:
print("ERROR")
formset = ShooterFormSet()
squad_form = ShooterSquadForm()
context = {
"title": title,
"formset": formset,
"squad_form": squad_form,
}
return render(request, "anasp/scores/shooter_formset.html", context)
Input Form Sample
My cleaned_data prints: [{'shooter_number': 67, 'squad': 'Woodland', 'name': 'Legolas', 'DELETE': False, 'id': None, 'shooter_score': 39, 'squad_id': 'Woodland'}]
So it seems that the squad_id has changed right? Wrong. When I look in my db my squad_id is <null>
How do I fix that?
Python: 3.5.4 Django: 1.8
I fixed it by not committing the save before all the changes were made:
if squad_form.is_valid():
squad = squad_form.save(commit=False)
if formset.is_valid():
shooters_to_save = list()
for f in formset.forms:
shooter = f.save(commit=False)
shooter.squad = squad
shooters_to_save.append(shooter)
squad.save()
for shooter in shooters_to_save:
shooter.save()
return redirect('anasp:mainpage')

form.is_valid() is false why?

I want to store a POST request to a database, so I a had model form MessageForm and called it from views to validate the data and save it.
models.py
class phoneNumber(models.Model):
address = models.CharField(max_length=15)
def __str__(self):
return self.address
class Message(models.Model):
to = models.ForeignKey(phoneNumber, null=True)
sentfrom = models.CharField(max_length=15, null=True)
content = models.TextField(null=True)
def __str__(self):
return '%s' % (self.content)
forms.py
class MessageForm(forms.ModelForm):
class Meta:
model = Message
fields = '__all__'
def __init__(self, *args, **kwargs):
to = kwargs.pop('to', '')
super(MessageForm, self).__init__(*args, **kwargs)
self.fields['to']=forms.ModelChoiceField(queryset=phoneNumber.objects.filter(address=to))
views.py
#csrf_exempt
def incoming(request):
if request.method == "POST":
form = MessageForm(request.POST)
if form.is_valid():
twiml = '<Response><Message>Yes</Message></Response>'
else:
twiml = '<Response><Message>No</Message></Response>'
else:
twiml = '<Response><Message></Message></Response>'
return HttpResponse(twiml, content_type='text/xml')
Nothing is saved and I get No response when I test it.
You can access your errors in views.py
#csrf_exempt
def incoming(request):
if request.method == "POST":
form = MessageForm(request.POST)
if form.is_valid():
twiml = '<Response><Message>Yes</Message></Response>'
else:
print(form.errors)
print(form.non_field_errors)
twiml = '<Response><Message>No</Message></Response>'
else:
twiml = '<Response><Message></Message></Response>'
return HttpResponse(twiml, content_type='text/xml')
Have you tried:
def __init__(self, *args, **kwargs):
to = kwargs.pop('to', '')
super(MessageForm, self).__init__(*args, **kwargs)
self.fields['to'].queryset = phoneNumber.objects.filter(address=to)
Also I'm not sure if you want to pass anything to the form in views method, because right now your to in form is empty string, so your queryset is querying on phoneNumber.objects.filter(address=''), which may or may not be what you want.
Edit:
The reason that to is empty string because kwargs.pop('to', '') means "pop argument to out from kwargs, if to is not there the default is ''". In your views you do:
form = MessageForm(request.POST)
but you didn't feed the constructor with any to argument, so kwargs.pop('to', '') would get '' as default value. You might need something like:
form = MessageForm(request.POST, to="white house")

Django form not inserting form values

I have a from created which is generated by a model. I can save the form, but the form data is not inserted into the table. The insert occurs, but with blank data. Any help would be greatly appreciated.
models.py
class HelpDefinition(models.Model):
org = models.IntegerField(default=0)
help_type = models.CharField(max_length=255)
help_content = models.TextField(blank=True)
def __unicode__(self):
return self.name
views.py
def index(request, org_id=None):
help_def = HelpDefinition()
if org_id:
help_def = HelpDefinition.objects.get(org=org_id)
if request.method == 'POST':
form = FormHelp(request.POST)
if form.is_valid():
help_def.save()
messages.success(request, 'Saved!')
else:
messages.error(request, 'Ugh')
else:
form = FormHelp(request=request, initial=initial_data)
return {
'form': form,
}
forms.py
class FormHelp(forms.Form):
org = forms.CharField(widget=forms.HiddenInput, required=True)
help_type = forms.ChoiceField(abel='Text', required=True)
help_content = forms.CharField(label='Description', required=True, widget=forms.Textarea)
def __init__(self, *args, **kwargs):
self.request = kwargs.pop('request', None)
super(FormHelp, self).__init__(*args, **kwargs)
Due that you dont use ModelForm, you need to set your attributes one by one.
if request.method == 'POST':
form = FormHelp(request.POST)
if form.is_valid():
help_def.org = form.cleaned_data.get("org")
help_def.help_type = form.cleaned_data.get("help_type")
help_def.help_type = form.cleaned_data.get("help_content")
help_def.save()

Categories