I am working on a Python project while following a book to create an online shop website, I have created the models, views and urls for the app named 'Shop' the project overall is called 'My shop'. Whenever I try to type in the 'product list' URL I am returned with the following error:
Reverse for 'product_list_by_category' with arguments '(3, 'accessories')' not found.
The expected result is the list.html page to be shown which includes all products because no category has been chosen in the URL.
I have followed the code in the book exactly and have tried it multiple times yet the error still appears.
I have two categories currently and two games, the games are Minecraft and GTA 5, the categories are Accessories and Games.
Below is the code from all of the relevant files, if any more are needed let me know.
Shop views.py
from django.shortcuts import render, get_object_or_404
from .models import Category, Product
# Create your views here.
#Product List view
def product_list(request, category_slug=None):
#Setting current category to none
category = None
#Retrieiving categories
categories = Category.objects.all()
#Getting all unfiltered products that are available
products = Product.objects.filter(available=True)
#Filtering products based on category
if category_slug:
#Get category
category = get_object_or_404(Category, slug=category_slug)
#Get products from category
products = products.filter(category=category)
#Return view with context (Product and category)
return render(request,
'shop/product/list.html',
{'category': category,
'categories': categories,
'products': products})
#Individual product view
def product_detail(request, id, slug):
#Return product
product = get_object_or_404(Product,
id=id,
slug=slug,
available=True)
#Return view with context (Product)
return render(request,
'shop/product/detail.html',
{'product': product})
Shop urls.py
from django.urls import path
from . import views
#Create URLS here
app_name = 'shop'
urlpatterns = [
path('', views.product_list, name='product_list'),
path('<slug:category_slug>/', views.product_list, name='product_list_by_category'),
path('<int:id>/<slug:slug>/', views.product_detail, name='product_detail'),
]
Shop models.py
from django.db import models
from django.urls import reverse
# Create your models here.
#Create catalog model
class Category(models.Model):
#Name of category
name = models.CharField(max_length=200, db_index=True)
#Slug Name (Link)
slug = models.SlugField(max_length=200, unique=True)
#Meta data
class Meta:
#Alphabetical ordering by category name
ordering = ('name',)
#Name for one category
verbose_name = 'category'
#Name for multiple categories
verbose_name_plural = 'categories'
#Returning the name
def get_absolute_url(self):
#Return reverse of product
return reverse('shop:product_list_by_category', args=[self.id, self.slug])
def __str__(self):
return self.name
#Create Product Model
class Product(models.Model):
#Create relation (Foreign Key) to Category model
category = models.ForeignKey(Category, related_name='products', on_delete=models.CASCADE)
"""
db_index ensures that name and slug are used as a COMPOSITE PRIMARY key
Name of product
"""
name = models.CharField(max_length=200, db_index=True)
#Slug Name (Link)
slug = models.SlugField(max_length=200, db_index=True)
#Product image (Saved in static image folder)
image = models.ImageField(upload_to='products/%Y/%m/%d', blank=True)
#Description of product
description = models.TextField()
#Price of product
price = models.DecimalField(max_digits=10, decimal_places=2)
#Product availability
available = models.BooleanField(default=True)
#Product Creation date
created = models.DateTimeField(auto_now_add=True)
#Product last updated
updated = models.DateTimeField(auto_now=True)
#Meta data
class Meta:
#Order alphabetically by name
ordering = ('name',)
#Product index is created with id and slug
index_together = (('id', 'slug'),)
def get_absolute_url(self):
#Return reverse of product
return reverse('shop:product_detail', args=[self.id, self.slug])
#Returning product name
def __str__(self):
return self.name
Project urls.py
from django.conf import settings
from django.conf.urls.static import static
"""MyShop URL Configuration
The `urlpatterns` list routes URLs to views. For more information please see:
https://docs.djangoproject.com/en/3.2/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
urlpatterns = [
path('admin/', admin.site.urls),
path('', include('shop.urls', namespace='shop')),
]
if settings.DEBUG:
urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
I have three HTML pages: List, Detail and Base
list.html
<!--Loading content from base.html and loading static files-->
{% extends "shop/base.html" %}
{% load static %}
<!--Title block-->
{% block title %}
{% if category %}{{ category.name }}{% else %}Products{% endif %}
{% endblock %}
<!--Content block (Main stuff)-->
{% block content %}
<div id="sidebar">
<h3>Categories</h3>
<ul>
<li {% if not category%}class="selected" {% endif %}>
<a href='{% url "shop:product_list" %}'>All</a>
</li>
{% for c in categories %}
<li {% if category.slug == c.slug %} class="selected"{% endif %}>
{{ c.name }}
</li>
{% endfor %}
</ul>
</div>
<div id="main" class="product-list">
<h1>{% if category %}{{ category.name }}{% else %}Products{% endif %}</h1>
{% for product in products %}
<div class="item">
<a href="{{ product.get_absolute_url }}">
<img src='{% if product.image %}{{ product.image.url }}{% else %}{% static "img/no_image.png" %}{% endif %}'/>
</a>
{{ product.name }}
<br>
£{{ product.price }}
</div>
{% endfor %}
</div>
{% endblock %}
detail.html currently has no code and base.html is definitely not the cause.
Any help is greatly appreciated!
Your get absolute url in the Category model is calling the product_list_by_category url only which only accepts one arg(parameter).
You can change
path('<slug:category_slug>/', views.product_list, name='product_list_by_category')
to
path('<int:id>/<slug:category_slug>/', views.product_list, name='product_list_by_category')
Related
I have data being stored in a Django model, and I want to display that data in my HTML file. What is the easiest way that I could do this? I am familiar with [this][1] question, but it does not help me because it is not very detailed and does not have a definite answer. Can someone please help me? My code is down below.
Django Model:
class userdetails(models.Model):
donations = models.IntegerField(blank=True, null = True,)
points = models.IntegerField(blank=True, null = True,)
user = models.ForeignKey(
settings.AUTH_USER_MODEL,
on_delete=models.CASCADE,
blank=True,
null=True,
)
HTML where I want to display data from the model:
<div class="box">
<span class="value"> </span>
<span class="parameter">Points</span>
</div>
This is my view:
#login_required(login_url='/login/')
def dashboard(request):
id = request.user.id
data= userdetails.objects.get(id=id)
return render(request,'dashboard.html',{'data':data})
The error I keep getting:
DoesNotExist at /dashboard/
userdetails matching query does not exist.
Has something to do with data= userdetails.objects.get(id=id) in my views.
you need to create a view to retreive the data you need from your model :
views.py :
from .models import userdetails
from django.shortcuts import render
def get_data(request):
my_data = userdetails.objects.all() #for all the records
one_data = userdetails.objects.get(pk=1) # 1 will return the first item change it depending on the data you want
context={
'my_data':my_data,
'one_data':one_data,
}
return render(request, 'get_data.html', context)
add the the view to urls.py :
url.py :
from .views import get_data
urlpatterns = [
path('get_data/', get_data, name='get_data'),
]
create get_data.html in the templates folder :
get_data.html : for the list
{% block content %}
{% for x in my_data %}
{{x.name }}
{% endfor %}
{% endblock content %}
for the item :
{% block content %}
{{one_data}}
{% endblock content %}
the best practice is to create a list view and a detail view so if you dont know how tell me and i will show you
You need to add a function to the views.py file and render the HTML file to a URL that should be there in Url Patterns.
For example:
This is a sample model:
class C(models.Model):
name = models.CharField(max_length=125, null=True)
phone = models.CharField(max_length=125, null=True)
date_created = models.DateTimeField(auto_now_add=True, null=True)
def __str__(self):
return self.name
This is my views.py
from .models import *
def home(request):
c = C.objects.all()
return render(request, "<app_name>/index.html", {'c': c})
This is my urls.py
from . import views
urlpatterns = [
path('home/',views.home),
]
This is my part of HTML file where I will show the data
{% block content %}
<h2>{{c.name}}</h2>
{% endblock content %}
I'm trying to display information from my model Administrateur into my HTML Template login.html, but nothing is happening.
This my Model:
from django.db import models
class Administrateur(models.Model):
nom = models.CharField(max_length=30)
prenom = models.CharField(max_length=30)
mdp = models.CharField(max_length=30)
mail = models.CharField(max_length=30)
def _str_(self):
return self.name
This is my view:
def Pseudo(request):
administrateurs = Administrateur.objects.all()
context={'administrateurs':administrateurs}
return render(request, "login.html",context)
This is my HTML:
{% extends "base.html" %}
{% load static %}
{% block content %}
{% for n in administrateurs %}
{{ n.nom }}
{{ n.prenom }}
{% endfor %}
{% endblock %}
I'm not sure what to do with urls.py
Do this step if you have not done it yet:
Add this to the file urls.py in the project's base directory:
from django.urls import include
urlpatterns = [
# your urls
path('login/', include('appname.urls')), #change appname to your app's name
]
now in your app make a new file called urls.py and add this to the file:
from django.urls import path
from .views import Pseudo
urlpatterns = [
path('', Pseudo, name="pseudo"),
]
then check when you go to login page (in url bar) what happens
I'm new in django and generally in programming. And now I write my first project - that will be my personal blog, it's almost done except one feature:
I have list of categories shown on the page in the right panel.
1) The question is how can I sort/filter my posts by these categories? I mean I want to click on one of these categories in the right panel and to see the posts where that category is mentioned (post may have several categories).
I've tried a lot of combinations, which found on stackoverflow, but I didn't do that before so can't understand how to realize that feature in my project.
models.py
class Category(models.Model):
title = models.CharField(max_length=20)
def __str__(self):
return self.title
class Post(models.Model):
title = models.CharField(max_length=100)
overview = models.TextField()
timestamp = models.DateTimeField(auto_now_add=True)
content = HTMLField('Content')
author = models.ForeignKey(Author, on_delete=models.CASCADE)
thumbnail = models.ImageField()
categories = models.ManyToManyField(Category)
featured = models.BooleanField()
previous_post = models.ForeignKey('self', related_name='previous', on_delete=models.SET_NULL, blank=True, null=True)
next_post = models.ForeignKey('self', related_name='next', on_delete=models.SET_NULL, blank=True, null=True)
def __str__(self):
return self.title
views.py
def filter_by_category(request):
post_list = Post.objects.filter(categories=)
context = {
'post_list': post_list
}
return render(request, 'post_by_category.html', context)
urls.py
urlpatterns = [
path('admin/', admin.site.urls),
path('', index),
path('blog/', blog, name='post-list'),
path('search/', search, name='search'),
path('blog/filter_by_category/', filter_by_category, name='filter_by_category'),
path('subscribe/', email_list_signup, name='subscribe'),
path('create/', post_create, name='post-create'),
path('post/<id>/', post, name='post-detail'),
path('post/<id>/update/', post_update, name='post-update'),
path('post/<id>/delete/', post_delete, name='post-delete'),
path('tinymce/', include('tinymce.urls')),
path('accounts/', include('allauth.urls')),
sidebar.html
<div class="widget categories">
<header>
<h3 class="h6">Categories</h3>
</header>
{% for cat in category_count %}
<div class="item d-flex justify-content-between">
{{ cat.categories__title }}<span>{{ cat.categories__title__count }}</span></div>
{% endfor %}
</div>
Given code doesn't work, I know that the problem in views.py. I'm absolutely messed up how to write it correctly.
Help me please to solve this problem.
UPDATED:
It's solved, thanks a lot to Landcross.
I was close in some moments to that decision, but messed up. Thank you!
First, expand your url definition like so:
path('blog/filter_by_category/<str:category>', filter_by_category, name='filter_by_category'),
Now you are defining a variable named 'category' (which is a string, hence the str) in the url which can be passed to the view:
def filter_by_category(request, category):
post_list = Post.objects.filter(categories__title=category)
context = {
'post_list': post_list
}
return render(request, 'post_by_category.html', context)
And change your template so it adds the parameter to the url:
<div class="widget categories">
<header>
<h3 class="h6">Categories</h3>
</header>
{% for cat in category_count %}
<div class="item d-flex justify-content-between">
{{ cat.categories__title }}<span>{{ cat.categories__title__count }}</span></div>
{% endfor %}
</div>
You can also change the url to int and change your template to use the category ID instead of title if that's something you like more or works better for you (e.g. if category titles can contain duplicates).
I have a books app using a UUID with a listview of all books and detailview of individual books. I keep getting the following error message:
NoReverseMatch at /books/
Reverse for 'book_detail' with arguments '('/books/71fcfae7-bf2d-41b0-abc8-c6773930a44c',)' not found. 1 pattern(s) tried: ['books/(?P<pk>[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12})$']
Here is the models.py file:
# books/models.py
import uuid
from django.db import models
from django.urls import reverse
class Book(models.Model):
id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
title = models.CharField(max_length=200)
author = models.CharField(max_length=200)
price = models.DecimalField(max_digits=6, decimal_places=2)
def __str__(self):
return self.title
def get_absolute_url(self):
return reverse('book_detail', args=[str(self.id)])
The urls.py file where I'm using to convert the id from the model to a uuid.
# books/urls.py
from django.urls import path
from .views import BookListView, BookDetailView
urlpatterns = [
path('', BookListView.as_view(), name='book_list'),
path('<uuid:pk>', BookDetailView.as_view(), name='book_detail'),
]
The top-level urls.py file looks like this and adds a books/ route.
# urls.py
from django.contrib import admin
from django.urls import path, include
urlpatterns = [
path('admin/', admin.site.urls),
path('books/', include('books.urls')),
The views.py file:
from django.views.generic import ListView, DetailView
from .models import Book
class BookListView(ListView):
model = Book
context_object_name = 'book_list'
template_name = 'books/book_list.html'
class BookDetailView(DetailView):
model = Book
context_object_name = 'book'
template_name = 'books/book_detail.html'
And the relevant templates file.
<!-- templates/book_detail.html -->
{% extends '_base.html' %}
{% block content %}
{% for book in book_list %}
<div>
<h2>{{ book.title }}</h2>
</div>
{% endfor %}
{% endblock content %}
I believe I'm implementing this correctly but the URL is not liking my UUID. What is amiss?
The problem is not "adding uuid". The problem is that you are doing the URL reversal twice: once in get_absolute_url and once in the {% url %} tag. Use one or the other, not both.
Either:
{{ book.title }}
Or:
{{ book.title }}
I'm new to Django and have been stuck on this for a few days now. Hoping to find some help here. I've searched stackoverflow and read through the django docs but haven't been able to grasp this. I'm using Django 1.6.2 and Python 2.7.
I'm setting up a simple news app in which article has a ManyToMany relationship with category. I'm running into trouble trying to display articles from a specific category. I have the index working displaying all articles and also the single page view is working e.g. clicking on article title from index brings you to the article itself. Once in the article I am displaying the article category. Up to here all is well. When I try to link the category and display an index for all posts in that category I get a NoReverseMatch for the url 'category-archive'.
Should I do this in a view like I'm trying or would the Manager work better? Open to all suggestions and answers. Like I said I'm new so would like to know best practice. Here is my code and thank you in advance for dealing with a noobie.
models.py
from django.db import models
from tinymce import models as tinymce_models
class ArticleManager(models.Manager):
def all(self):
return super(ArticleManager, self).filter(active=True)
class Category(models.Model):
title = models.CharField(max_length=65)
slug = models.SlugField()
def __unicode__(self, ):
return self.title
class Article(models.Model):
title = models.CharField(max_length=65)
slug = models.SlugField()
description = models.CharField(max_length=165)
content = tinymce_models.HTMLField()
categories = models.ManyToManyField(Category)
image = models.ImageField(upload_to='article/images')
active = models.BooleanField(default=False)
timestamp = models.DateTimeField(auto_now_add=True, auto_now=False)
updated = models.DateTimeField(auto_now=True, auto_now_add=False)
objects = ArticleManager()
def __unicode__(self, ):
return self.title
class Meta:
ordering = ['-timestamp',]
views.py
from django.http import HttpResponse, HttpResponseRedirect
from django.shortcuts import render_to_response, RequestContext, get_object_or_404
from .models import Article, Category
def all_articles(request):
articles = Article.objects.all()
return render_to_response('news/all.html', locals(), context_instance=RequestContext(request))
def single_article(request, slug):
article = get_object_or_404(Article, slug=slug)
return render_to_response('news/single.html', locals(), context_instance=RequestContext(request))
def category_archive(request, slug):
articles = Article.objects.filter(category=category)
categories = Category.objects.all()
category = get_object_or_404(Category, slug=slug)
return render_to_response('news/category.html', locals(), context_instance=RequestContext(request))
single.html - for single article view
{% extends 'base.html' %}
{% block content %}
<h1>{{ article.title }}</h1>
<img src='{{ MEDIA_URL }}{{ article.image }}' class="article-image img-responsive"/>
<p>{{ article.content|safe }}</p>
<p class='small'>
**this next line gets an error for the url 'category-archive'**
{% for category in article.categories.all %}Category: <a href='{% url "category-archive" %}{{ category.slug }}'>{{ category }}</a>{% endfor %}</p>
{% endblock %}
category.html - display all articles in specific category
{% extends 'base.html' %}
{% block content %}
{% for article in articles %}
<h1><a href='{% url "articles" %}{{ article.slug }}'>{{ article }}</a></h1>
<a href='{% url "articles" %}{{ article.slug }}'><img src='{{ MEDIA_URL }}{{ article.image }}' class="img-responsive"/></a>
{{ article.description }}
{% if forloop.counter|divisibleby:4 %}
<hr/>
<div class='row'>
{% endif %}
{% endfor %}
</div>
{% endblock %}
urls.py - project urls
from django.conf.urls import patterns, include, url
from django.conf import settings
from filebrowser.sites import site
from django.contrib import admin
admin.autodiscover()
urlpatterns = patterns('',
(r'^tinymce/', include('tinymce.urls')),
(r'^admin/filebrowser/', include(site.urls)),
(r'^grappelli/', include('grappelli.urls')),
(r'^static/(?P<path>.*)$', 'django.views.static.serve',{
'document_root': settings.STATIC_ROOT
}),
(r'^media/(?P<path>.*)$', 'django.views.static.serve',{
'document_root': settings.MEDIA_ROOT
}),
url(r'^admin/', include(admin.site.urls)),
url(r'^$', 'dl.views.home', name='home'),
(r'^news/', include('news.urls')),
(r'^guides/', include('guides.urls')),
)
urls.py - news urls
from django.conf import settings
from django.conf.urls import patterns, include, url
urlpatterns = patterns('news.views',
url(r'^$', 'all_articles', name='articles'),
url(r'^(?P<slug>[-\w]+)/$', 'single_article'),
**This next one is giving me the problem I suspect - should be url to category with articles**
url(r'^chive/(?P<slug>[-\w]+)/?', 'category_archive', name='category-archive'),
)
I would have post it as a comment but i don't have the reputation.
I think that the thing is that the URL Dispatcher expects the category-archive to also get the slug. so you should change the URL in the template to:
{% url "category-archive" category.slug %}
hope this helps!