Django: Model Form "object has no attribute 'cleaned_data'" - python

I am trying to make a search form for one of my classes. The model of the form is:
from django import forms
from django.forms import CharField, ModelMultipleChoiceField, ModelChoiceField
from books.models import Book, Author, Category
class SearchForm(forms.ModelForm):
authors = ModelMultipleChoiceField(queryset=Author.objects.all(),required=False)
category = ModelChoiceField (queryset=Category.objects.all(),required=False)
class Meta:
model = Book
fields = ["title"]
And the view I'm using is:
from django.shortcuts import render_to_response, redirect, get_object_or_404
from django.template import RequestContext
from books.models import Book,Author
from books.forms import BookForm, SearchForm
from users.models import User
def search_book(request):
if request.method == "POST":
form = SearchForm(request.POST)
if form.is_valid():
form = SearchForm(request.POST)
stitle = form.cleaned_data['title']
sauthor = form.cleaned_data['author']
scategory = form.cleaned_data['category']
else:
form = SearchForm()
return render_to_response("books/create.html", {
"form": form,
}, context_instance=RequestContext(request))
The form shows up fine, but when I submit it I get an error: 'SearchForm' object has no attribute 'cleaned_data'
I'm not sure what's going on, can someone help me out? Thanks!

For some reason, you're re-instantiating the form after you check is_valid(). Forms only get a cleaned_data attribute when is_valid() has been called, and you haven't called it on this new, second instance.
Just get rid of the second form = SearchForm(request.POST) and all should be well.

I would write the code like this:
def search_book(request):
form = SearchForm(request.POST or None)
if request.method == "POST" and form.is_valid():
stitle = form.cleaned_data['title']
sauthor = form.cleaned_data['author']
scategory = form.cleaned_data['category']
return HttpResponseRedirect('/thanks/')
return render_to_response("books/create.html", {
"form": form,
}, context_instance=RequestContext(request))
Pretty much like the documentation.

I was facing the same problem,
I changed the code like this
if request.method == "POST":
form = forms.RegisterForm(request.POST)
if form.is_valid():
username = form.cleaned_data.get('username')
fname = form.cleaned_data.get('fname')
lname = form.cleaned_data.get('lname')
email = form.cleaned_data.get('email')
pass1 = form.cleaned_data.get('pass1')
pass2 = form.cleaned_data.get('pass2')

At times, if we forget the
return self.cleaned_data
in the clean function of django forms, we will not have any data though the form.is_valid() will return True.

Related

"save() got an unexpected keyword argument 'commit'" error in functional view

I got this error in my functional view:
save() got an unexpected keyword argument 'commit'
I'm try to save one object in database. 'debtors' is Many to Many field in models.py.
forms.py
class ExpenseForm(forms.ModelForm):
class Meta:
model = Expense
fields = ('amount', 'text', 'debtors', 'date', 'time',)
widgets = {
'date': AdminDateWidget(),
'time': AdminTimeWidget(),
'debtors': forms.CheckboxSelectMultiple(),
}
views.py
def expenseformview(request, pk):
if request.method == 'POST':
form = Expense.objects.create(
expenser = request.user,
amount = request.POST.get('amount'),
text = request.POST.get('text'),
date = request.POST.get('date'),
time = request.POST.get('time'),
)
form.debtors.add(request.POST.get('debtors'))
formcoseshare = form.save(commit=False)
formcoseshare.save()
form.save_m2m()
return redirect('expense_detail', pk=pk, expenseid=form.id)
else:
form = ExpenseForm()
return render(request, 'financials/expense_form.html', {'form': form})
How can to solve this problem?
Your form is not an ExpenseForm, it is a model object Expense, hence commit=False makes no sense, and neither does .save_m2m():
from django.contrib.auth.decorators import login_required
#login_required
def expenseformview(request, pk):
if request.method == 'POST':
form = ExpenseForm(request.POST, request.FILES)
if form.is_valid():
form.instance.expenser = request.user
expense = form.save()
return redirect('expense_detail', pk=pk, expenseid=expense.pk)
else:
form = ExpenseForm()
return render(request, 'financials/expense_form.html', {'form': form})
It is however unclear to me what pk is doing here: you do not use it in any way.
Note: You can limit views to a view to authenticated users with the
#login_required decorator [Django-doc].

Multi select checkbox doesnt work creating object in django

I have a app where people can declare things, within a decla they can say who was present so they have to pay, only its not working. The edit function works but the fileDecla doesn't.
The part that doensn't work is the present people. When i print the people present (via print(request.POST))before i save the decla it gives all the people selected but then it doesnt save them, and when i print(decla.present) i get --> None.(it should be all the people present.
Does someone know a solution to this?
models.py
class Decla(models.Model):
owner = models.ForeignKey(Lid, on_delete=models.CASCADE)
event = models.ForeignKey(Event, on_delete=models.SET_NULL, null=True, blank=True)
content = models.TextField(max_length=50)
total = models.FloatField()
present = models.ManyToManyField(Lid, related_name="present_leden")
receipt = models.ImageField(
upload_to="declas/", null=True, blank=True
) ## this will need to be put back to nothing when it ends
verwerkt = models.BooleanField(default=False)
views.py
#login_required(login_url="login")
def fileDecla(request):
form = DeclaForm()
if request.method == "POST":
print(1, request.POST)
form = DeclaForm(request.POST, request.FILES)
if form.is_valid():
# print(form)
decla = form.save(commit=False)
decla.owner = request.user.lid
# i tried this line bellow but it didnt work
# decla.present.set(request.POST["present"])
decla.save()
messages.info(request, "Decla was created")
return redirect("agenda")
context = {
"form": form,
"stand": Stand.objects.get(owner_id=request.user.lid.id).amount,
}
return render(request, "finance/decla_form.html", context)
#login_required(login_url="login")
def editDecla(request, pk):
decla = Decla.objects.get(id=pk)
form = DeclaForm(instance=decla)
if request.method == "POST":
print(request.POST)
form = DeclaForm(request.POST, request.FILES, instance=decla)
if form.is_valid():
decla = form.save()
messages.info(request, "Decla was edited")
return redirect(request.GET["next"] if "next" in request.GET else "agenda")
context = {
"form": form,
"stand": Stand.objects.get(owner_id=request.user.lid.id).amount,
}
return render(request, "finance/decla_form.html", context)
forms.py
from django import forms
from django.forms import ModelForm
from django.forms.widgets import NumberInput, CheckboxSelectMultiple
from .models import Decla
class DeclaForm(ModelForm):
class Meta:
model = Decla
fields = "__all__"
exclude = ["owner", "id"]
widgets = {
"present": CheckboxSelectMultiple(),
}
def __init__(self, *args, **kwargs):
super(DeclaForm, self).__init__(*args, **kwargs)
for name, field in self.fields.items():
if not name in ["verwerkt", "present"]:
field.widget.attrs.update({"class": "input"})
# also tried this
# elif name == "present":
# field.widget.attrs.update({"class": "CheckboxSelectMultiple"})
else:
field.widget.attrs.update({"class": "checkbox"})
Here is something from the docs:
Another side effect of using commit=False is seen when your model has
a many-to-many relation with another model. If your model has a
many-to-many relation and you specify commit=False when you save a
form, Django cannot immediately save the form data for the
many-to-many relation. This is because it isn’t possible to save
many-to-many data for an instance until the instance exists in the
database.
To work around this problem, every time you save a form using
commit=False, Django adds a save_m2m() method to your ModelForm
subclass. After you’ve manually saved the instance produced by the
form, you can invoke save_m2m() to save the many-to-many form data.
According to this, adding save_m2m() after calling decla.save() would resolve your issue:
#login_required(login_url="login")
def fileDecla(request):
form = DeclaForm()
if request.method == "POST":
print(1, request.POST)
form = DeclaForm(request.POST, request.FILES)
if form.is_valid():
# print(form)
decla = form.save(commit=False)
decla.owner = request.user.lid
# i tried this line bellow but it didnt work
# decla.present.set(request.POST["present"])
decla.save()
form.save_m2m()
messages.info(request, "Decla was created")
return redirect("agenda")
context = {
"form": form,
"stand": Stand.objects.get(owner_id=request.user.lid.id).amount,
}
return render(request, "finance/decla_form.html", context)
However, this seems like a messy solution. See this antipattern for more info.
My suggestion is to do this:
#login_required(login_url="login")
def fileDecla(request):
form = DeclaForm()
if request.method == "POST":
print(1, request.POST)
form = DeclaForm(request.POST, request.FILES)
if form.is_valid():
# This seems like a much cleaner solution and it should resolve your problem
form.instance.owner = request.user.lid
decla = form.save()
messages.info(request, "Decla was created")
return redirect("agenda")
context = {
"form": form,
"stand": Stand.objects.get(owner_id=request.user.lid.id).amount,
}
return render(request, "finance/decla_form.html", context)
Disclaimer: the code is untested. Let me know if you have any bugs.

rendered form isnt saving any input into database, why isnt it working?

I tryed to add validation to ContactModel, by doing Forms.py but I went too far away with it and now dont know to fix it. Can someone help ?
def addContact(request):
form = ContactForm()
if request.method == 'POST':
form = ContactForm(request.POST)
if form.is_valid():
# form = Contact(
# full_name = request.POST ('fullname'),
# relationship = request.POST ('relationship'),
# email = request.POST ('email'),
# phone_number = request.POST ('phone-number'),
# address = request.POST ('address'),
# )
form.save()
return redirect('/contact')
context = {'form': form}
return render(request, 'contact/new.html', context)
def contactProfile(request,pk):
contact = Contact.objects.get(id=pk)
return render(request, 'contact/contact-profile.html', {'contact': contact})
In my opinion in Views I have big mess.. When I fill up all fields data isn't sending to database.
forms.py:
from django.forms import ModelForm
from .models import Contact
class ContactForm(ModelForm):
class Meta:
model = Contact
fields = '__all__'
models.py:
from django.db import models
# Create your models here.
class Contact(models.Model):
full_name = models.CharField(max_length=500)
relationship = models.CharField(max_length=50)
email = models.EmailField(max_length=254)
phone_number =models.CharField(max_length=20)
address = models.CharField(max_length=100)
def __str__(self):
return self.full_name
It seems that your form is not valid and it redirects always to contact.
You should to use redirect only if the form is valid. Otherwise you will never see which errors your form contains.
Try the following code:
def addContact(request):
if request.method == 'POST':
form = ContactForm(request.POST)
if form.is_valid():
form.save()
return redirect('/contact')
else:
form = ContactForm()
context = {'form': form}
return render(request, 'contact/new.html', context)

Initial value not showing up in DecimalField

I have a form with a DecimalField and I have set the initial value like so:
class RawProductForm(forms.Form):
title = forms.CharField(label="")
description = forms.CharField(required=False)
price = forms.DecimalField(initial=199.99)
Here is the view:
from django.shortcuts import render
from .forms import ProductForm, RawProductForm
from .models import Product
def product_create_view(request):
form = RawProductForm(request.GET)
if request.method == "POST":
form = RawProductForm(request.POST)
if form.is_valid():
print(form.cleaned_data)
Product.objects.create(**form.cleaned_data)
else:
print(form.errors)
context = {
"form": form
}
return render(request, "products/product_create.html", context)
However, the initial value is not showing up when I render the page:
What could be the issue?
You should not use request.GET here as a source of data, since then it will try to parse the data out of a (likely non-existing) querystring. If you want to create an empty non-bounded form, you construct it without data:
def product_create_view(request):
if request.method == "POST":
form = RawProductForm(request.POST)
if form.is_valid():
print(form.cleaned_data)
Product.objects.create(**form.cleaned_data)
else:
print(form.errors)
else:
form = RawProductForm()
context = {
"form": form
}
return render(request, "products/product_create.html", context)
That being said, your code has some additional problems. If the creation is successful with a POST request, it is better to redirect, and implement the Post/Redirect/Get pattern [wiki]. Furthermore you probably here should use a ModelForm, this will ensure that the creation of the model object (here a Product) is done correctly.

How can I get the id of the particular modelform?

I am new to Django. I am just learning to use forms and modelforms. Here I used modelforms to get two charfields(username and password) and saving it. What I wanted to do is to get the model id of that username. Below is the code. But I can't get the id.
from django.http import HttpResponse, Http404, HttpResponseRedirect
from django.core.urlresolvers import reverse
from reg.models import registration, registrationform
from django.shortcuts import render_to_response, get_object_or_404
from django.template import RequestContext
def registration(request):
if request.method == 'POST':
form = registrationform(request.POST)
if form.is_valid():
form.save()
username = form.cleaned_data['username']
p = registration.objects.all()
for loop in p:
if loop.username == username:
id = loop.id
return HttpResponseRedirect(reverse('reg.views.thanks', args=(id)))
else:
form = registrationform()
return render_to_response('registration.html', {'form' : form}, context_instance=RequestContext(request))
def thanks(request, id):
p = get_object_or_404(registration, pk=id)
return render_to_response('thanks.html', {'reg': p)
One more question. What is the model field for password?
Thanks.
if request.method == 'POST':
form = registrationform(request.POST)
if form.is_valid():
data =form.save()
#...
id = data.id
#...
return HttpResponseRedirect(reverse('reg.views.thanks', args=(id)))
user = form.save(commit=False)
user.first_name = u'First name'
user.last_name = u'Last name'
user.save()
For password use password1 field
Please could you paste your urls.py?
I recently had a problem almost exactly the same as this - it was just a typo there, I had the wrong value in in second field of the url function:
url(r'^people/thanks/(?P<person_id>\d+)$', 'people.views.thanks'),
Should have been:
url(r'^people/thanks/(?P<person_id>\d+)$', 'people.views.new'),
How about changing your registration function to this:
def registration(request):
if request.method == 'POST':
form = registrationform(request.POST)
if form.is_valid():
userdetails = form.save()
user = userdetails.username
val = registration.objects.get(username = user)
return HttpResponseRedirect(reverse('reg.views.thanks', args=(val.id)))
else:
form = registrationform()
return render_to_response('registration.html', {'form' : form}, context_instance=RequestContext(request))
I suggest you read this: https://docs.djangoproject.com/en/dev/topics/forms/modelforms/

Categories

Resources