When filling out a form I get "This field is required." even though all fields are filled in.
It doesn't have to do with setting required to False or anything like that, because all fields are required.
views.py
def upload(request):
if request.method == 'POST':
form = UploadFileForm(request.POST, request.FILES)
if form.is_valid():
title = form.cleaned_data['title']
username = request.user.get_username()
category = form.cleaned_data['category']
handle_uploaded_file(request.FILES['file'],title,username,category)
return HttpResponseRedirect('')
else:
form = UploadFileForm()
return render(request, 'main/upload.html', {'form': form})
function
def handle_uploaded_file(f,title,username,category):
with open('/uploads/' + category + '/' + title, 'wb+') as destination:
for chunk in f.chunks():
destination.write(chunk)
forms.py
class UploadFileForm(forms.Form):
title = forms.CharField(max_length=50)
category = forms.CharField(max_length=50)
file = forms.FileField()
upload.html
{% extends 'base.html' %}
{% block title %}Upload{% endblock %}
{% block content %}
{% if user.is_authenticated %}
Uploading as: {{ user.username }}
<form method="post">
{% csrf_token %}
{{ form.as_p }}
<input type="submit" value="Submit"/>
</form>
{% else %}
<p>You are not logged in</p>
login
{% endif %}
{% endblock %}
The error I get when filling out a form is: "This field is required"
Screenshot:
When I select a file and it throws the error it unselects whatever file I've selected, similar to how the password field is cleared when hitting sign up without completing every field.
The file isn't being submitted with the request because you didn't sent the correct enctype on the form element. Here are Django's docs concerning that.
<form method="post" enctype="multipart/form-data">
One way to verify this/debug it would be to print the form's data form.data, request.POST and/or request.FILES before the call to is_valid. Or verifying the request in a browser's dev tools.
Related
I have following scenario.
User fills out a form
If the user clicks the "continue" button and the form is valid the user will be redirected to a summary view
In the summary view the user checks the input again. He can either continue or go back.
If he continues the data will be saved in the database, if he goes back he can edit the form.
Since in step 4 the user is at the view summary I have to redirect him to the home view. I don´t want the user to fill out the entire form again, the previously entered data should be autofilled if he goes back.
Something special: I am using django-tagify2 for one input in the form to get tags rather then text. If the user goes back the tags should be rendered correctly in the tagify specific form.
So here are my files:
home.html
{% extends "messenger/base.html" %}
{% load crispy_forms_tags %}
{% block content %}
<div class="message-container">
<form method="POST" autocomplete="off">
{% csrf_token %}
{{ form|crispy }}
<button name="sendmessage" class="btn btn-outline-info" type="submit">Continue</button>
</form>
</div>
{% endblock content %}
summary.html
{% extends "messenger/base.html" %}
{% block content %}
<h4>Zusammenfassung</h4>
<p><b>Empfänger: </b>{{ receiver }}</p>
<br>
<p><b>Betreff: </b>{{ subject }}</p>
<br>
<p><b>Nachricht: </b>{{ message }}</p>
<button>Edit</button>
<button>Continue</button>
{% endblock content %}
home view
#login_required(login_url='login')
def home(request):
if request.method == 'POST' and 'sendmessage' in request.POST:
message_form = MessageForm(request.POST)
if message_form.is_valid():
receiver_list = message_form['receiver'].value().split(';')
subject = message_form['subject'].value()
message = message_form['textmessage'].value()
#create sessions and send data to next view
session_receiver = receiver_list
request.session['session_receiver'] = session_receiver
session_subject = subject
request.session['session_subject'] = session_subject
session_message = message
request.session['session_message'] = session_message
return redirect('summary')
else:
message_form = MessageForm()
return render(request, 'messenger/home.html', {'form': message_form})
summary view
def summary(request):
receiver = request.session.get('session_receiver')
subject = request.session.get('session_subject')
message = request.session.get('session_message')
return render(request, 'messenger/summary.html', {'receiver':receiver,
'subject':subject,
'message':message})
So what is the best way to do this?
Can I use the session variables to set the fields in the form?
I don´t want to change the logic in the app. I want a home/summary/success view/template where I can loop as long is I want between home and summary until the user is happy with his entered form data
How about checking request.session when there is get request to home view? Then you can bind message_form = MessageForm() to session data.
You can check out htmx and django-htmx. You can do what you want easily without session by swapping HTML with context.
I played around with the session values and views and finally got a way to redirect to other views with prefilled form fields based on session values.
#login_required(login_url='login')
def home(request):
if request.method == 'POST' and 'sendmessage' in request.POST:
message_form = MessageForm(request.POST)
if message_form.is_valid():
ad_group = message_form['ad_group'].value().split(';')
ad_user = message_form['ad_user'].value().split(';')
subject = message_form['subject'].value()
message = message_form['textmessage'].value()
#create sessions and send data to next view
session_ad_group = ad_group
request.session['session_ad_group'] = session_ad_group
session_ad_user = ad_user
request.session['session_ad_user'] = session_ad_user
session_subject = subject
request.session['session_subject'] = session_subject
session_message = message
request.session['session_message'] = session_message
return redirect('summary')
else:
if request.session.get('session_subject'):
message_form = MessageForm(initial={'ad_group': request.session.get('session_ad_group'),
'ad_user': request.session.get('session_ad_user'),
'subject': request.session.get('session_subject'),
'textmessage': request.session.get('session_message')})
return render(request, 'messenger/home.html', {'form': message_form})
else:
message_form = MessageForm()
return render(request, 'messenger/home.html', {'form': message_form})
def summary(request):
ad_group = request.session.get('session_ad_group')
ad_user = request.session.get('session_ad_user')
subject = request.session.get('session_subject')
message = request.session.get('session_message')
if request.method == 'POST' and 'edit' in request.POST:
message_form = MessageForm(initial={'ad_group':ad_group, 'ad_user': ad_user,
'subject':subject, 'textmessage':message})
return render(request, 'messenger/home.html', {'form': message_form})
return render(request, 'messenger/summary.html', {'ad_group':ad_group,
'ad_user': ad_user,
'subject':subject,
'message':message})
Template
{% extends "messenger/base.html" %}
{% block content %}
<h2>Zusammenfassung</h2>
<div class="border-top pt-3">
<p><b>AD-Gruppe: </b>{{ ad_group }}</p>
<p><b>AD-User: </b>{{ ad_user }}</p>
<br>
<p><b>Betreff: </b>{{ subject }}</p>
<br>
<p><b>Nachricht: </b>{{ message }}</p>
<div class="buttoncontainer">
<form name="edit" action="" method="post">
{% csrf_token %}
<button class="btn edit_btn" formaction="{% url 'messenger-home' %}">Zurück</button>
</form>
<form name="senden" action="" method="post">
{% csrf_token %}
<button class="btn continue_btn" formaction="{% url 'send_messages' %}">Nachricht senden</button>
</form>
</div>
</div>
{% endblock content %}
I am tring to sent email with django using gmail smtp server i write settings in setting.py.here is my other code but I am getting AttributeError at /share/4 'str' object has no attribute 'get' ? please help me to solve that error.
**forms.py**
from django import forms
class EmailPostForm(forms.Form):
name = forms.CharField(max_length=100)
email = forms.EmailField()
to = forms.EmailField()
comment = forms.CharField(widget=forms.Textarea, required=False)
views.py
def share_email(request, id):
post = get_object_or_404(Post, id=id)
sent = False
if request.method == 'POST':
form = EmailPostForm(data=request.method)
if form.is_valid():
cd = form.cleaned_data
post_url =
request.build_absolute_uri(post.get_absolute_url())
subject = '{} ({}) recommend you reading "{}"'.format(cd['name'], cd['email'], post.title)
message = 'Read "{}" at {}\n\n{}\'s comments: {}'.format(post.title, post_url, cd['name'], cd['comment'])
send_mail(subject, message, 'admin#gmail.com', cd['to'])
sent = True
else:
form = EmailPostForm()
return render(request, 'blog/post/share_post.html', {'post': post, 'form': form, 'sent': sent})
url.py
urlpatterns = [path('share/<int:id>', views.share_email, name='share_post'),]
share_post.html
{% extends 'blog/base.html' %}
{% block title %}
Share Post
{% endblock %}
{% block content %}
{% if sent %}
<h2>E-mail successfully sent</h2>
<p>{{ post.title }} is successfully dent by email</p>
{% else %}
<h2>Share {{ post.title }} by email</h2>
<form action="{% url 'blog:share_post' post.id %}" method="post">
{{ form.as_p }}
{% csrf_token %}
<input type="submit" value="Send Email">
</form>
{% endif %}
{% endblock %}
Here:
form = EmailPostForm(data=request.method)
you want request.POST, not request.method.
As a side note: a successful post should be followed by a redirect (to prevent page reload to repost the same data). You can use the contrib.messages app to set a message in session, that will then be displayed on the next page.
I was trying to create a function for upload file in Django. First time I running my code, it's cannot upload a file. So, I was trying to improve my code and what I got its error. I thought the error it's weird because I always used that and I never get an error. I'll show my code.
models.py
class UploadFiles(models.Model):
File = models.ImageField(upload_to = 'Images/', default='Images/')
views.py
def upload_file(request):
if request.method == 'POST':
form = UploadFile(request.POST, request.FILES)
if form.is_valid():
form.save()
return redirect('home')
else:
form = UploadFile()
return render(request, 'girl/upload.html', {'form': form})
forms.py
class UploadFile(forms.Form):
title = forms.CharField(max_length=50)
file = forms.FileField
upload.html
{% extends 'girl/base.html' %}
{% block content %}
<form method="post" enctype="multipart/form-data">
{% csrf_token %}
{{ form.as_p }}
<button type="submit">Upload</button>
</form>
<p>Return to home</p>
{% endblock %}
error:
django.urls.exceptions.NoReverseMatch: Reverse for '/' not found. '/' is not a valid view function or pattern name.
urls.py
url(r'^cat/upload/$', views.upload_file, name='uploads')
Any help would be appreciated.
This is the line the error is
<p>Return to home</p>
Change it to
<p>Return to home</p>
And in your forms to
class UploadFile(forms.ModelForm)
class Meta:
model=UploadFiles
fields ='__all__'
I want to edit two forms in Django. A form for 'Motel' and its 'Images'. In my app, users can upload multiple images to the 'Motel' model. And now, editing the images with 'get()' function is giving me,
MultipleObjectsReturned get() returned more than one MotelImages -- it returned 4!
Models
class Motel(models.Model):
user= models.ForeignKey(User)
title= models.CharField(max_length=120)
body= models.TextField()
#other fields
class MotelImages(models.Model):
motel= models.ForeignKey(Motel, default=None, related_name='images')
image= models.ImageField(upload_to='company', verbose_name= 'Image')
class MotelImagesForm(forms.ModelForm):
image= forms.ImageField(label='Image',)
def __init__(self, *args, **kwargs):
super(MotelImagesForm,self).__init__(*args, **kwargs)
self.fields['image'].widget= forms.FileInput(attrs={'name':'image',
'multiple':'multiple'})
Views for saving the form
def create_motel(request):
if request.method=="POST":
motelForm= MotelForm(request.POST, request.FILES)
formset=MotelImagesForm(request.POST, request.FILES)
if motelForm.is_valid() and formset.is_valid():
human= True
motel_form= motelForm.save(commit=False)
motel_form.user= request.user
motel_form.pub_date= datetime.datetime.now()
motel_form.save()
for image in request.FILES.getlist('image',[]):
photo= MotelImages(motel=motel_form, image=image)
photo.save()
messages.success(request,
"Welldone Boy")
return HttpResponseRedirect('/view_all/')
else:
print motelForm.errors, formset.errors
else:
motelForm=MotelForm()
formset= MotelImagesForm()
return render(request, 'motels/add_motel.html',{'motelForm': motelForm, 'formset':formset})
Views for editing the form
#login_required
def edit_motel(request,motel_id=None,slug=None,template_name='motel_edit.html'):
if id:
post=get_object_or_404(Motel,id=motel_id,slug=slug)
images=MotelImages.objects.get(motel=motel_id)
else:
post=Motel(user=request.user)
images=MotelImages(user=request.user)
if request.POST:
motelform=MotelForm(request.POST,request.FILES, instance=post)
formset=MotelImagesForm(request.POST,request.FILES, instance=images)
if form.is_valid() and formset.is_valid():
form.save()
formset.save()
redirect_url=reverse('moteldetail',kwargs={'motel_id':motel_id,'slug':slug})
return render(request, 'motels/updatenotice.html')
else:
form=MotelForm(instance=post)
formset= MotelImagesForm(instance=images)
return render(request, template_name,{'formset':formset,'motelform':motelform})
Template for editing the form
<form id="post_form" method="post" action=""
enctype="multipart/form-data">
{% csrf_token %}
{% for hidden in motelform.hidden_fields %}
{{ hidden }}
{% endfor %}
{% for field in motelform %}
{{ field.name }}
{{ field }} <br />
{% endfor %}
{{ formset.management_form }}
{% for form in formset %}
{{ form }}
{% endfor %}
<input type="submit" name="submit" value="Submit" />
</form>
What am I missing?
images = MotelImages.objects.get(motel=motel_id)
Since get can return only one object, you want to use filter:
images = MotelImages.objects.filter(motel__pk=motel_id)
images will be a list of the relevant images.
I am trying to do a basic search feature but I am having a small issue. When I go to the template that has the search form, it is displaying all the items before I even try to search. Is there a way to show a blank template until the user has put in a search term and hit the search button?
Example:
[Search field][Button]
1
2
3
etc
views.py
def view_player_home(request):
if request.method == 'GET':
form = searchPlayerForm(request.GET)
if form.is_valid():
string = form.cleaned_data.get('text')
players = Player.objects.filter(Q(first_name__icontains = string)|Q(last_name__icontains = string))
return render_to_response('player/player.html', {'form': form, 'players':players}, context_instance=RequestContext(request))
else:
form = searchPlayerForm()
return render_to_response('player/player.html', {'form': form}, context_instance=RequestContext(request))
forms.py
class searchPlayerForm(forms.Form):
text = forms.CharField(label = "Search")
def __init__(self, *args, **kwargs):
super(searchPlayerForm, self).__init__(*args, **kwargs)
self.fields['text'].required = False
template
{% extends "base.html" %}
{% block content %}
<h5>Find Player</h5>
<form method="GET" action="">
{% csrf_token %}
{{ form.as_table }}
<input type="submit" value="Submit"/>
</form>
{% if players %}
{% for p in players %}
{{ p.first_name }} {{ p.last_name }}
{% endfor %}
{% else %}
No Players
{% endif %}
{% endblock %}
One change should do it:
if request.method == 'GET':
should be
if request.GET:
The underlying issue is that your request method is always GET, so you never go into the else block or to the bottom of the function.
Another option is to explicitly look for a term in the GET data
if request.GET and 'text' in request.GET:
# do query / processing
or even don't allow blanks
if request.GET and 'text' in request.GET and request.GET['text'] != '':
# do query / processing
This work easily if you only have one field or are checking if options in a form have certain values.
When doing a lot of fields, I like to do a named submit button so that I can check is it's been hit, and then do the if statements checking for the button name.