I am carrying out a project for an online grocery store. I want to have a ‘View Ratings’ button beneath each item within the store that takes users to a ratings.html page where they can view previous ratings and also submit their own using a form. However, I am running into the following error when I attempt to click the ‘View Ratings’ button beneath an item. Also, if i managed to get this fixed, is there a way I can make it so I can view the ratings in my admin area. Any help appreciated!
Reverse for 'ratings' with arguments '('',)' not found. 1 pattern(s) tried: ['ratings/(?P<item_id>[0-9]+)/\\Z']
Request Method: GET
Request URL: http://localhost:8000/ratings/1/
Django Version: 4.1.7
Exception Type: NoReverseMatch
Exception Value:
Reverse for 'ratings' with arguments '('',)' not found. 1 pattern(s) tried: ['ratings/(?P<item_id>[0-9]+)/\\Z']
Exception Location: C:\Users\Sammc\OneDrive - Ulster University\Desktop\django_project\venv\lib\site-packages\django\urls\resolvers.py, line 828, in _reverse_with_prefix
Raised during: customer.views.Ratings
Python Executable: C:\Users\Sammc\OneDrive - Ulster University\Desktop\django_project\venv\Scripts\python.exe
Python Version: 3.10.7
Python Path:
['C:\\Users\\Sammc\\OneDrive - Ulster '
'University\\Desktop\\django_project\\groc',
'C:\\Python310\\python310.zip',
'C:\\Python310\\DLLs',
'C:\\Python310\\lib',
'C:\\Python310',
'C:\\Users\\Sammc\\OneDrive - Ulster '
'University\\Desktop\\django_project\\venv',
'C:\\Users\\Sammc\\OneDrive - Ulster '
'University\\Desktop\\django_project\\venv\\lib\\site-packages']
Server time: Thu, 04 May 2023 14:54:43 +0000
Error during template rendering
In template C:\Users\Sammc\OneDrive - Ulster University\Desktop\django_project\groc\customer\templates\customer\ratings.html, error at line 15
Reverse for 'ratings' with arguments '('',)' not found. 1 pattern(s) tried: ['ratings/(?P<item_id>[0-9]+)/\\Z']
5 <div class="container">
6 <div class="row justify-content-center mt-3">
7 <div class="col-md-6 col-sm-12 text-center">
8 <h1>Item Ratings</h1>
9 <h3>{{ item.name }}</h3>
10 </div>
11 </div>
12
13 <div class="row justify-content-center mt-5 mb-5">
14 <div class="col-md-8 col-sm-12 text-center">
15 <form method="GET" action="{% url 'ratings' item_id %}">
16 <div class="form-group">
17 <label for="name">Name:</label>
18 <input class="form-control" name="name" type="text" required>
19 </div>
20 <div class="form-group">
21 <label for="comment">Comment:</label>
22 <textarea class="form-control" name="comment" rows="4" required></textarea>
23 </div>
24 <div class="form-group">
25 <label for="rating">Rating:</label>
I am not sure where the issue is occuring so ill supply the code for all relveant files (groceries.html, ratings.html, models.py, urls.py, views.py, forms.py):
groceries.html:
{% block content %}
<p>
<button style="font-size: 16px;" onclick="increaseTextSize()">+A</button>
<button style="font-size: 16px;" onclick="decreaseTextSize()">-A</button>
</p>
<div class="container">
<div class="row justify-content-center mt-3">
<div class="col-md-6 col-sm-12 text-center">
<h1>Groceries</h1>
</div>
</div>
<div class="row justify-content-center mt-5 mb-5">
<div class="col-md-8 col-sm-12 text-center">
<form method="GET" action="{% url 'groceries-search' %}">
<div class="md-form mt-0 active-cyan-2">
<input class="form-control" name="q" type="text" placeholder="Search" aria-label="Search" value="{{ request.GET.q }}">
</div>
</form>
</div>
</div>
<div class="row justify-content-center mb-5">
{% for item in groc_items %}
<div class="col-md-4 col-sm-12 text-center mb-5">
<img class="rounded" src="{{ item.image.url }}" width=350 height="300">
<h5 class="mt-3">{{ item.name }}</h5>
<p>Price: £{{ item.price }}</p>
<p>{{ item.description }}</p>
<a href="{% url 'ratings' item.id %}">View Ratings</a>
</div>
{% endfor %}
</div>
</div>
{% endblock content %}
ratings.html:
{% block content %}
<div class="container">
<div class="row justify-content-center mt-3">
<div class="col-md-6 col-sm-12 text-center">
<h1>Item Ratings</h1>
<h3>{{ item.name }}</h3>
</div>
</div>
<div class="row justify-content-center mt-5 mb-5">
<div class="col-md-8 col-sm-12 text-center">
<form method="GET" action="{% url 'ratings' item_id %}">
<div class="form-group">
<label for="name">Name:</label>
<input class="form-control" name="name" type="text" required>
</div>
<div class="form-group">
<label for="comment">Comment:</label>
<textarea class="form-control" name="comment" rows="4" required></textarea>
</div>
<div class="form-group">
<label for="rating">Rating:</label>
<select class="form-control" name="rating" required>
<option value="" disabled selected>Select rating</option>
<option value="5">5 - Excellent</option>
<option value="4">4 - Very Good</option>
<option value="3">3 - Good</option>
<option value="2">2 - Fair</option>
<option value="1">1 - Poor</option>
</select>
</div>
<button type="submit" class="btn btn-primary">Submit</button>
</form>
</div>
</div>
<div class="row justify-content-center mb-5">
{% if ratings %}
<div class="col-md-8 col-sm-12 text-center">
<h3>Reviews</h3>
<hr>
{% for rating in ratings %}
<div class="card mb-3">
<div class="card-body">
<h5 class="card-title">{{ rating.name }} - {{ rating.get_rating_display }}</h5>
<p class="card-text">{{ rating.comment }}</p>
</div>
</div>
{% endfor %}
</div>
{% endif %}
</div>
</div>
{% endblock content %}
models.py:
from django.core.validators import MinValueValidator, MaxValueValidator
class ShopItem(models.Model):
name = models.CharField(max_length=100)
description = models.TextField()
image = models.ImageField(upload_to='item_images/')
price = models.DecimalField(max_digits=5, decimal_places=2)
category = models.ManyToManyField('Category', related_name='item')
def __str__(self):
return self.name
class Category(models.Model):
name = models.CharField(max_length=100)
def __str__(self):
return self.name
class OrderModel(models.Model):
created_on = models.DateTimeField(auto_now_add=True)
price = models.DecimalField(max_digits=7, decimal_places=2)
items = models.ManyToManyField(
'ShopItem', related_name='order', blank=True)
name = models.CharField(max_length=50, blank=True)
email = models.CharField(max_length=50, blank=True)
address = models.CharField(max_length=50, blank=True)
city = models.CharField(max_length=50, blank=True)
county = models.CharField(max_length=15, blank=True)
postcode = models.CharField(max_length=7, null=True)
is_paid = models.BooleanField(default=False)
out_for_delivery = models.BooleanField(default=False)
def __str__(self):
return f'Order: {self.created_on.strftime("%b %d %I: %M %p")}'
class Rating(models.Model):
item = models.ForeignKey('ShopItem', on_delete=models.CASCADE, related_name='ratings')
name = models.CharField(max_length=100)
comment = models.TextField()
rating = models.IntegerField(validators=[MinValueValidator(0), MaxValueValidator(5)])
created_at = models.DateTimeField(auto_now_add=True)
def __str__(self):
return f"{self.name}'s rating for {self.item.name}"
urls.py
The `urlpatterns` list routes URLs to views. For more information please see:
https://docs.djangoproject.com/en/4.1/topics/http/urls/
Examples:
Function views
1. Add an import: from my_app import views
2. Add a URL to urlpatterns: path('', views.home, name='home')
Class-based views
1. Add an import: from other_app.views import Home
2. Add a URL to urlpatterns: path('', Home.as_view(), name='home')
Including another URLconf
1. Import the include() function: from django.urls import include, path
2. Add a URL to urlpatterns: path('blog/', include('blog.urls'))
"""
from django.contrib import admin
from django.urls import path, include
from django.conf import settings
from django.conf.urls.static import static
from customer.views import Index, About, Order, OrderConfirmation, OrderPayConfirmation, Groceries, GroceriesSearch, Ratings
urlpatterns = [
path('admin/', admin.site.urls),
path('accounts/', include('allauth.urls')),
path('shop/', include('shop.urls')),
path('', Index.as_view(), name='index'),
path('about/', About.as_view(), name='about'),
path('ratings/<int:item_id>/', Ratings.as_view(), name='ratings'),
path('groceries/', Groceries.as_view(), name='groceries'),
path('groceries/search', GroceriesSearch.as_view(), name='groceries-search'),
path('order/', Order.as_view(), name='order'),
path('order-confirmation/<int:pk>', OrderConfirmation.as_view(), name='order-confirmation'),
path('payment-confirmation/', OrderPayConfirmation.as_view(), name='order-pay-confirmation'),
] + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
views.py:
from urllib import request
from django.http import HttpResponse
from django.shortcuts import render, redirect, get_object_or_404
from django.views import View
from django.db.models import Q
from .models import ShopItem, OrderModel, Rating
from django.core.mail import send_mail
from django.contrib.auth.mixins import UserPassesTestMixin, LoginRequiredMixin
from django.utils.timezone import datetime
from customer.forms import RatingForm
class Index(View):
def get(self, request, *args, **kwargs):
return render(request, 'customer/index.html')
class About(View):
def get(self, request, *args, **kwargs):
return render(request, 'customer/about.html')
class Order(View):
def get(self, request, *args, **kwargs):
# get every item from each category
foods = ShopItem.objects.filter(category__name__contains='Food')
meats = ShopItem.objects.filter(category__name__contains='Meat')
fruits = ShopItem.objects.filter(category__name__contains='Fruit')
cleaning = ShopItem.objects.filter(category__name__contains='Cleaning')
bakery = ShopItem.objects.filter(category__name__contains='Bakery')
# pass into context
context = {
'foods': foods,
'meats': meats,
'fruits': fruits,
'cleaning': cleaning,
'bakery': bakery,
}
# render the template
return render(request, 'customer/order.html', context)
def post(self, request, *args, **kwargs):
name = request.POST.get('name')
email = request.POST.get('email')
address = request.POST.get('address')
city = request.POST.get('city')
county = request.POST.get('county')
postcode = request.POST.get('postcode')
order_items = {
'items': []
}
items = request.POST.getlist('items[]')
for item in items:
print(item)
shop_item = ShopItem.objects.get(pk=int(item))
item_data = {
'id': shop_item.pk,
'name': shop_item.name,
'price': shop_item.price
}
order_items['items'].append(item_data)
price = 0
item_ids = []
for item in order_items['items']:
price += item['price']
item_ids.append(item['id'])
order = OrderModel.objects.create(
price=price,
name=name,
email=email,
address=address,
city=city,
county=county,
postcode=postcode
)
order.items.add(*item_ids)
# After everything is done, send confirmation email to user
body = ('Thanks for your order! Your order is being prepared and will be delivered as soon as possible!\n'
f'Total price: {price}\n'
'Thanks for your order!')
send_mail(
'Thanks For Your Order!',
body,
'example@example.com',
[email],
fail_silently=False
)
context = {
'items': order_items['items'],
'price': price
}
return redirect('order-confirmation', pk=order.pk)
class OrderConfirmation(View):
def get(self, request, pk, *args, **kwargs):
order = OrderModel.objects.get(pk=pk)
context = {
'pk': order.pk,
'items': order.items,
'price': order.price,
}
return render(request, 'customer/order_confirmation.html', context)
def post(self, request, pk, *args, **kwargs):
data = json.loads(request.body)
if data['isPaid']:
order = OrderModel.objects.get(pk=pk)
order.is_paid = True
order.save()
return redirect('payment-confirmation')
class OrderPayConfirmation(View):
def get(self, request, *args, **kwargs):
return render(request, 'customer/order_pay_confirmation.html')
def change_text_size(request, size):
response = HttpResponse()
response.set_cookie('text_size', size)
return response
class Groceries(View):
def get(self, request, *args, **kwargs):
groc_items = ShopItem.objects.all()
context = {
'groc_items': groc_items
}
return render(request, 'customer/groceries.html', context)
class GroceriesSearch(View):
def get(self, request, *args, **kwargs):
query = self.request.GET.get("q")
groc_items = ShopItem.objects.filter(
Q(name__icontains=query) |
Q(price__icontains=query) |
Q(description__icontains=query)
)
context = {
'groc_items': groc_items
}
return render(request, 'customer/groceries.html', context)
class Ratings(View):
def get(self, request, *args, **kwargs):
return render(request, 'customer/ratings.html')
def ratings(request, item_id):
item = get_object_or_404(ShopItem, pk=item_id)
ratings = item.ratings.all().order_by('-created_at')
form = RatingForm()
if request.method == 'POST':
form = RatingForm(request.POST)
if form.is_valid():
rating = form.save(commit=False)
rating.item = item
rating.save()
return redirect('ratings', item_id=item.id)
context = {
'item': item,
'ratings': ratings,
'form': form
}
return render(request, 'ratings.html', context)
forms.py:
from .models import Rating
class RatingForm(forms.ModelForm):
class Meta:
model = Rating
fields = ['name', 'comment', 'rating']