I'm having some problems with model formsets in django.
# forms.py
OppFormSet = modelformset_factory(Opportunity, fields=opp_fields)
# views.py
def index2(request):
queryset = Opportunity.objects.for_user(request.user).filter(is_deleted=False)
if request.method == 'POST':
formset = OppFormSet(request.POST, queryset=queryset)
else:
formset = OppFormSet(queryset=queryset)
return render_to_response("opp_index2.tmpl", { "formset" : formset}, context_instance=RequestContext(request))
Here are my 2 questions regarding model forms:
In my template I have {% for form in formset %} to create the forms in a table, but somehow, I keep getting an extra blank row, as if there is an additional blank form in the formset.
If i use {{ form.instance.id }} to output an id while iterating through the formset, it prints out ok. However, if I do a {% url summary form.instance.id %} I keep getting an error regarding no NoReverseMatch with arguments (None,). It seems like when using form.instance.id in a template tag, it doesn't work. Is that true? If so, how do i circumvent it?
Thank you in advance.
Use {% for form in formset.forms %} This "blank form" is ManagementForm
Related
few months ago i made a website where it worked but similar code this time isn't working! it returns :
ValueError at /registration/
The User could not be created because the data didn't validate.
this is my form.py in bottom:
class CreateUserForm(UserCreationForm):
class Meta:
model = User
fields = ["username", "email", "password1", "password2"]
my views:
from .form import CreateUserForm
def registrationPage(request):
form = CreateUserForm()
if request.method == "POST":
form = CreateUserForm(request.POST)
if form.is_valid:
form.save()
return redirect("login")
else:
form = CreateUserForm()
context = {"form": form}
return render(request, "store/registration.html", context)
in HTML previously i used :
{{form.errors}}
& it used to show me work on the page but not anymore
According to your comment above ("i want django to show the error messages"[if password is weak in example]), you should add this to your html page (instead than {{form.errors}}).
<div class="error-message">
{% if form.non_field_errors %}
{% for error in form.non_field_errors %}
<p style="font-size: 13px;">
{{ error|escape }}
</p>
{% endfor %}
{% endif %}
</div>
Form.non_field_errors()
This method returns the list of errors from Form.errors that aren’t associated with a particular field. This includes ValidationErrors that are raised in Form.clean() and errors added using Form.add_error(None, "...").
When this error you get then do this:
You must type strong password, which is provided by Django.
password validation rules:
At least 1 digit;
At least 1 uppercase character;
At least 1 lowercase character;
At least 1 special character;
for example:
Example#4089
This error will come while confirming your password, you must enter correct password in both the fields.
you will face this error if user is already exist.
you must check exists user while creating user, if user exist, this error will come.
I started to learn Django today, but I am stuck at using forms. I have created two forms: /contact and /blog-new. The form at the Contact page is working fine, but the one at /blog-new is redirecting me to the home page after the submission button is pressed and no information is printed in the terminal nor saved in the database.
Code on Github
I appreciate if someone can explain to me what I did wrong as I cannot figure it out. Thank you!
mysite/blog/forms.py
from django import forms
from .models import BlogPost
class BlogPostModelForm(forms.ModelForm):
class Meta:
model = BlogPost
fields = ['title', 'slug', 'content']
mysite/blog/views.py
from .forms import BlogPostModelForm
def blog_post_create_view(request):
# create objects
# ? use a form
# request.user -> return something
form = BlogPostModelForm(request.POST or None)
if form.is_valid():
print(form.cleaned_data)
form.save()
form = BlogPostModelForm()
template_name = 'form.html'
context = {'form': form}
return render(request, template_name, context)
mysite/blog/models.py
from django.db import models
# Create your models here.
class BlogPost(models.Model):
title = models.TextField()
slug = models.SlugField(unique=True)
content = models.TextField(null=True, blank=True)
mysite/mysite/urls.py
from blog.views import (
blog_post_create_view,
)
urlpatterns = [
..
path('blog-new', blog_post_create_view),
..
]
mysite/templates/form.html
{% extends "base.html" %}
{% block content %}
{% if title %}
<h1>{{ title }}</h1>
{% endif %}
<form method='POST' action='.'> {% csrf_token %}
{{ form.as_p }}
<button type='submit'>Send</button>
</form>
{% endblock %}
You need to point to right url in action attribute of form.
<form action="/blog-new/" method="post">
{% csrf_token %}
{{ form }}
<input type="submit" value="Submit">
</form>
I think it's not necessary in your case but you could also refactor your view to match the docs.
from django.http import HttpResponseRedirect
from django.shortcuts import render
from .forms import SomeForm
def some_view(request):
# if this is a POST request we need to process the form data
if request.method == 'POST':
# create a form instance and populate it with data from the request:
form = SomeForm(request.POST)
# check whether it's valid:
if form.is_valid():
# process the data in form.cleaned_data as required
# ...
# redirect to a new URL:
return HttpResponseRedirect('/thanks/')
# if a GET (or any other method) we'll create a blank form
else:
form = SomeForm()
return render(request, 'template_name.html', {'form': form})
You need to point to right url in action attribute of form.
That was not actually the solution but something that helped me to figure out what was wrong.
It is not necessary to point to /blog-new/ as . for action will point to the same page, but I have tried with /blog-new/ as action URL and I was surprised to see that /blog-new/ page doesn't exist.
The bug was in mysite/mysite/urls.py for missing a /:
path('blog-new', blog_post_create_view),
It is funny (and annoying) how a symbol like / missing from your code will mess up everything and make you spend hours trying to find a solution as simple as that.
Thank you for your time spend to have a look over my code and try to help me!
I'm trying to get validation running on a django form used to retrieve a list of objects in a ListView View. Despite having read django docs and many other questions here, I can't find out what's wrong in this simple test code:
form.html
<form action="list.html" method="get">
{{ form }}
<input type="submit" value="Submit">
</form>
list.html
<ul>
{% for area in object_list %}
<li>{{ area.name }}</li>
{% endfor %}
</ul>
forms.py
from django import forms
class SearchArea(forms.Form):
area = forms.CharField(label='Area code', max_length=6)
def clean_area(self):
area = self.cleaned_data['area'].upper()
if '2' in area:
raise forms.ValidationError("Error!")
return area
views.py
class HomePageView(FormView):
template_name = 'form.html'
form_class = SearchArea
class AreaListView(ListView):
template_name = 'list.html'
model = AreaCentral
def get_queryset(self):
q = self.request.GET.get('area')
return AreaCentral.objects.filter(area__istartswith=q)
When I try to submit something like "2e" I would expect a validation error, instead the form is submitted. Moreover I can see in the GET parameters that 'area' is not even converted to uppercase ('2E' instead of '2e').
The default a FormView will only process the form on POST; the GET is for initially displaying the empty form. So you need to use method="post" in your template form element.
Your action attribute is also suspect; it needs to point to the URL of the form view. If that actually is the URL, note it's not usual to use extensions like ".html" in Django URLs, and I would recommend not doing so.
Django version 1.8.7
I'm creating a pages where the user has to add a list of invitees to his weeding so I needed to use the same form many times on the same page to create mnay model instances of the invitees; In order to do that I used model formsets using modelformset_factory function .
So in my forms.py
class InviteesForm(ModelForm):
class Meta:
model = Invitees
fields = ['user', 'invitee_name' , 'invitee_address', 'invitee_count',
'invitee_email']
exclude = ('user',)
#creating a formset
InviteesFormSet = modelformset_factory(Invitees, form = InviteesForm )
Above you can see my model form for the invitees model and my InviteesFormSet which uses modelformser_factory fucntion.
In my views.py
def preview(request):
formset = forms.InviteesFormSet(queryset=Invitees.objects.all())
if request.method == 'POST':
formset = forms.InviteesFormSet(request.POST)
if formset.is_valid():
formset.save(commit = False)
return redirect('/invitees/')
else:
formset = forms.InviteesFormSet(request.POST)
return render(request, 'preview.html', {'formset': formset} )
In my Preview.html
<form action="/preview/" method='POST'>
{% csrf_token %}
{{ formset.management_form }}
<button type="submit">Add an Invitee</button>
</form>
The formset is not rendering in my html, am not sure what I'm doing wrong here, it's basic code! but I get this error
[u'ManagementForm data is missing or has been tampered with']
I tried the solution mentioned here by adding .management_form to the formset on template page : referred here
https://docs.djangoproject.com/en/dev/topics/forms/formsets/#understanding-the-managementform
Can you please help me figure out the issue?
Thanks
from your code
if request.method == 'POST':
formset = forms.InviteesFormSet(request.POST)
if formset.is_valid():
formset.save(commit = False)
return redirect('/invitees/')
else:
formset = forms.InviteesFormSet(request.POST)
do not use request.POST if it is a GET request
just do
formset = forms.InviteesFormSet(queryset=Invitees.objects.all()) (you can remove the else clause altogether)
I keep getting the error:
[u'ManagementForm data is missing or has been tampered with']
I can't figure out why either. Here is my view:
def CreateWorkout(request):
WorkoutInlineFormSet = inlineformset_factory(workout,exercise)
if request.method == "POST" :
formset = WorkoutInlineFormSet(request.POST)
if formset.is_valid():
formset.save();
else:
formset = WorkoutInlineFormSet()
return render_to_response('submit.html',{'formset': formset},context_instance=RequestContext(request))
And here is my template:
<body>
<form method="POST" action ="">
{{ formset.management_form }}
<table>
{% for form in formset.forms %}
{{ form }}
{% endfor %}
</table>
</form>
</body>
I've read that you have to include the formset.management_form, and I have. I thought that would be an easy fix, but I haven't been able to figure out the problem.
I have meet this problem.
The reason is there is NO something like form-TOTAL_FORMS, form-INITIAL_FORMS and form-MAX_NUM_FORMS) in your POST data.
You should use {{ formset.as_p }}, this will render the management_form data from the formset. If you want to make the custom formset rendering, you should not forget the management_form of the formset to let POST data be with the mangement_form data.
When you use inline formset, you need to provide the instance that the objects relate to.
# First, fetch the instance from the db
workout = code_that_fetches_instance()
if request.method == "POST" :
formset = WorkoutInlineFormSet(request.POST, instance=workout)
...
else:
formset = WorkoutInlineFormSet(instance=workout)
See the example in the docs on using an inline formset in a view for more information.
If workout and exercise are your models, you should follow the python convention and rename them Workout and Exercise. Lowercase workout should be the instance that all the exercises in your formset are linked to.
Change this:
formset = WorkoutInlineFormSet(request.POST)
to this:
formset = WorkoutInlineFormSet(request.POST or None, request.FILES or None)