I have a form with a POST Submit button. I want to link to a new page when the form is submitted and when the form.is_valid().
Is it better to make the link in the view or in the template? How to do it?
view.py:
from django.shortcuts import render_to_response
from ezmapping.models import *
from django.forms.models import modelformset_factory
def setName(request):
ezAppFormSet = modelformset_factory(ezApp, extra=1, fields=('name'))
formset = ezAppFormSet(queryset=ezApp.objects.none())
if request.method == 'POST':
formset = ezAppFormSet(request.POST, request.FILES)
if formset.is_valid():
formset.save()
return render_to_response("project/manage_new.html", {'formset': formset, 'title': "New"}, context_instance=RequestContext(request))
template.html
{% extends "basemap.html" %}
{% block content %}
<table border="1">
<tr>
<td>
<h1>Define new App options</h1>
{% if formset.errors %}
<p style="color: red;">
Please correct the error{{ formset.errors|pluralize }} below.
</p>
{% endif %}
<form method="post" action="." encrypt="multipart/form-data">{% csrf_token %}
{{ formset.as_p }}
<input type="submit" value="Submit">
</form>
</td>
</tr>
</table>
{% endblock %}
You can use HttpResponseRedirect() in the view like this:
from django.shortcuts import render_to_response
from ezmapping.models import *
from django.forms.models import modelformset_factory
def setName(request):
ezAppFormSet = modelformset_factory(ezApp, extra=1, fields=('name'))
formset = ezAppFormSet(queryset=ezApp.objects.none())
if request.method == 'POST':
formset = ezAppFormSet(request.POST, request.FILES)
if formset.is_valid():
formset.save()
next_link = u"/next/"
return HttpResponseRedirect(next_link)
return render_to_response("project/manage_new.html", {'formset': formset, 'title': "New"}, context_instance=RequestContext(request))
Sure. Just return a render_to_response inside of your conditional for request.method == 'POST', or optionally, just set up the context and template as variables to hand into render_to_response as such:
Paraphrased:
def foo(request):
template = 'template1.html'
# form and formsets here set into `context` as a dictionary
if request.method == 'POST':
template = 'template2.html'
return render_to_response(template, context)
[EDIT]
When I re-read your question, if you want to redirect to a different view if your form is valid, then return an HttpResponseRedirect instead.
If I understand your question correctly.
Your view:
from django.shortcuts import render_to_response
from ezmapping.models import *
from django.forms.models import modelformset_factory
def setName(request):
ezAppFormSet = modelformset_factory(ezApp, extra=1, fields=('name'))
formset = ezAppFormSet(queryset=ezApp.objects.none())
if request.method == 'POST':
formset = ezAppFormSet(request.POST, request.FILES)
if formset.is_valid():
formset.save()
submit_link = True # 2*
else:
submit_link = False
return render_to_response("project/manage_new.html", {'submit_link': submit_link, 'formset': formset, 'title': "New"}, context_instance=RequestContext(request))
Your template:
{% extends "basemap.html" %}
{% block content %}
<table border="1">
<tr>
<td>
<h1>Define new App options</h1>
{% if formset.errors %}
<p style="color: red;">
Please correct the error{{ formset.errors|pluralize }} below.
</p>
{% endif %}
<form method="post" action="." encrypt="multipart/form-data">{% csrf_token %}
{{ formset.as_p }}
<input type="submit" value="Submit">
</form>
{% if submit_link %}
<a href='/next/'>Data is saved, let's continue.</a>
{% endif %}
</td>
</tr>
</table>
{% endblock %}
Update.
And yes, if you want to redirect (not to show the next link) just place:
from django.shortcuts import redirect
...
return redirect( 'you-url' )
Instead of 2*.
Related
The post requests from the frontend do not get saved in the database, without any error shown. However, when I manually add entries from the admin panel, it shows on the frontend.
My index.html(form part):
<form class="main__input--form" method="POST">
{% csrf_token %}
<p class="main__input--text">
<textarea name="content" id="content" class="main__input--content" cols="35" rows="8" aria-label="Entry content" placeholder="Enter text here..."></textarea>
</p>
<button class="main__input--submit" type="submit">Vent</button>
</form>
My extension of index which loops through the database entries:
{% for obj in all_vents %}
<div>
<h1>{{obj.vent}}</h1>
</div>
<br />
{% endfor %}
My models.py:
class Vents(models.Model):
vent = models.CharField(max_length=10000)
def __str__(self):
return self.vent
My forms.py:
from django import forms
from .models import Vents
class VentForm(forms.ModelForm):
class Meta:
model = Vents
fields = ['vent']
My views.py:
from django.shortcuts import render, redirect
from .forms import VentForm
from .models import Vents
def ventout(request):
if request.method == "POST":
form = VentForm(request.POST or None)
if form.is_valid():
form.save()
return redirect("ventout")
else:
all_vents = Vents.objects.all()
return render(request, "ventout.html", {"all_vents": all_vents})
Views:
def ventout(request):
all_vents = Vents.objects.all()
if request.method == "POST":
form = VentForm(request.POST or None)
if form.is_valid():
form.save()
return redirect("ventout")
else:
form = VentForm()
context = {"all_vents": all_vents, "form":form}
return render(request, "ventout.html", context)
Template:
<form class="main__input--form" method="POST">
{% csrf_token %}
{{ form.as_p }}
<button type="submit" class="main__input--submit">Vent</button>
</form>
you could install/use "crispy_forms_tags" to make the form look better,
https://django-crispy-forms.readthedocs.io/en/latest/index.html
if you want to go further you could install/use "widget_tweaks"
https://pypi.org/project/django-widget-tweaks/
Your index.html from part should have {{ form }} form tag, as I guess.
Try Using following code
<form class="main__input--form" method="POST">
{% csrf_token %}
{{ form }}
<p class="main__input--text">
<textarea name="content" id="content" class="main__input--content"
cols="35" rows="8" aria-label="Entry content" placeholder="Enter text here...">
</textarea>
</p>
<button class="main__input--submit" type="submit" value="Submit">Vent</button>
</form>
I'm trying to render this form set:
ProductFormSet = modelformset_factory(
model=Product,
fields='__all__',
extra=5,
)
class ProductFormSetHelper(FormHelper):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.form_tag = False
self.layout = Layout(
Row(
'productCategory',
'name',
'measurement_unit',
)
)
self.render_required_fields = True
with this view:
def product_create(request):
helper = ProductFormSetHelper()
context = {
'helper': helper,
'title': 'Nuovi Prodotti',
}
if request.method == 'GET':
formset = ProductFormSet(queryset=Product.objects.none())
context['formset'] = formset
elif request.method == 'POST':
formset = ProductFormSet(request.POST)
context['formset'] = formset
if formset.is_valid():
formset.save()
messages.success(request, 'Prodotti aggiunti correttamente', fail_silently=True)
return HttpResponseRedirect(reverse('warehouse:products_list'))
else:
return render(request, 'warehouse/product_create.html', context)
return render(request, 'warehouse/product_create.html', context)
and this template:
{% extends "masterpage.html" %}
{% load static %}
{% block headTitle %}
<title>Nuovo Prodotto</title>
{% endblock %}
{% block contentHead %}
{% endblock %}
{% block contentBody %}
{% load document_tags %}
{% load custom_tags %}
{% load crispy_forms_tags %}
<FORM method="POST" autocomplete="off">
<div class="alert alert-info">
{{ title }}
</div>
{{ formset.management_form }}
{% crispy formset helper %}
<input type="submit" class="btn btn-primary margin-left" value="SALVA">
</FORM>
{% endblock %}
Problem is that when I submit the form I get the: ValidationError: management form data are missing! First of all, using crispy forms the management data should be included, second even if I explicitly call with the tag, I still get the ValidationError.
in Every forum I searched online, everyone was missing the management form tag, so I have no clue on what could be wrong....
Any idea?
thank you very much
C
in your Post method you didnt include the "queryset"
formset = ProductFormSet(queryset=Product.objects.WHATEVER_YOU_CHOOSE, request.POST)
and for crispy forms
{% load crispy_forms_tags %}
<form method="post">
{% csrf_token %}
{{ formset|crispy }}
{{ formset.management_form }}
<input type="submit" class="btn btn-primary margin-left" value="SALVA">
</form>
and because you are not working in get_context_data fucntion, just keep it simple
context = {'formset':formset}
Exemple from the docs
from django.forms import modelformset_factory
from django.shortcuts import render
from myapp.models import Author
def manage_authors(request):
AuthorFormSet = modelformset_factory(Author, fields=('name', 'title'))
if request.method == "POST":
formset = AuthorFormSet(
request.POST, request.FILES,
queryset=Author.objects.filter(name__startswith='O'),
)
if formset.is_valid():
formset.save()
# Do something.
else:
formset = AuthorFormSet(queryset=Author.objects.filter(name__startswith='O'))
return render(request, 'manage_authors.html', {'formset': formset})
Hope it can help others. Since I'm having troubles configuring the thousand separator, I tried to change the input.html widget in /templates/django/forms/widgets by adding the |intcomma filter.
This altered the management form data ( one field is set to 1000 by default ), thus corrupting the whole form.
I've written a basic forum model that allows users to create a post that others can respond to. After the user submits a form for a response to a forum post, the site displays a blank CommentForm, but instead, I want the user to be redirected to the unique forum post they responded to.
Here's what I have so far:
# views.py
from django.shortcuts import render, get_object_or_404
from .models import Forum
from .forms import CommentForm, ForumForm
from django.contrib.auth.decorators import login_required
# this is the view for the response form
#login_required
def newcomment(request):
form = CommentForm
if request.method == 'POST':
form = CommentForm(request.POST)
if form.is_valid():
post = form.save(commit = True)
post.save()
form = CommentForm
else:
form = CommentForm
return render(request, 'myapp/newcomment.html', {'form' : form})
# this is the view for a specific forum
def forumdetail(request, id):
forum = get_object_or_404(Forum, pk = id)
responses=[]
responses.append(forum.comment_set.all())
context={'forum' : forum,
'responses' : responses}
return render(request, 'myapp/forumdetail.html', context)
This is the webpage for the response form
<!-- myapp/newcomment.html -->
{% extends 'base.html' %}
{% block content %}
<h2 style="font-family: Impact; letter-spacing: 3px;">New Comment</h2>
<table class = 'table'>
<form method = "POST" class = "post-form">
{% csrf_token %}
{{form.as_table}}
</table>
<button type = 'submit' class = "save btn btn_default">
Save
</button>
</form>
{% endblock %}
This is the webpage for a specific forum
<!-- myapp/forumdetail.html -->
{% extends 'base.html' %}
{% block content %}
<h2 style="font-family: Impact; letter-spacing: 3px;">{{forum.topic}}</h2>
<p style = "border-bottom: solid; border-width: 1px; padding-bottom: 15px;">{{forum.description}}
<br>
<small>Posted by {{forum.userID}} on {{forum.date_created}}</small>
</p>
<button style = "background-color: gray;">
Comment
</button>
<h3>Comments:</h3>
<ul>
<li style = "list-style-type: none;">
{% for response in responses %}
{% for objs in response %}
{% if objs.forum == forum %}
{{ objs.response }}
<br>
<small style = "list-style-type: none; border-bottom: solid; border-width: 1px; padding-bottom: 15px;">
{{ objs.userID }} on {{ objs.date_created }}</small>
<br>
<br>
{% endif %}
{% endfor %}
{% endfor %}
</li>
</ul>
{% endblock%}
This is what you can do
from django.shortcuts import redirect
def newcomment(request):
form = CommentForm
if request.method == 'POST':
form = CommentForm(request.POST)
if form.is_valid():
post = form.save(commit = True)
post.save()
form = CommentForm
else:
form = CommentForm
return redirect('forumdetail', post.forum.id)
Try to use this :-
from django.shortcuts import redirect
def newcomment(request,id):
form = CommentForm
if request.method == 'POST':
form = CommentForm(request.POST)
if form.is_valid():
post = form.save(commit = True)
post.save()
form = CommentForm
else:
form = CommentForm
return redirect('forumdetail',id=id)
urls.py
path ('newcomment/<int:id>/', views.newcomment,name='newcomment'),
error messages are not working in Django templates.
after add error code in html template it shows no error message in webapp when fields are empty and press on submit button. html5 error is "novalidate" in template.
ValueError at /signup/
The view blog.views.user_signup didn't return an HttpResponse object. It returned None instead.
forms.py
from django import forms
from django.contrib.auth.forms import UserCreationForm, AuthenticationForm, UsernameField
from django.contrib.auth.models import User
from django.utils.translation import gettext,gettext_lazy as _
class SignUpForm(UserCreationForm):
password1 = forms.CharField(label='Password',widget=forms.PasswordInput(attrs={'class':'form-control'}))
password2 = forms.CharField(label='Confirm Password(again)',widget=forms.PasswordInput(attrs={'class':'form-control'}))
class Meta:
model = User
fields = ['username','first_name','last_name','email']
labels = {'username':'Username','first_name':'First Name','last_name':'Last Name','email':'Email'}
widgets = {'username':forms.TextInput(attrs={'class':'form-control'}),
'first_name':forms.TextInput(attrs={'class':'form-control'}),
'last_name':forms.TextInput(attrs={'class':'form-control'}),
'email':forms.EmailInput(attrs={'class':'form-control'}),}
class LoginForm(AuthenticationForm):
username = UsernameField(widget=forms.TextInput(attrs={'autofocus':True, 'class':'form-control'}))
password = forms.CharField(label=_('password'),strip=False, widget=forms.PasswordInput(attrs={'autocomplete':'current-password','class':'form-control'}))
signup.html
{% extends 'blog/base.html' %}
{% load static %}
{% block content %}
<div class="col-sm-10">
<h3 class="text-white my-5">Signup Page</h3>
<form action="" class="post" novalidate>
{% csrf_token %}
{% for fm in form %}
<div class="form-group">
{{fm.label_tag}} {{fm}} {{fm.errors | striptags}}
</div>
{% endfor %}
<input type="submit" value='Submit' class='btn btn-primary'>
{% if form.non_field_errors %}
{% for error in form.non_field_errors %}
<p> {{error}} </p>
{% endfor %}
{% endif %}
</form>
</div>
{% endblock content %}
views.py
from django.shortcuts import render,HttpResponseRedirect
from django.contrib import messages
# Create your views here.
# home
def home(request):
return render(request, 'blog/home.html')
# about
def about(request):
return render(request, 'blog/about.html')
# contact
def contact(request):
return render(request, 'blog/contact.html')
# Dashboard
def dashboard(request):
return render(request, 'blog/dashboard.html')
# Logout
def user_logout(request):
return HttpResponseRedirect('/')
# Signup
def user_signup(request):
if request.method == 'POST':
form = SignUpForm(request.POST)
if form.is_valid():
messages.success(request, 'Congratulations You have become an Author.')
form.save()
else:
form = SignUpForm()
return render(request, 'blog/signup.html',{'form':form})
# Login
def user_login(request):
form = LoginForm()
return render(request, 'blog/login.html', {'form':form})
You need to handle GET and POST request :
def user_signup(request):
if request.method == 'POST':
form = SignUpForm(request.POST)
if form.is_valid():
messages.success(request, 'Congratulations You have become an Author.')
form.save()
else:
form = SignUpForm()
return render(request, 'blog/signup.html',{'form':form})
Please make sure to use POST method in your html :
<form action="" method="POST" class="post" novalidate>
...
</form>
I dont understand this one...
the token is in the template and the 'django.middleware.csrf.CsrfViewMiddleware' is define in MIDDLEWARE_CLASSES
views.py:
from django.shortcuts import render_to_response
from ezmapping.models import *
from django.forms.models import modelformset_factory
def setMapOptions(request):
ezMapFormSet = modelformset_factory(ezMap, fields=('map_name', 'zoom_level', 'center_lat', 'center_long', 'map_width', 'map_height'))
if request.method == 'POST':
formset = ezMapFormSet(request.POST, request.FILES)
if formset.is_valid():
formset.save()
else:
formset = ezMapFormSet(queryset=ezMap.objects.filter(map_name ='first test'))
return render_to_response("ezmapping/manage_mapOptions.html", {'formset': formset,})
template:
<html>
<head>
<title>Manage Map Options</title>
</head>
<body>
<h1>Define map options</h1>
<form method="post" action="">{% csrf_token %}
{{ formset.management_form }}
{% for form in formset %}
{{ form.as_p }}
{% endfor %}
<input type="submit" value="Submit" />
</form>
</body>
</html>
You need to use RequestContext to use the CSRF tags.
https://docs.djangoproject.com/en/dev/ref/templates/api/#subclassing-context-requestcontext
context = RequestContext(request, {
'foo': 'bar',
})
# or
render_to_response('foo.html', {}, context_instance=RequestContext(request))
RequestContext takes the request object and loads all kinds of variables automatically, including CSRF.