Django: POST and GET request and rendering on a template - python

I'm probably lost in a glass of water but at the moment I can't figure it out. I'm working on a restaurant capstone project where the client is able to see a menu page, a purchase page and the owner of the restaurant after login is able to manage and enter a new recipe and create his personal menu. What I'm trying to do is: when the owner of the restaurant submits a POST request where he entered the recipe, i want that the recipe appear also in the page where is the menu. In this way is able to update new recipe and change maybe the old one. (I copy model, form and view code for a complete overview):
form.py
class RecipeForm(forms.ModelForm):
class Meta:
model = Recipe
fields = '__all__'
model.py
class Recipe(models.Model):
name = models.CharField(max_length=50)
ingredients = models.CharField(max_length=500)
def __str__(self):
return self.name
View.py
def recipeEntry(request):
recipe_menu = Recipe.objects.all()
form = RecipeForm()
if request.method == 'POST':
form = RecipeForm(request.POST)
if form.is_valid():
form.save()
return redirect("recipe")
context = {'form':form, 'recipe_menu':recipe_menu}
return render(request, 'inventory/recipe.html', context)
recipe.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Recipe</title>
</head>
<body>
<form method="post", action="">{% csrf_token %}
{{form.as_p}}
<input type="submit" value="Add Recipe">
</form>
{% for rec in recipe_menu %}
<div>
<p>Recipe: {{rec.name}}</p>
<p>Ingredient :{{rec.ingredients}}</p>
</div>
{% endfor %}
</body>
</html>
At the moment the part of submitting the POST request it works so is only the second part that don't works. I tried a bit few solution but i don't understand what to do. I thought also to create a GET view for the menu page but i need to pass an URL for get the data and i didn't works.
Thank you very much for the help.

You must try with explicitly instantiate empty form when it's not a post request :
def recipeEntry(request):
recipe_menu = Recipe.objects.all()
# form = RecipeForm() Not here yet
if request.method == 'POST':
# Instantiate form with request.POST
form = RecipeForm(request.POST)
if form.is_valid():
form.save()
return redirect("recipe")
else: # Explicitly write else block
# Instantiate empty form for get request
form = RecipeForm()
context = {'form':form, 'recipe_menu':recipe_menu}
return render(request, 'inventory/recipe.html', context)

Related

Django Form not updating data in the model

this is my first Django project and I am stuck. If not a solution, but just a hint on what I am doing wrong will be truly appreciated.
I have a model with one attribute set as Null by default and I want to use a Form to update that attribute with the ID taken from another model.
These are the 2 models:
models.py
class Squad(models.Model):
squad_name = models.CharField(max_length=20)
def __str__(self):
return self.squad_name
class AvailablePlayer(models.Model):
player_name = models.CharField(max_length=25)
squad = models.ForeignKey(Squad, on_delete=models.CASCADE, blank=True, null=True)
def __str__(self):
return self.player_name
This is the form:
forms.py
class AddSquadToPlayerForm(forms.Form):
# squad the player will be added to
squad_to_player = forms.ModelMultipleChoiceField(queryset=None)
def __init__(self, *args, **kwargs):
super(AddSquadToPlayerForm, self).__init__()
self.fields['squad_to_player'].queryset = AvailablePlayer.objects.all()
This is the view file, where I think something is missing/wrong:
views.py
def add_player_to_squad(request, squad_id):
# player = AvailablePlayer.objects.get(id=squad_id)
squad = Squad.objects.get(id=squad_id)
if request.method == "POST":
form = AddPlayerToSquadForm(request.POST)
if form.is_valid():
form.squad = form.cleaned_data['id']
form.save()
return redirect('fanta_soccer_app:squad', squad_id=squad_id)
else:
form = AddPlayerToSquadForm(queryset=AvailablePlayer.objects.all())
context = {"squad": squad, "form": form}
return render(request, 'fanta_soccer_app/add_player.html', context)
And finally, this is html file
add_player.html
<body>
<p>Add a new player to the Squad:</p>
<p>{{ squad }}</p>
<form action="{% url 'fanta_soccer_app:add_player' squad.id %}" method="POST">
{% csrf_token %}
<table>
{{ form.as_table }}
</table>
<button name="submit" type="submit" >Add player</button>
</form>
</body>
The rendered html shows correctly a form with a drop down menu correctly populated with the objects in the database from the "AvailablePlayer" model, however when selecting one and clicking on "Add", nothing happens, and selected player is not added to the DB.
Thank you in advance for your time.
EDIT: the code in views.py has been modified according to a comment
ADDITIONAL INFO: to confirm the db is working, if I manually add the squad_id to one of the AvailablePlayer(s) in the DB, it will be correctly listed in the squad details view.
Based off the docs I think where you are going wrong is that you are trying to update an existing value, which requires you to pass an instance keyword argument to form.save().
So I think you need to do something like this:
if form.is_valid():
a = Squad.objects.get(id=squad_id)
form = AddSquadToPlayerForm(request.POST, instance=a)
form.squad = form.cleaned_data['id']
form.save()
I managed to fix it by myself, and sharing here the solution:
I changed the form field from ModelMultipleChoiceField to ModelChoiceField. ModelMultipleChoiceField is for ManyToMany relationships model fields, while mine is a ForeignKey. I have also removed the init method:
squad_to_player = forms.ModelChoiceField(queryset=AvailablePlayer.objects.all())
The view was pretty messed up, as I was aware of, but after fixing the above, I started to have error logs, so I could eventually come up with the following solution:
view.py
def add_player_to_squad(request, squad_id):
squad = Squad.objects.get(id=squad_id)
if request.method == "POST":
form = AddPlayerToSquadForm(request.POST)
if form.is_valid():
player_to_sign = form.cleaned_data['squad_to_player']
player_to_sign.squad = squad
player_to_sign.save()
return redirect('fanta_soccer_app:squad', squad_id=squad_id)
else:
form = AddPlayerToSquadForm()
context = {"squad": squad, "form": form}
return render(request, 'fanta_soccer_app/add_player.html', context)

Django - How do you get the corresponding model object in a for loop in html?

I am trying to create a simple django website where any user can rate and create posts. As displayed in this django tutorial (https://docs.djangoproject.com/en/1.7/topics/templates/), you can display all the model objects in html using a for loop. In my case, each object is going to be displayed with a Like and a Dislike button, so people can rate the post. My problem is: How do I know which object belongs to which like/dislike button so that the corresponding model field can be changed for that particular object? Thank You for answers!
models.py
from django.db import models
# Create your models here.
class Post(models.Model):
post_text = models.CharField(max_length=500)
pub_date = models.DateTimeField("date published")
likes = models.IntegerField(default=0)
dislikes = models.IntegerField(default=0)
def __str__(self):
return self.post_text
index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>AllPosts</title>
</head>
<body>
{% if post_list %}
<ul>
{% for post in post_list %}
<li>{{post.post_text}}</li>
<p>This post has {{post.likes}} likes and {{post.dislikes}} dislikes.</p>
<br>Leave a <button type="button" method="LIKE">Like</button> or a <button type="button" method="DISLIKE">Dislike</button>!</p>
{% endfor %}
</ul>
<h2>If you want to create a post yourself, click here.</h2>
{% else %}
<h1>There are no posts yet...</h1>
{% endif %}
</body>
</html>
views.py
from django.http import HttpResponse
from django.template import loader
from django.shortcuts import render
from django.utils import timezone
from .models import Post
# Create your views here.
def index(request):
post_list = Post.objects.order_by('-pub_date')
template = loader.get_template('post/index.html')
context = {'post_list': post_list, }
#if request.method == "LIKE":
# post = Post.objects.get(id=) How do I find out the id?
# return HttpResponse(template.render(context, request))
#else:
return HttpResponse(template.render(context, request))
def create(request):
template = 'post/create.html'
if request.method == 'POST':
post = Post()
post.post_text = request.POST.get("post_text")
post.pub_date = timezone.now()
post.save()
return render(request, template)
else:
return render(request, template)
In order for the buttons to work, they need to be inside a form element and be of type="submit" otherwise they won't do anything when clicked. To identify which button was clicked, you can then replace the method attributes with name="like" and name="dislike". The buttons can then be referenced to the related post by setting their value to the post ID.
Below is an example of the code that should do this. I've clipped out some of the unrelated parts of the code. (Note: I haven't tested this, so it may not work perfectly)
index.html UL element:
<ul>
{% for post in post_list %}
<li>
<span>{{post.post_text}}</span><br>
<p>This post has {{post.likes}} likes and {{post.dislikes}} dislikes.</p>
<form method="post">
<p>
Leave a <button type="submit" name="like" value="{{post.id}}">Like</button>
or a <button type="submit" name="dislike" value="{{post.id}}">Dislike</button>!
</p>
</form>
</li>
{% endfor %}
</ul>
views.py index:
def index(request):
if request.method == 'POST':
like = request.POST.get('like')
dislike = request.POST.get('dislike')
if like:
# Handle liked post
# `like` is equal to the post ID
else if dislike:
# Handle disliked post
# `dislike` is equal to the post ID
else:
# No action requested
else:
post_list = Post.objects.order_by('-pub_date')
template = loader.get_template('post/index.html')
context = {'post_list': post_list, }
return HttpResponse(template.render(context, request))
I hope this helps :)

Django: How to create a form using inline_formset with a many to one relationship with user

I am trying to set up a form using Django's inlineformset_factory. The model is set up in a many to one relationship, each user will have many cases. I want the user to add a case.
I have followed the general outline from this site
models.py
class Case(models.Model):
date_due = models.DateField()
user = models.ForeignKey(User, on_delete=models.CASCADE)
forms.py
CaseFormset = inlineformset_factory(User,Case,
fields=('date_due',),
can_delete = True)
class CaseForm(forms.ModelForm):
class Meta:
model = Case
fields = ('date_due',)
views.py
#login_required
def add_case(request):
if request.method == 'POST':
form = CaseForm(request.POST)
if form.is_valid():
case = form.save(commit = False)
case_formset = CaseFormset(request.POST, instance = case)
if case_formset.is_valid():
case.save()
case_formset.save()
return redirect('index')
else:
print(form.errors)
else:
form = CaseForm()
case_formset = CaseFormset(instance = Case())
return render(request, 'cases/add_case.html',
{'form':form, 'case_formset':case_formset})
add_case.html
<!DOCTYPE html>
{% load staticfiles %}
<html>
<head>
<body>
<form method="post">
{% csrf_token %}
{{ form.as_p }}
{{ case_formset.as_p }}
{{ case_formset.management_form }}
<button type="submit">Save changes</button>
</form>
</body>
</head>
</html>
I am getting a
Exception Type: ValidationError
Exception Value:
['ManagementForm data is missing or has been tampered with']
Reading the docs it looks like I need to add the management_form to the formset, which I have done. I am not sure where else I am going wrong.
I also tried a different approach from the docs
It looks slightly different than the above and tried to create a formset using the user as an instance. I am not sure which approach is preferable.
I have two questions.
Why I am I getting the above error?
Should I be setting the formset to an instance of user instead of case?
Thanks
I figured it out!
In views.py I needed to add case.user = request.user
So views.py looks like
#login_required
def add_case(request):
if request.method == 'POST':
form = CaseForm(request.POST)
if form.is_valid():
case = form.save(commit=False)
case.user = request.user
case_formset = CaseFormset(request.POST, instance = case)
if case_formset.is_valid():
case.save()
case_formset.save()
return redirect('index')
else:
print(form.errors)
else:
form = CaseForm()
case_formset = CaseFormset(instance = Case())
return render(request, 'cases/add_case.html',
{'form':form, 'case_formset':case_formset})

Django form.py not updating

I have been going through the Django forms 'tutorial'. Once I had read through the tutorial, I tried modifying it to suit my needs and customize it to learn it Django forms well. I discovered whenever I modified the form, the website would not update. I assume its an error with my code, but I have not been able to find it.
# views.py
def contact(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 = ContactForm(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('/message_recived/')
# forms.py
from django import forms
class ContactForm(forms.Form):
name = forms.CharField(label='Name', max_length=100)
email = forms.EmailField(label='Email', max_length=100)
message = forms.CharField(label='Message', max_length=500)
# models.py
from django.db import models
class Contact(models.Model):
name = models.CharField(max_length=100)
email = models.CharField(max_length=100)
message = models.CharField(max_length=500)
and here is the contact.html template:
#contact.html
{% extends "BlogHome/headerAndFooter.html" %}
{% block content %}
<script>
document.title = "Pike Dzurny - Contact"
</script>
<form action="/message_recived/" method="post">
{% csrf_token %}
{{ form }}
<input type="submit" value="Submit" />
</form>
{% endblock %}
Did I do something wrong? I have tried clearing my browsers cache, using a new browser, and obviously refreshing it.
Looks like your forget to render response inside your view.
Also you need to include form into context to render template right.
Try to change view as follow:
def contact(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 = ContactForm(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('/message_recived/')
else:
form = ContactForm()
return render(request, 'contact.html', {'form': form})

Validating the form without required field in django 1.8

My django modelform is letting the user submit the form without raising error even when the user hasn't submitted appropriate form, here it lets the user keep the email field blank.It doesn't save into the database because of is_valid() but the page refreshes and form goes blank again... Here is the code
models.py
from django.db import models
class MainForm(models.Model):
text = models.CharField(max_length=100)
email = models.EmailField(blank=False)
name = models.CharField(max_length=100,blank=False)
def __unicode__(self):
return self.email
forms.py
from django import forms
from .models import MainForm,new_model
class form_MainForm(forms.ModelForm):
class Meta:
model = MainForm
fields = '__all__'
views.py
def view_MainForm(request):
context = {
"form": form_MainForm
}
if request.method == 'POST' :
form_instance = form_MainForm(request.POST or None)
if form_instance.is_valid():
form_instance.save()
return render(request,'done.html',{'text':form_instance.cleaned_data.get('email')})
return render(request,'main_form.html',context)
template ->main_form.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Main Form</title>
</head>
<body>
<form method="post" action=".">
{% csrf_token %}
{{ form.as_p }}
<input type="submit" value="Submit">
</form>
</body>
</html>
Your view function is wrong - you have to pass the invalid form to the context to get the error messages, ie:
def view_MainForm(request):
if request.method == 'POST' :
form_instance = form_MainForm(request.POST)
if form_instance.is_valid():
form_instance.save()
# here you should redirect to avoid
# re-submission of the form on page reload
# cf https://en.wikipedia.org/wiki/Post/Redirect/Get
return render(request,'done.html',{'text':form_instance.cleaned_data.get('email')})
else:
form_instance = form_MainForm()
context = {"form": form_instance}
return render(request,'main_form.html',context)
check this link to render error in your form https://docs.djangoproject.com/en/1.10/topics/forms/#rendering-form-error-messages , this will give an idea like why you are not able to save data.
when you are sending back the form it should be
context = {"form": form_MainForm(request.POST)} , this will display the form submitted values

Categories

Resources