I must just be overlooking something here, but after stripping everything back - I can't seem to get Django to render either a Form or ModelForm to my template. Code below:
#forms.py
class ContactForm(forms.Form):
subject = forms.CharField(max_length=100)
message = forms.CharField()
sender = forms.EmailField()
cc_myself = forms.BooleanField(required=False)
#views.py
def index(request):
if request.method == 'POST':
form = ContactForm(request.POST)
if form.is_valid(): # All validation rules pass
return HttpResponseRedirect('/thanks/')
else:
form = ContactForm() # An unbound form
return render_to_response('home/new_website.html',{
'form': form,
})
#new_website_html
<html>
<body>
<form method = "post" action = "">
{{ form.as_p }}
</form>
</body>
</html>
I had the same issue and after many tries this is my solution:
Change the view from this
#views.py
else:
form = ContactForm() # An unbound form
return render_to_response('home/new_website.html',{
'form': form,
})
To that:
#views.py
else:
form = ContactForm() # An unbound form
return render_to_response('home/new_website.html',{
'form': form,
})
Or a simple newline is enough:
#views.py
else:
form = ContactForm() # An unbound form
return render_to_response('home/new_website.html',{
'form': form,
})
Strange thing is, after these changes the original code worked.
Any error page or just blank page? Actually I just try your code and get form rendering correct(I don't know how to insert local result image here)
Please make sure DEBUG=TRUE in settings.py while it's not the problem.
#Burhan I think indent problem only happens because he edits it in stackoverflow.
Btw, your form doesn't have a submit button, maybe add it in html like
Related
I am rendering a dropdown which displays a list of integers. This is the only field in the form/view. Once that form is submitted, the integer selected should be passed to the URL of the next view which is rendered on submission of the previous form.
I am getting a 404 when I attempt this.
Here is what I am currently trying:
forms.py
#this is the dropdown field
class ManifestDropDown(forms.Form):
reference = forms.ModelChoiceField(queryset=Orders.objects.values_list('reference', flat=True).distinct(),
empty_label=None)
views.py
#this is the view where the dropdown is submitted
def manifest_references(request):
if request.method == 'POST':
form = ManifestDropDown(request.POST)
if form.is_valid():
reference_id = form.cleaned_data.get('reference')
form.save()
return render('manifest', reference_id=reference_id)
query_results = Orders.objects.all()
reference_list = ManifestDropDown()
context = {
'query_results': query_results,
'reference_list': reference_list,
}
return render(request, 'manifest_references.html', context)
#this is the view where the value should be displayed in the url
def manifest(request, reference_id):
form = CreateManifestForm(request.POST)
if request.method == "POST":
....
data = Manifests.objects.all().filter(reference__reference=reference_id)
form = CreateManifestForm(initial={
'reference': Orders.objects.get(reference=reference_id),
})
total_cases = Manifests.objects.filter(reference__reference=reference_id).aggregate(Sum('cases'))
context = {
'reference_id': reference_id,
'form': form,
'data': data,
'total_cases': total_cases['cases__sum'],
}
return render(request, 'manifest_readonly.html', context)
urls.py
#url which displays the manifest view above
url(r'^manifest/(?P<reference_id>\d+)/$', manifest, name='manifest'),
url(r'^references_manifests', manifest_references, name='references_manifests'),
manifest_references.html
<div class="container">
<br>
<br>
<br>
<form method="POST" action="references_manifests">
{% csrf_token %}
{{ reference_list }}
<button type="submit" class="btn btn-primary" name="button">Create Proforma</button>
</form>
</div>
To dynamically change the URL that you're actually submitting to, you would need to use JavaScript.
But an alternative is to submit back to the manifest_references view, then redirect from there to manifest. (Note, you should always be redirecting, not rendering, after a successful submission anyway. And no need to call form.save(), this isn't a modelform so there is nothing to save.)
def manifest_references(request):
if request.method == 'POST':
form = ManifestDropDown(request.POST)
if form.is_valid():
reference_id = form.cleaned_data.get('reference')
return redirect('manifest', reference_id=reference_id)
You can do two things:
Call the manifest view directly.
Redirect the user to the manifest page.
The first one should be done like this:
if form.is_valid():
reference_id = form.cleaned_data.get('reference')
form.save()
return manifest(request, reference_id)
The second one can be done like this:
if form.is_valid():
reference_id = form.cleaned_data.get('reference')
form.save()
return HttpResponseRedirect(reverse('manifest', reference_id = reference_id))
It doesn't really matter which one you do, although I would recomment redirecting the user to the correct page, because then a refresh will not resend the form the user has entered.
Python noob here trying to learn something very simple.
I'm trying to create a basic form that takes some personal information from a user and saves it into a sqlite3 table with the username of the user as the primary key.
My models.py looks like this:
class userinfo(models.Model):
user = models.OneToOneField(settings.AUTH_USER_MODEL, primary_key= True,
on_delete=models.CASCADE)
name = models.CharField(max_length = 200, blank = True)
email = models.EmailField(max_length= 300, default = 'Null')
phone = models.CharField(max_length= 10, default = 'Null')
def __unicode__(self):
return self.user
forms.py:
class NewList(forms.ModelForm):
class Meta:
model = userinfo
exclude = {'user'}
views.py
def newlist(request):
if request.method == 'POST':
form = NewList(request.POST)
if form.is_valid():
Event = form.save(commit = False)
Event.save()
return redirect('/home')
else:
form = NewList()
return render(request, 'home/newlist.html', {'form': form})
html:
{% load static %}
<form action="/home/" method="post">
{% csrf_token %}
{{ form.as_p }}
<input type="submit">
</form>
urls.py too, but I don't know how that would help:
urlpatterns = [
url(r'^newlist/$', views.newlist, name='newlist')
]
So when I go to the url, I see the form. I can then fill the form, but when I submit the form, the data doesn't go into the database.
What am I doing wrong here?
Thanks in advance!
I think all you need to do is just save the form if it's valid, probably also add the userinfo as an instance of the form. You are also exluding the user from the form and need to assign it manually.
def newlist(request):
if request.user.is_authenticated():
user = request.user
if request.method == 'POST':
form = NewList(request.POST, instance=user.userinfo)
if form.is_valid():
form.save(commit=false)
form.user = user
form.save()
return redirect('/home')
else:
form = NewList(instance=user.userinfo) # add this if you want it to automatically fill the form with the old data if there is any.
return render(request, 'home/newlist.html', {'form': form})
The rest look like it should work.Except you need to send the post URL back to newlist:
{% load static %}
<form action="/newlist/" method="POST">
{% csrf_token %}
{{ form.as_p }}
</form>
If users are assigned at the creation of the model the first time, you don't need the user save, but since this is saving a users data you want to make sure they are logged in anyway:
def newlist(request):
if request.user.is_authenticated():
user = request.user
if request.method == 'POST':
form = NewList(request.POST, instance=user.userinfo)
if form.is_valid():
form.save()
return redirect('/home')
else:
form = NewList(instance=user.userinfo) # add this if you want it to automatically fill the form with the old data if there is any.
return render(request, 'home/newlist.html', {'form': form})
The instance is the model it is either going to save to, or copying data from. In the: form = NewList(request.POST, instance=user.userinfo) part, it is taking the POST data from the form, and linking that to the specific model entry of user.userinfo, however, it will only save to the database when you call form.save().
The user.userinfo is just so you can get the correct form to save to, as userinfo is a onetoone model to user. Thus making it possible to get it with user.userinfo.
The form = NewList(instance=user.userinfo) part is where it takes the currently logged in user's userinfo and copies into the form before it is rendered, so the old userinfo data will be prefilled into the form in the html. That being if it got the correct userinfo model.
The Problem:
I'm tying to post to a view and pass on a value from the template by using a hidden value field and a submit button. The values from the submit button (ie the csrf_token) gets through but the hidden value does not. I've checked from the Wezkrug debugger that request.POST only contains form values and not my 'id' value from the hidden field.
Background:
The button takes you to a form where you can enter a comment. I'm trying to include the review.id that the user is commenting on to make commenting easy. I have the value as 'test' not for test purposes.
My form:
<div>
<form method='POST' action='/add_comment/'>
{% csrf_token %}
<input type="hidden" name='id' value='test'>
<input type="submit" value="Make a Comment">
</form>
</div>
Comment View:
#login_required
def make_comment(request):
if request.method == 'POST':
form = CommentForm(request.POST)
if form.is_valid():
comment = form.save(commit=False)
comment.user = request.user
comment.save()
# render?
return HttpResponseRedirect('/results/', {
'restaurant': get_object_or_404(
Restaurant,
name=request.POST['name'],
address=request.POST['address']
)
})
else:
form = CommentForm()
return render(request, 'stamped/comment.html', {'form': form})
Comment Model:
class Comment(models.Model):
content = models.TextField()
review = models.ForeignKey(Review)
user = models.ForeignKey(User)
date_added = models.DateTimeField(auto_now_add=True)
Comment ModelForm Code:
class CommentForm(ModelForm):
class Meta:
model = Comment
exclude = ('user', 'review',)
I've been trying to follow the tactics in this question, but using the request.session dict is undesirable because Id have to store an id for every review regardless if they're are ever commented on.
What is a more efficient way to pass variables from Template to View in Django?
Any ideas on how to include the hidden value in the POST? Thanks!
views.py
def make_comment(request):
if request.method == 'POST':
if 'prepair_comment' in request.POST:
review = get_object_or_404(Review, pk=request.POST.get('id'))
form = CommentForm({'review': review.id})
return render(request, 'stamped/comment.html', {
'form': form,
})
else: # save the comment
models.py
class CommentForm(ModelForm):
class Meta:
model = Comment
exclude = ('user',)
widgets = {'review': forms.HiddenInput()}
restaurant.html
<form method='POST' action='/add_comment/'>
{% csrf_token %}
<input type='hidden' value='{{ r.id }}' name='id'>
<input type="submit" name='prepair_comment' value="Make a Comment">
</form>
You can access the form with form.cleaned_data. You could also use a if form.is_valid() or if you want to ignore the hidden test value when there is no comment, then you could use a if/else logic to ignore the hidden value if comment is None: logic.
To access the form and only record the test value if comment is not None, the views.py might look like this:
def form_view(request):
if request.method == 'POST'
form = form(request.POST)
if form.is_valid():
comment = form.cleaned_data['comment']
# do something with other fields
if comment is not None:
id = form.cleaned_data['test']
# do something with the hidden 'id' test value from the form
return HttpResponseRedirect('/thanks/')
else:
form = form()
return render(request, 'form.html', {'form': form})
Here are the Django Docs that I would reference for this:
https://docs.djangoproject.com/en/dev/topics/forms/
at the moment, I try to make a search form for a small database.
This is a part of my models.py file:
from django.db import models
from django import forms
#...
class searchForm(forms.Form):
searchField = forms.CharField(max_length = 100)
#...
This is a part of my views.py file:
from django.shortcuts import render
from django.http import HttpResponse
from django.http import HttpResponseRedirect
#...
def index(request):
template = loader.get_template('index.html')
context = Context({})
return HttpResponse(template.render(context))
def search(request):
if request.method == 'POST': # If the form has been submitted...
form = searchForm(request.POST)# A form bound to the POST data
if form.is_valid():
searchData = form.cleaned_data['searchField']
return HttpResponseRedirect('search.html') # Redirect after POST #???
else:
searchData = searchForm() # an unbound form
return render(request, 'search.html', {'form': form,}) #???
#...
This is a part of my index.html, where I want to implement that form:
<label for="Search">Search:</label>
<form action = "/search/" method = "post">
{% csrf_token %} {{ form.as_p }}
<input type = "submit" value = "Go" />
</form>
What I'm trying to do:
When I submit the form I would like to redirect to the result file called search.html, where for the beginning, is the input from the search textfield showing up. The link struktur should be something like that:
Landing-Page is: http://127.0.0.1:8000/
after a submitted form: http://127.0.0.1:8000/search.html
I think there might be an error in the search method, where I marked the lines with the '???'. The next problem is, that my search textfield isn't showing up.
Would be great, if someone could give me some advice.
thanks,
eljobso
First: The form isn't showing up because as you say, you want it to appear in index.html but the index view isn't passing any form to the template. Is in search view where you pass the form the template.
If you want the behavior described you should reorganize the code like this:
from django.shortcuts import render
from django.shortcuts import render_to_response
from django.http import HttpResponse
from django.http import HttpResponseRedirect
from django.template.context import RequestContext
#...
def index(request):
# this will only render the template with the form
searchData = searchForm() # an unbound form
return render_to_response(
'index.html',
context_instance=RequestContext(
request,{'form':searchData,}
)
)
def search(request):
if request.method == 'POST': # If the form has been submitted...
form = searchForm(request.POST)# A form bound to the POST data
if form.is_valid():
searchData = form.cleaned_data['searchField']
# do whatever you want to process the search with
# searchada, maybe populate some variable
return render_to_response(
'search.html',
context_instance=RequestContext(
request,{'form':searchData,} # maybe add here the populated variable with the search
)
)
else:
# request.GET, just show the unbound form
searchData = searchForm() # an unbound form
return render_to_response(
'search.html',
context_instance=RequestContext(
request,{'form':searchData,}
)
)
Then your templates should be:
index.html
<!-- is not good to have a label outside form -->
<label for="Search">Search:</label>
<form action = "/search/" method = "post">
{% csrf_token %} {{ form.as_p }}
<input type = "submit" value = "Go" />
</form>
And also that text included inside search.html template because there you render the form as well.
I hope this may bring some light!
With django FormView you can do that:
class Index(FormView):
form_class = SearchForm
template_name = 'index.html'
success_template = 'search.html' # I've added this attr
def form_valid(self, form): #That return a your form, validated
# Here you can do something with you VALID form.
searchData = form.cleaned_data['searchField']
context = dict(
searchData=searchData,
)
return render_to_response(self.success_template, {}, RequestContext(self.request, context))
I have several forms in my application, and like all forms after the users have completed them, I would like to redirect them to a form completion page, which the particulars of the forms are displayed after the submission.
Now, assuming that my forms all have different attributes, how can I create a common view and display template such that I do not have to re-create the them since they are all similar other than the particulars of the forms to be displayed?
According to this Django: How do I redirect a post and pass on the post data you can't redirect with the post data, so you have to either 1) display the success page at the same url as the form or 2) put all the variables into the redirect URL.
If you are ok displaying the success at the same URL as the form, i.e. /my-form/ not /my-form/success/, then you could mutate the canonical form processing view as such:
def contact(request):
if request.method == 'POST':
form = ContactForm(request.POST)
if form.is_valid():
# ...
return render_to_response('form_success.html', {'form' : form,} )
else:
form = ContactForm()
return render_to_response('contact.html', {'form': form,})
Then in the template you could do:
<h3>Success! You submitted:</h3>
{% for field in form %}
{{field.label}}: {{field.data}}
{% endfor %}