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.
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 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)
I can create model objects through admin panel. But I want it to be created on website. The code below allows me to enter values of a model, and when I submit it, it redirects to the written url, which happens after form.save. This is the message from server "POST /taskcreate HTTP/1.1" 302 0. But there is no changes in database. How to solve this issue? Any thoughts... Thanks
models.py
class Task(models.Model):
name = models.CharField(max_length=200)
description = models.CharField(max_length=1000)
pub_date = models.DateTimeField('date_published', auto_now_add = True)
cost = models.IntegerField()
def __str__(self):
return '%s' % (self.name)
forms.py
class TaskCreateForm(forms.ModelForm):
class Meta:
model = Task
fields = ('name', 'description', 'cost')
views.py
def TaskCreateView(request):
if request.method == 'POST':
form = TaskCreateForm(request.POST)
if form.is_valid():
form.save
return redirect('home')
else:
form = TaskCreateForm()
return render(request, 'employer/create_task.html')
You didn't actually call the save method.
if form.is_valid():
form.save()
return redirect('home')
When you use ModelForm you just need to write form.save() method right after if is_valid() if case. In your case, you are missing curly brackets after save.
def TaskCreateView(request):
if request.method == 'POST':
form = TaskCreateForm(request.POST)
if form.is_valid():
form.save() # here you were missing curly brackets
return redirect('home')
else:
form = TaskCreateForm()
return render(request, 'employer/create_task.html')
I want to pass a pk from one form to another so that it can be used as the foreign key for the second form. Here are the model:
models.py
class CompanyDetails(models.Model):
name = models.CharField(max_length=100)
class CompanyDetailsForm(forms.ModelForm):
class Meta:
model = CompanyDetails
class DataRequest(models.Model):
company = models.ForeignKey(CompanyDetails, default="0")
agency_name = models.CharField(max_length=100)
class DataRequestForm(forms.ModelForm):
class Meta:
model = DataRequest
exclude = ['company']
And here is the view for the first form:
views.py
def index(request):
if request.method == 'POST':
form = CompanyDetailsForm(request.POST or None)
if form.is_valid():
data = form.save(commit=False)
data.save()
return HttpResponseRedirect(reverse('canareeform:datarequest', data.id))
else:
form = CompanyDetailsForm()
return render(request, 'canareeform/index.html', {'form': form})
How should I set up my second view so that the form will save an object that has the foreign key for the object created by the first form in it?
I got it to work by passing the primary key of the first object through the url. It goes abc.com/form -> abc.com/form/16/datarequest. Not super ideal since by changing the number in the url the second object will use some other foreign key.
views.py
def index(request):
if request.method == 'POST':
form = CompanyDetailsForm(request.POST or None)
if form.is_valid():
data = form.save(commit=False)
data.save()
return HttpResponseRedirect(reverse('canareeform:datarequest', args=(data.id,)))
else:
form = CompanyDetailsForm()
return render(request, 'canareeform/index.html', {'form': form})
def datarequest(request, company_id):
if request.method == 'POST':
form = DataRequestForm(request.POST or None)
if form.is_valid():
data = form.save(commit=False)
data.company = CompanyDetails.objects.get(pk=company_id)
data.save()
return HttpResponse("Thanks")
else:
form = DataRequestForm()
return render(request, 'canareeform/datarequest.html', {'form': form})
If anyone has a better solution I'd love to hear it.
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.