Why does my Django form keep saying "this field is required" - django

Does anyone know why my form (filepicker) is constantly returning "this field is required" when it worked in a simpler version?
My view is
def add_attempt(request, m_id, a_id):
template = loader.get_template('add_attempt.html')
if request.method == 'POST':
import pprint
pprint.pprint(request.POST)
pprint.pprint(request.FILES)
form = UploadAttemptForm(data=request.POST, files=request.FILES)
if form.is_valid():
form.instance.pub_date = datetime.datetime.now()
form.instance.user_id = request.user
form.instance.assignment = m.Assignment.objects.get(id=a_id)
form.save()
return HttpResponseRedirect(reverse('assignment', args=(m_id, a_id)))
else:
print form.errors
else:
form = UploadAttemptForm()
context = RequestContext(request,
{
'form':form,
})
return HttpResponse(template.render(context))
My Model is
class Attempt(models.Model):
user_id = models.ForeignKey(User)
pdf_filename = models.FileField(storage=settings.S3_STORAGE, upload_to='pdfs')
pub_date = models.DateTimeField('date uploaded')
assignment = models.ForeignKey(Assignment)
And my form is
class UploadAttemptForm(forms.ModelForm):
def __init__(self, *args, **kwargs):
super(UploadAttemptForm, self).__init__(*args, **kwargs)
class Meta():
model = Attempt
fields = ['pdf_filename',]
The error prints out as
`<QueryDict: {u'submit': [u'Upload Attempt'], u'pdf_filename': [u'something.pdf']}>`
<MultiValueDict: {}>
<ul class="errorlist"><li>pdf_filename<ul class="errorlist"><li>This field is required.</li></ul></li></ul>

Adding my comment as a proper answer:
Please try adding enctype= multipart/form-data to your <form> element in your template file.
If you don't have this element your request.FILES will always be empty.
Copying from https://docs.djangoproject.com/en/1.7/topics/http/file-uploads/#basic-file-uploads:
Note that request.FILES will only contain data if the request method was POST and the <form> that posted the request has the attribute enctype="multipart/form-data". Otherwise, request.FILES will be empty.

If the field is required in your models.py (i.e. you have not stated blank=True or null=True), and you are using a ModelForm, then that will be a required field in your ModelForm

Related

DJANGO: NOT NULL constraint failed: courses_comment.lesson_id

I try create comments form add and take error. But I'm not shure that I correctly use lesson = at view.py at def post function.
Can You help me?
models.py:
class Comment(models.Model):
text = models.TextField('Comment text')
user = models.ForeignKey(User, on_delete=models.CASCADE)
lesson = models.ForeignKey(Lesson, on_delete=models.CASCADE)
view.py:
class LessonDetailPage(DetailView):
....
def post(self, request, *args, **kwargs):
lesson = Lesson.objects.filter(slug=self.kwargs['lesson_slug']).first()
post = request.POST.copy()
post['user'] = request.user
post['lesson'] = lesson
request.POST = post
form = CommentForms(request.POST)
if form.is_valid():
form.save()
part of urls.py
path('course/<slug>/<lesson_slug>', views.LessonDetailPage.as_view(), name='lesson-detail'),
forms.py:
class CommentForms(forms.ModelForm):
text = forms.CharField(
label='Text',
required=True,
widget=forms.Textarea(attrs={'class': 'form-control'})
)
user = forms.CharField(
widget=forms.HiddenInput()
)
lesson = forms.CharField(
widget=forms.HiddenInput()
)
class Meta:
model = Comment
fields = ['text']
comment.html
<div class="form-section">
<form method="post">
{% csrf_token %}
{{ form }}
<button type="submit">ОК</button>
</div>
And my Error
IntegrityError at /course/linux/set-on-linux
NOT NULL constraint failed: courses_comment.lesson_id
Request Method: POST
Request URL: http://127.0.0.1:8000/course/linux/set-on-linux
Django Version: 4.0.6
Exception Type: IntegrityError
Exception Value:
NOT NULL constraint failed: courses_comment.lesson_id
My suspicion is that this is causing your issue:
lesson = Lesson.objects.filter(slug=self.kwargs['lesson_slug']).first()
What this is doing is returning the first Lesson object in a queryset filtered by your lesson slug. However, filter will return an empty queryset if there are no results. Running first() on that empty queryset will return nothing, which would explain why an ID is not being passed to your form.
To solve this, you just need to catch whether the lesson object is empty:
if lesson is None:
# do something else
As an aside, combining .filter() and .first() is generally not recommended as you are potentially being vague with your object selection. Using .get() will get you a single object and return an error if two or more are returned. The downside with .get() is that it will also raise an exception if nothing is returned, so you need to handle both outcomes in your view.
But better at forms.py write:
class CommentForms(forms.ModelForm):
class Meta:
model = Comment
fields = ['text', 'user', 'lesson'] #here is the answer
widgets = {'user': forms.HiddenInput(), 'lesson': forms.HiddenInput()}
then at views.py:
def post(self, request, *args, **kwargs):
course = Course.objects.filter(slug=self.kwargs['slug']).first()
lesson = Lesson.objects.filter(slug=self.kwargs['lesson_slug']).first()
post = request.POST.copy()
post['user'] = request.user
post['lesson'] = lesson
request.POST = post
form = CommentForms(request.POST)
if form.is_valid():
form.save()
May be not best solution but It's work:
def post(self, request, *args, **kwargs):
lesson = Lesson.objects.filter(slug=self.kwargs['lesson_slug']).first()
post = request.POST.copy()
post['user'] = request.user
post['lesson'] = lesson
request.POST = post
form = CommentForms(request.POST)
if form.is_valid():
comment = Comment(text=request.POST['text'], user=request.POST['user'], lesson=request.POST['lesson'])
comment.save()

Django ModelForm saves and fetches <QuerySet object> instead of values

I have a simple Django 3.1.0 app I need to create in order to assign Tasks with Tags (or assign tags into tasks).
Model
class Task(models.Model):
user = models.CharField(max_length=33)
time = models.DateTimeField(auto_now_add=True)
task = models.CharField(max_length=500)
tags = models.CharField(max_length=100, default="None", null=True)
class Tag(models.Model):
tag = models.CharField(max_length=30, default="No Tag")
members = models.ManyToManyField('Task', related_name="tag")
class Meta:
verbose_name = "tag"
verbose_name_plural = "tags"
view
def main(request):
model = Task.objects.values().all()
tags = Tag.objects.values().all()
form = TaskForm()
con = {'context': list(model), 'form': form, 'tags': list(tags)}
if request.method == 'POST':
form = TaskForm(request.POST)
if form.is_valid():
form.save()
return redirect('/')
else:
form = TaskForm()
return render(request, "tasks.html", con)
form
class TaskForm(ModelForm):
class Meta:
model = Task
fields = ['user', 'task', 'tags']
template_name = 'tasks.html'
tags = ModelMultipleChoiceField(
queryset= Tag.objects.all(),
widget=CheckboxSelectMultiple(), required=False,
)
task_form
<form method="post" class="form">
{% csrf_token %}
{{form}}
<input type="submit" value="Save">
</form>
This returns in the tags list the items listed as:
Tag object (1)
Tag object (2)
And when it saves when i press submit, it fetches in a table (in another template), the values saved in the text of <QuerySet [<Tag: Tag object (2)>]>
That's how it stores them in the database.
I have managed to extract the values as they are ('jenkins','AKS') and send them in the template using this (bootstrapvuejs) : {% for tag in tags %}<b-form-checkbox>{{tag.tag}}</b-form-checkbox>{% endfor %}, which lists them raw values perfectly.
However, when I do that modification, the form submitted is not written to database.
What am I missing?
UPDATE!
I have partly solved it by adding this into the Tag model:
def __str__(self):
return self.tag
but when it persists it on submit, it still saves it as:
<QuerySet [<Tag: jenkins>]>
So, how and where do I strip only the specific tag values to be inserted in the database?
Many Thanks
Alright so there is a couple issues with your code, first off your main view:
Change it from this:
def main(request):
model = Task.objects.values().all() # calling values without specifying an argument makes no sense so just call it like **Task.objects.all()**
tags = Tag.objects.values().all() # same here
form = TaskForm() # don't call your form here it gets reassigned later anyways
con = {'context': list(model), 'form': form, 'tags': list(tags)} # don't define your context here since you are reasigning your form later so the form instance is always TaskForm()
if request.method == 'POST':
form = TaskForm(request.POST)
if form.is_valid():
form.save()
return redirect('/')
else:
form = TaskForm()
return render(request, "tasks.html", con)
To this:
def main(request):
model = Task.objects.all()
tags = Tag.objects.all()
if request.method == 'POST':
form = TaskForm(request.POST)
if form.is_valid():
form.save()
return redirect('/')
else:
form = TaskForm()
context = {'tasks': model,
'form': form,
'tags': tags}
return render(request, "tasks.html", con)
Then in your template pass your form with as_p method call:
{{ form.as_p }}
Hovewer the error you are getting is not because of your html or your view, it's because your tags field in your Task model is not a ManyToMany relationship to your Tag model but rather a simple CharacterField and you are trying to save objects to the CharField, so rewrite your Task model like this:
class Task(models.Model):
user = models.CharField(max_length=33)
time = models.DateTimeField(auto_now_add=True)
task = models.CharField(max_length=500)
tags = models.ManyToMany(Tags)
Then your form should save them in the tags field of your Task instance and you can view them like this:
task = Task.objects.get(pk=1)
task_tags = task.tags.all() # stores a queryset of all tags of the queried task
and in the template:
{% for tag in task.tags.all %}
...
{% endfor %}
OK , I solved the POST data that is saved in database as Queryset, by extracting in the view where save() is called, the field 'tags' likewise:
f = form.save(commit=False)
f.tags = request.POST['tags']
form.save()
The only problem now is that I have multiple checkboxes in the form but this way it extracts only one of them, whilst I would expect it to return a list like what is printed in the request.POST : <QueryDict: {'csrfmiddlewaretoken': ['XV7HgTFiWXEnrkhqT3IsqUN2JbnT7YIH5r6fKgh2ehqeLsLMpvCPdUU4N2qwWuPk'], 'user': ['afa'], 'task': ['aff'], 'tags': ['jenkins', 'AKS']}> -> from that I call 'tags' but it saves only 'jenkins' ...
UPDATE
OK, I RTFM and saw that there is a method on the QueryDict object that can be passed to request.POST.getlist('tags') , so now it returns the complete value of 'tags' key.

How to check if `MultiSelectField` is empty or not in Django?

In my model I have a field department which is a MultiSelectField and I give the blank=True to that field for some reasons. Now I want to check if user fills the field or not. I have tried to get data from request.POST and gave it a condition using len() function like this if len(field) == 0: but I got an error. Everything works just fine until I added teacher_year = request.POST['teacher_year']
models.py
class CustomUser(AbstractUser):
teacher_department = MultiSelectField(choices=department_choice, blank=True)
forms.py
class TeacherRegisterForm(UserCreationForm):
class Meta(UserCreationForm):
model = CustomUser
fields = ['teacher_year', ...]
views.py
def teacherRegisterView(request):
form = TeacherRegisterForm()
template_name = "attendance/login-register/teacher_register.html"
if request.method == "POST":
form = TeacherRegisterForm(request.POST)
teacher_year = request.POST['teacher_year']
if len(teacher_year) == 0:
messages.warning(request, "Just a remind! You didn't select deparment!")
return redirect('teacher_register')
elif form.is_valid():
form.save()
messages.success(request, "Your account was created! You can log in now.")
return redirect('/')
return render(request, template_name, {'form': form})
the error I got
django.utils.datastructures.MultiValueDictKeyError: 'teacher_year'
MultiValueDict is inherited from normal dict. So you can use get() method with it:
teacher_year = request.POST.get('teacher_year') # if request.POST doesn't contain teacher_year it returns None
if teacher_year:
...

Django: Save id on a OneToOneField

models:
class UserDataUpdate(models.Model):
code = models.CharField(max_length=8)
address = models.CharField(max_length=50)
class UserSurvey(models.Model):
about_treatment = models.CharField(max_length=2)
user_data_update = OneToOneField(UserDataUpdate)
views:
#login_required
def generate_survey(request):
user_data_update = UserDataUpdate.objects.get(code=request.user.username)
if request.method == 'POST':
form = SurveyForm(request.POST)
if form.is_valid():
form.save()
return redirect('/success')
else:
form = SurveyForm(request.GET)
return render_to_response(
'survey.html',
{'form': form },
context_instance = RequestContext(request))
form:
class SurveyForm(forms.ModelForm):
def __init__(self, *args, **kwargs):
super(SurveyForm, self).__init__(*args, **kwargs)
for field in self.fields.values():
field.widget = RadioSelect(choices=SURVEY_CHOICES)
class Meta:
model = Survey
exclude = ['user_data_update']
I just need a way to set the UserDataUpdate id (that already has been created) on a UserSurvey.
I'm getting this message on generate_survey request.POST:
user_data_update_app_usersurvey.user_data_update_id may not be NULL
It should be clear to you that you get the user_data_update value but then don't do anything with it. I guess you want to set it on the object that's created by the form:
if form.is_valid():
instance = form.save(commit=False)
instance.user_data_update = user_data_update
instance.save()
(I don't understand what all that stuff in the form's __init__ method is supposed to do. You only have one field in your form, anyway.)

Django ModelForms: Trying to save a form with a foreign key

Django will just go to the else condition.
here's the code:
models.py
class StakeholderProfile(models.Model):
types = models.ForeignKey(Stakeholder)
name = models.CharField(blank=False, max_length=50)
forms.py
class SPForm(forms.ModelForm):
class Meta:
model = StakeholderProfile
exclude = ('key_contact_person',)
views.py
def profile(request):
stakeholderprofile = StakeholderProfile.objects.all()
if request.method == 'POST':
form = SPForm(request.POST)
if form.is_valid():
form.save()
return HttpResponseRedirect('/profile/')
else:
form = SPForm()
return render_to_response('profile.html',{'form':form,'sp':stakeholderprofile})
I really need your help sir/maam.
You are excluding a field that doesn't exist in StakeHolderProfile.
Also be sure you added method='POST' in your form tag.