I am trying to create a "restaurant rating" app on Django 3. I have set up the following models:
# Table storing the different restaurants
class Restaurant(models.Model):
restaurant_name = models.CharField(max_length=200, unique=True)
restaurant_address = models.CharField(max_length=200)
restaurant_street_number = models.CharField(max_length=10)
restaurant_city = models.CharField(max_length=200)
restaurant_cuisine_type = models.CharField(max_length=200)
def __str__(self):
return self.restaurant_name + ' - ' + self.restaurant_city
class UserReview(models.Model):
# Defining the possible grades
Grade_1 = 1
Grade_2 = 2
Grade_3 = 3
Grade_4 = 4
Grade_5 = 5
# All those grades will sit under Review_Grade to appear in choices
Review_Grade = (
(1, '1'),
(2, '2'),
(3, '3'),
(4, '4'),
(5, '5')
)
restaurant = models.ForeignKey(Restaurant, on_delete=models.CASCADE)
user_review_grade = models.IntegerField(default=None, choices=Review_Grade) # default=None pour eviter d'avoir un bouton vide sur ma template
user_review_comment = models.CharField(max_length=1500)
def get_absolute_url(self):
return reverse('restaurants:reviews', args=[self.id])
This is the form I am using:
# Form for user reviews per restaurant
class UserReviewForm(forms.ModelForm):
class Meta:
model = UserReview
# restaurant = forms.ModelChoiceField(queryset=Restaurant.objects.filter(pk=id))
fields = [
'restaurant',
'user_review_grade',
'user_review_comment'
]
widgets = {
'restaurant': forms.HiddenInput,
'user_review_grade': forms.RadioSelect,
'user_review_comment': forms.Textarea
}
labels = {
'user_review_grade': 'Chose a satisfaction level:',
'user_review_comment': 'And write your comments:'
}
Here are my URLs:
app_name = 'restaurants'
urlpatterns = [
# ex: /restaurants/
path('', views.index, name='index'),
# ex: /restaurants/15
path('<int:restaurant_id>/', views.details, name='details'),
# ex: /restaurants/test
path('<int:restaurant_id>/test', views.Test.as_view(), name='test')
]
Template:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>TEST</title>
</head>
<body>
<h1>Write a review for this restaurant:</h1>
<form method="post">
{% csrf_token %}
<input type="Hidden" name="restaurant" value="{{restaurant.restaurant_id}}">
{{ form.as_p }}
<br>
<input type="submit" value="Submit">
</form>
</body>
</html>
And finally my view:
# Test class to be renamed posts reviews as it should
class Test (CreateView):
template_name = 'restaurants/TEST.html'
form_class = UserReviewForm
# Get the initial information needed for the form to function: restaurant field
def get_initial(self, restaurant_id, *args, **kwargs):
initial = super(Test, self).get_initial(**kwargs)
initial['restaurant'] = 9
return initial()
# Post the data into the DB
def post(self, request, *args, **kwargs):
form = UserReviewForm(request.POST)
if form.is_valid():
review = form.save()
print(review) # Print so I cna see in cmd prompt that something posts as it should
review.save()
return render(request, 'restaurants/reviews.html', {'form': form})
I am facing an issue as when I define initial as an integrer (let's say 9 - as I put it to test if my form was actually posting) it posts with no issue the review in the DB for restaurant that holds id=9 However I can't get it to have the restaurant_id automatically populated depending on which restaurant's page we're visiting.
I tried the following as well as few other 'tricks' found here and there but nothing seems to do the cut...
# Test class to be renamed later IF it works...
class Test (CreateView):
template_name = 'restaurants/TEST.html'
form_class = UserReviewForm
# Get the initial information needed for the form to function: restaurant field
def get_initial(self, restaurant_id, *args, **kwargs):
restaurant = get_object_or_404(Restaurant, pk=restaurant_id)
initial = super(Test, self).get_initial(**kwargs)
initial['restaurant'] = self.request.restaurant.pk
return initial()
# Post the data into the DB
def post(self, request, *args, **kwargs):
form = UserReviewForm(request.POST)
if form.is_valid():
review = form.save()
print(review) # Print so I cna see in cmd prompt that something posts as it should
review.save()
return render(request, 'restaurants/reviews.html', {'form': form})
Any help would be appreciated to point me in the right direction :)
You can obtain the restaurant_id
in the url parameters with self.kwargs['restaurant_id']
. So you can ue:
class Test(CreateView):
def get_initial(self, *args, **kwargs):
initial = super(Test, self).get_initial(**kwargs)
return initial
# …
That being said, it is rather odd to store this in a form anyway. You can simply set this when the form is valid. So we define the form without a restaurant:
class UserReviewForm(forms.ModelForm):
class Meta:
model = UserReview
fields = [
'user_review_grade',
'user_review_comment'
]
widgets = {
'user_review_grade': forms.RadioSelect,
'user_review_comment': forms.Textarea
}
labels = {
'user_review_grade': 'Chose a satisfaction level:',
'user_review_comment': 'And write your comments:'
}
and in the CreateView
, we then set the restaurant
of that instance:
class Test(CreateView):
template_name = 'restaurants/TEST.html'
model = UserReview
form_class = UserReviewForm
success_url = …
def form_valid(self, form):
super().form_valid(form)
You here need to specify a success_url
to which it will redirect in case the submission is succesful. In case a POST is successful, you need to make a redirect to implement the Post/Redirect/Get pattern [wiki] .
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.