I'm struggling to understand how to submit data from two django forms into two separate database tables from the same view. I only want one submit button. While this question got me closer to the solution, I'm getting errors and the data is not writing to the database. I think this code actually checks the two forms against each other instead of submitting both forms in one go. Any ideas?
Here's what I've tried:
For one form --> one table. This works, so it's a start.
# views.py
def BookFormView(request):
if request.method == 'POST':
form = BookForm(request.POST)
if form.is_valid():
form.save()
return HttpResponseRedirect("/books/")
else:
form = BookForm()
return render(request, 'books/createbooks.html',
{'form' : form})
However, when I add this form in from forms.py to get the subsequent views.py I get local variable 'book_form' referenced before assignment. That's usually an easy global-vs-local variable issue to fix, but I don't know what it means in this case.
def BookFormView(request):
if request.method == 'POST':
if 'book' in request.POST:
book_form = BookForm(request.POST, prefix='book')
if book_form.is_valid():
book_form.save()
return HttpResponseRedirect("/books/")
bookdetailsform = BookDetailsForm(prefix='bookdetails')
elif 'bookdetails' in request.POST:
bookdetailsform = BookDetailsForm(request.POST, prefix='bookdetails')
if bookdetailsform.is_valid():
bookdetailsform.save()
return HttpResponseRedirect("/books/")
book_form = BookForm(prefix='book')
else:
book_form = BookForm(prefix='book')
bookdetailsform = BookDetailsForm(prefix='bookdetails')
return render(request, 'books/createbook.html',
{'book_form' : book_form,
'bookdetailsform': bookdetailsform})
Based on the question's comments:
def BookFormView(request):
if request.method == 'POST':
book_form = BookForm(request.POST, prefix='book')
bookdetailsform = BookDetailsForm(request.POST, prefix='bookdetails')
if book_form.is_valid() and bookdetailsform.is_valid():
book_form.save()
bookdetailsform.save()
return HttpResponseRedirect("/books/")
else:
book_form = BookForm(prefix='book')
bookdetailsform = BookDetailsForm(prefix='bookdetails')
return render(request, 'books/createbook.html',
{'book_form': book_form, 'bookdetailsform': bookdetailsform})
I think the problem is that when a user submits a bookdetails post request,
it will be handled under if 'book' in request.POST: condition. Why?
because string bookdetails contains string book, no matter the type of request they do, it will be handled with if book in request.POST: condition.
I believe fixing that if condition problem is the first step.
Related
I have a view and a model form as shown below. I initially could get a single item ID to use inn the view. Now I need multiple items selected from a Select2MultipleWidget. How would I do this? I already tried as shown in my code. I can understand that the data from the form to the view is not correct.
def new_issue(request,pk):
borrowed = request.session.get('teacher_borrowings')
if request.method == 'POST':
form = IssueForm(request.POST,pk=pk)
if form.is_valid():
try:
book = form.cleaned_data['book_id'].id
form.save(commit=True)
books = Books.objects.filter.get(id=book)
Books.Claimbook(books)
return redirect('all_borrowed_teacher', borrowed=borrowed)
except Exception as e:
return redirect('/')
else:
pass
return render(request, 'item.html)
def new_issue(request,pk):
borrowed = request.session.get('teacher_borrowings')
if request.method == 'POST':
form = IssueForm(request.POST,pk=pk)
if form.is_valid():
try:
book = form.cleaned_data['book_id'].id
form.save(commit=True)
books = Books.objects.filter.get(id=book)
Books.Claimbook(books)
return redirect('all_borrowed_teacher', borrowed=borrowed)
except Exception as e:
return redirect('/')
else:
pass
return render(request, 'item.html)
The error
Select a valid choice. That choice is not one of the available choices.
I just wanna get profile with full form or empty form.
def local_cabinet(request):
user_id = request.user.id
caruser = Checkout.objects.filter(user=request.user)
# form = CheckoutForms()
orders = request.user.orderitem_set.all()
total_orders = orders.count()
ready_order = request.user.order_set.all()
customer = Customer.objects.filter(user=request.user)
customer_form = CustomerForm()
Maybe here's problem I don't know:
if request.method == 'POST':
if customer.exists():
form = CustomerForm(request.POST, request.FILES, instance=customer)
else:
form = CustomerForm(request.POST)
if form.is_valid():
form.save()
context = {
'caruser': caruser,
'orders': orders,
'total_orders': total_orders,
'ready_order': ready_order,
'cat_selected': 0,
'customer_form': customer_form,
'customer': customer,
}
return render(request, 'localcabinet.html', context=context)
I don't know why I get this, maybe because I'm not right at saving the form.
You are missing User instance in form, that you probably need to pass it after form creation and before saving it.
You didn't provide model nor forms, but I guess it will look like this:
if request.method == 'POST':
...
else:
form = CustomerForm(request.POST)
form.user = request.user
if form.is_valid():
form.save()
...
Another thing is that you assign queryset instead of single object with filter method:
customer = Customer.objects.filter(user=request.user) # gives queryset with probably one object
customer = Customer.objects.get(user=request.user) # gives an object - but gives Error if there is None or more than one
Probably the best approach to get single object is with try and except:
try:
customer = Customer.objects.get(user=request.user)
except Customer.DoesNotExists:
customer = None
then later instead of if customer.exists() you can use simple if customer.
I am trying to submit a form but receiving an error:
UnboundLocalError at /create/
local variable 'spr' referenced before assignment
Below is the section of my views.py file that is highlighted in the error, specifically:
return HttpResponseRedirect("/%i" %spr.id)
def create(response):
if response.method == "POST":
form = CreateNewSprint(response.POST)
if form.is_valid():
n = form.cleaned_data["name"]
spr = Sprint(name=n)
spr.save()
response.user.sprint.add(spr)
return HttpResponseRedirect("/%i" %spr.id)
else:
form = CreateNewSprint()
return render(response, "main/create.html", {"form": form})
I am unsure of why this is happening, any pointers in the right direction would be greatly appreciated. If any other code/information is needed please let me know.
If the form.is_valid() returns False, then it will aim to evaluate return HttpResponseRedirect("/%i" %spr.id), but spr is never set in that case. You thus should in that case rerender the invalid form:
def create(response):
if response.method == 'POST':
form = CreateNewSprint(response.POST)
if form.is_valid():
n = form.cleaned_data['name']
spr = Sprint(name=n)
spr.save()
response.user.sprint.add(spr)
return HttpResponseRedirect('/%i' %spr.id)
else:
form = CreateNewSprint()
return render(response, 'main/create.html', {'form': form})
Note: You can make use of redirect(…) [Django-doc] and
determine the url based on the view name and the parameters. This is more safe and elegant than performing string formatting and
then wrap it in a HttpResponseRedirect object [Django-doc].
I wish I could make a loop that would allow me to instantiate all my formsets for now I have written
def access(request, page_id):
if request.method == 'POST':
formset = ReplyFormSet(request.POST, request.FILES, initial=[{'instance':instance,}])
if formset.is_valid():
#...
return ...
else:
formset = ReplyFormSet(queryset=Reply.objects.filter(question=questions))
return ...
On this last line that I recovered the information in the db but just for my first forms! Is there way to make a loop so that it instantiates me all the forms?
I tried something like this but it does not work :
else:
for form in formset:
form.formset = ReplyFormSet(queryset=Reply.objects.filter(question=questions))
return ...
This line only works for my first form :
formset = ReplyFormSet(queryset=Reply.objects.filter(question=questions))
How can I do to affect it at all?
Should I change my init function of my ReplyForm ?
You could try:
formset = ReplyFormSet(queryset=Reply.objects.filter(question__in=questions))
Using the in filter you get every question which is in questions queryset.
I am working on my first django webaite, I am trying to submit two forms one after the other.
Here is the views.py :
def home(request):
import json
if request.method == 'POST':
form = MajorForm(request.POST)
if form.is_valid():
url = 'http://www.mysite.com:8082'
dataout = {'my':'data'}
headers = {'content-type':'application/json'}
r = requests.post(url,data=json.dumps(dataout),headers=headers)
return collector(request)
else:
return HttpResponse("thnx")
else:
form = MajorForm()
return render(request,'index.html',{'form':form})
def collector(request):
if request.method == 'POST':
form = ContactForm(request.POST)
if form.is_valid():
return HttpResponse("thanx")
else:
return HttpResponse("not valid")
else:
form = ContactForm();
return render(request,'collector.html',{'form':form})
So the first view calls the second view. The first form works fine, and the second form is also displayed fine, but submitting the second form does not work at all ( I was never able to get to form.is_valid path). Maybe this entire approach of calling one view from another is not correct? What would be the right one?
Please indent your code correctly. Also you are missing an else in the collector function when the request.method is not POST.