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.
Related
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].
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.
how do I not save the form data until the transaction is done which is in a different URL, if the shipping form and the payment options were to be in the same URL then there wouldn't be this problem but it's not so how do I go about this? thx!
views.py
def checkout(request):
if request.method == 'POST':
form = ShippingForm(request.POST)
if form.is_valid():
new_shipping = form.save(commit=False)
new_shipping.customer = customer
new_shipping.order = order
#how do I not save the data until the transaction is successful
new_shipping.save()
return redirect('store:checkout_shipping')
else:
form = ShippingForm()
else:
form = ShippingForm()
context = {"form": form}
return render(request, 'shop/checkout.html', context)
def checkout_payment(request):
return render(request, 'shop/checkout_payment.html', context)
urls.py
path('checkout', views.checkout, name="checkout"),
path('checkout_payment', views.checkout_payment, name="checkout_payment"),
forms.py
class ShippingForm(forms.ModelForm):
address_one = forms.CharField(max_length=200)
address_two = forms.CharField(max_length=200)
I think what might help is to use sessions. Django will store this temporary data using session cookies. Here's the idea:
from django.forms.models import model_to_dict
def checkout(request):
form = ShippingForm(request.POST or None)
if form.is_valid():
new_shipping = form.save(commit=False)
new_shipping.customer = customer
new_shipping.order = order
request.session['partial-data'] = model_to_dict(new_shipping)
return redirect('store:checkout_shipping')
context = {"form": form}
return render(request, 'shop/checkout.html', context)
def checkout_payment(request):
# I'm guessing here is where the rest of the data
# is to be filled in. The data of the previous view
# is already here stored in the cookie
full-form-data = request.session['partial-data']
full-form-data['extra-field-1'] = 'something'
full-form-data['extra-field-2'} = 'something else'
form = ShippingForm(full-form-data or None)
if form.is_valid():
form.save()
context = {
'form': form
}
return render(request, 'shop/checkout_payment.html', context)
I'm trying to create a form that takes inputs and uses these inputs to create an output that's posted to a results page. I've searched everywhere and can't understand how to post the data (in the case below, 'country' and 'culture') to the results_view.
# view.py
from django.shortcuts import render
from django.http import HttpResponseRedirect
from django.shortcuts import get_object_or_404, render
from form.forms import InputForm
def get_list(request):
if request.method == 'GET':
form = InputForm(request.GET)
if form.is_valid():
country = form.cleaned_data['country']
culture = form.cleaned_data['culture']
return results_view(form)
else:
form = InputForm()
return render(request, 'form/index.html', {'form': form})
def results_view(form):
text = form.restaurant
c = {'output' : text}
return render(form, 'form/results.html', c)
and
# forms.py
from django import forms
class InputForm(forms.Form):
country = forms.CharField(label='country', max_length=100)
cuisine = forms.CharField(label='cuisine', max_length=100)
How can I access the inputs and use them as the text in 'results_view'? Additionally, if I want to pass these results as an input argument for another python function (say a function that maps country name to latitude and longitude), how can I incorporate this into views.py? Thanks a lot!
You don't need to redirect to another function, just render this another template
# view.py
from django.shortcuts import render
from django.http import HttpResponseRedirect
from django.shortcuts import get_object_or_404, render
from form.forms import InputForm
def get_list(request):
if request.method == 'POST':
form = InputForm(request.POST)
if form.is_valid():
country = form.cleaned_data['country']
culture = form.cleaned_data['culture']
c = {'country' : country, 'culture'... whatever you get}
return render(form, 'form/results.html', c)
else:
form = InputForm()
return render(request, 'form/index.html', {'form': form})
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.