get attribute name based on slug - django

I have a page listing articles based on categories.
The category is filtered from the slug in the url.
I want to display a tag in the template with the category name.
With get_context_data I am able to retrive the slug and use it as {{categoryslug}} But how do I get the name of the category given the slug?
Model.py
class Category(models.Model):
name = models.CharField(max_length=50,unique=True, blank=True)
slug = models.SlugField(max_length=100,unique=True, blank=True)
def __str__(self):
return self.name
class Article(models.Model):
title= models.CharField(max_length=40, blank=True)
category = models.ForeignKey('Category', on_delete= models.PROTECT, related_name="pcat", blank=True)
def __str__(self):
return self.title
View.py
class ListArticleView(ListView):
model = Article
context_object_name = "listcat"
template_name = "myapp/categories.html"
paginate_by = 5
def get_queryset(self):
return Article.objects.filter(category__slug=self.kwargs['cat_slug'])
def get_context_data(self, **kwargs):
context=super(ListArticleView,self).get_context_data(**kwargs)
context['categoryslug']=self.kwargs['cat_slug']
return context
URLS.py
path(('/<cat_slug>'), views.ListArticleView.as_view(), name='some_categories'))

Related

Filter in get_context_data and get_query_set not working

I have a listview where I'm trying to filter out products by category. Some products have a subcategory. When a product has a subcategory I want the listview to display them by subcategory.
Problem is: The listview works perfect for items with a subcategory, but does not work for items who do not have a subcategory. Where am I taking a wrong turn here?
Models:
class Category(models.Model):
category_name = models.CharField(max_length=200)
sub_category = models.CharField(max_length=200,blank=True,null=True)
category_picture = ResizedImageField(upload_to='category/', null=True, blank=True)
category_info = models.TextField(blank=True, null=True)
category_video = models.CharField(max_length=250,blank=True, null=True)
def __str__(self):
if self.sub_category is None:
return self.category_name
else:
return f" {self.sub_category}"
class Meta:
ordering = ['category_name']
class Bottle(models.Model):
category_name = models.ForeignKey('Category', on_delete=models.SET_NULL,null=True,blank=True)
brand = models.ForeignKey('Brand', on_delete=models.CASCADE)
bottle_name = models.CharField(max_length=255)
bottle_info = models.TextField()
bottle_tasting_notes = models.TextField()
bottle_barcode = models.IntegerField()
bottle_image = ResizedImageField(upload_to='bottles/',null=True, blank=True)
bottle_shop_link = models.CharField(max_length=250, null=True, blank=True)
def __str__(self):
return f"{self.brand}, {self.bottle_name}"
class Meta:
ordering = ['bottle_name']
View:
class BottlesByCategoryView(ListView):
model = Bottle
context_object_name = 'bottles'
#Filter bij subcategory in the category model. If no subcategory exists, load by category_name
def get_queryset(self):
if Bottle.objects.filter(category_name__sub_category=self.kwargs['category']) is None:
return Bottle.objects.filter(category_name__category_name=self.kwargs['category'])
else:
return Bottle.objects.filter(category_name__sub_category=self.kwargs['category'])
def get_context_data(self, **kwargs):
context = super(BottlesByCategoryView, self).get_context_data(**kwargs)
if Bottle.objects.filter(category_name__sub_category=self.kwargs['category']) is None:
context['category_info'] = Category.objects.filter(category_name=self.kwargs['category'])
else:
context['category_info'] = Category.objects.filter(sub_category=self.kwargs['category'])
return context
URLS:
path('BottlesByCategory/<str:category>/',BottlesByCategoryView.as_view(template_name='academy/bottlesByCat_list.html'),name='bottlesByCat_list'),
Can i not use if statements in the get_context_data and get_query_set?

Render all products that relate to one of subcategories of one category, in category page

I had a question. I am creating an ecommerce website in django. There, I have categories and subcategories. When I enter to subcategory page, I able to render all products that relate to this subcategory. But, when I wanted to render all product that relate on one parent category, I am having troubles. So, I have some subcategories in one category. In that category page, I want to render all products that relate to one of subcategories of this category. Can you help me please?
models.py
class Category(models.Model):
parent = models.ForeignKey('self', related_name='children', on_delete=models.CASCADE, blank=True, null=True)
title = models.CharField(max_length=255)
slug = models.SlugField(max_length=255)
image = models.ImageField(null=True, blank=True, verbose_name="Изображение")
ordering = models.IntegerField(default=0)
is_featured = models.BooleanField(default=False)
class Meta:
verbose_name_plural = 'Categories'
ordering = ('ordering',)
def __str__(self):
if self.parent is not None:
return f"{self.parent}/{self.title}"
return self.title
#property
def imageURL(self):
try:
url = self.image.url
except:
url = ''
return url
def get_absolute_url(self):
return '/%s/' % (self.slug)
class Product(models.Model):
category = models.ForeignKey(Category, related_name='products', on_delete=models.CASCADE)
parent = models.ForeignKey('self', related_name='variants', on_delete=models.CASCADE, blank=True, null=True)
name = models.CharField(max_length=200, verbose_name="Название продукта")
price = models.IntegerField(verbose_name="Цена")
slug = models.SlugField(max_length=255)
description = models.CharField(max_length=5000,blank=True, verbose_name="Описание:")
image = models.ImageField(null=True, blank=True, verbose_name="Изображение")
novinki = models.BooleanField(default=False, verbose_name="Новинки")
popularnye = models.BooleanField(default=False, verbose_name="Популарные")
def __str__(self):
return self.name
class Meta:
verbose_name = 'Продукты'
verbose_name_plural = "Продукты"
#property
def imageURL(self):
try:
url = self.image.url
except:
url = ''
return url
views.py
def category_detail(request, slug):
data = cartData(request)
cartItems = data['cartItems']
order = data['order']
items = data['items']
categories_for_menu = Category.objects.filter(parent=None)[:3]
categories = Category.objects.filter(parent=None)
category = get_object_or_404(Category, slug=slug)
**products_all = Product.objects.filter(category.parent==category)**
print(products_all)
products = category.products.all()
context = {'items' : items, 'order' : order, 'cartItems' : cartItems, 'products':products, 'category':category, 'categories':categories,'categories_for_menu':categories_for_menu,'products_all':products_all}
return render(request, "store/categories.html", context)
Here I want to save all products that relate the category in products_all. Looking forward to your help!
class Category(models.Model):
# ...
root = models.ForeignKey('self', on_delete=models.CASCADE)
# ...
def save(self, *args, **kwargs):
self.root = self.parent.root if self.parent else self
# I didn't debug it. Maybe it has some bug.
super(Category, self).save(*args, **kwargs)
# query
Product.objects.filter(category__root=(...))
I don't agree this answer:
products = Product.objects.filter(Q(category = category)|Q(category__parent = category))
When your category is more than 2 depth, it will be wrong.
You can do it using Q function:
from django.db.models import Q
category = get_object_or_404(Category, slug=slug)
products = Product.objects.filter(Q(category = category)|Q(category__parent = category))

How to change the queryset returned based on the URL

I am trying to make an educational site and have made a category system. There is a URL for each category and I need change the queryset returned based on the URL I am on. For example if I am on "localhost:8000/posts/category/3", I want my queryset returned to be:
Post.objects.filter(category=3).order_by('-date_posted')
And so one depending on the URL.
I don't quite know where to start from for this.
The class based view that returns the queryset:
class CatPostListView(ListView):
model = Post
template_name = 'blog/science.html' #This is when you click a profile in a post, it takes you to his posts only
context_object_name = 'posts'
paginate_by = 15
def get_queryset(self):
return Post.objects.filter(category=2).order_by('-date_posted')
urls.py (Contains only the part necessary):
urlpatterns = [
path('post/category/<int:pk>/', CatPostListView.as_view(), name='category')
]
And just in case models.py:
class Category(models.Model):
name = models.CharField(max_length=200)
slug = models.SlugField()
parent = models.ForeignKey('self', blank=True, null=True, related_name='children', on_delete=models.SET_NULL)
class Meta:
# enforcing that there can not be two categories under a parent with same slug
# __str__ method elaborated later in post. use __unicode__ in place of
# __str__ if you are using python 2
unique_together = ('slug', 'parent',)
verbose_name_plural = "categories"
def __str__(self):
return self.name
class Post(models.Model):
title = models.CharField(max_length=100)
content = models.TextField()
category = models.ForeignKey('Category', null=True, blank=True, on_delete=models.SET_NULL)
display = models.TextField(max_length=250)
date_posted = models.DateTimeField(default=timezone.now)#DON'T USE () HERE Just auto_now_ will show the date of the current day
author = models.ForeignKey(User, on_delete=models.CASCADE)#No () #This deletes the posts when the user is deleted
def __str__(self):
return self.title
def get_absolute_url(self):
return reverse('post-detail', kwargs={'pk': self.pk})
If I use the view i posted here that will not quite work. I need a method to take the pk from the url and put it in views.
You can get the value from the URL:
return Post.objects.filter(category=self.kwargs['pk']).order_by('-date_posted')

Django foreign key and one-to-many relationship

I'm trying to build a basic ecommerce website, as a mean to learning django. I'm trying to build my models, so that there is a Category, a Product and Product Image class to store my data in. This is my models.py:
class Category(models.Model):
name = models.CharField(max_length=200, db_index=True)
slug = models.SlugField(max_length=200, db_index=True, unique=True)
class Meta:
ordering = ('name', )
verbose_name = 'category'
verbose_name_plural = 'categories'
def __str__(self):
return self.name
def get_absolute_url(self):
return reverse('products:product_list_by_category', args=[self.slug])
class Product(models.Model):
category = models.ForeignKey(Category, related_name='products')
name = models.CharField(max_length=200, db_index=True)
slug = models.SlugField(max_length=200, db_index=True)
description = models.TextField(blank=True)
price = models.DecimalField(max_digits=10, decimal_places=2)
stock = models.PositiveIntegerField()
available = models.BooleanField(default=True)
updated_at = models.DateTimeField(auto_now=True)
class Meta:
ordering = ('name', )
index_together = (('id', 'slug'), )
def __str__(self):
return self.name
def get_absolute_url(self):
return reverse('products:product_detail', args=[self.id, self.slug])
class ProductImage(models.Model):
property = models.ForeignKey('Product', related_name='images', on_delete=models.CASCADE)
image = models.ImageField(upload_to='products')
And this is my views.py:
def product_list(request, category_slug=None):
category = None
categories = Category.objects.all()
products = Product.objects.filter(available=True)
product_img = Product.images.all()
if category_slug:
category = get_object_or_404(Category, slug=category_slug)
products = products.filter(category=category)
return render(request, 'products/list.html', {'category': category, 'categories': categories, 'products': products, 'product_img': product_img})
I've seen similar post here on stack overflow, and have tried to do the same thing, but I still get the following error: AttributeError: 'ReverseManyToOneDescriptor' object has no attribute 'all'
Where am I going wrong here?

How to call ManyToManyField in class based view

I'm just bricked here; I don’t know what is going on?
I want to do simple blog.
So as you can see below I defined ManyToManyField and set category as a many to many field and then related the name posts.
Earlier I used a function based view and I simply called it a related name like this:
example
def catdetail(request, slug):
code here
and
posts = category.pots.all() /////and this gave me all posts related to this cateogry,
But in the class based view in the category detail view I cannot call this category field from Post; all my tries are unsuccessful; errors like, category has not defined, category has no object, category or post and thing similar to that which you already know…
So my question is: how can I call this related name in Detail view in category?
Here are my models and views.py:
class Category(models.Model):
title = models.CharField(max_length=20)
slug = models.SlugField(unique=True)
def __unicode__(self):
return self.title
def get_absolute_url(self):
return reverse("category_detail", kwargs={"slug": self.slug})
class Tag(models.Model):
title = models.CharField(max_length=100)
slug = models.SlugField(unique=True)
def __unicode__(self):
return self.title
class Post(models.Model):
user = models.ForeignKey(settings.AUTH_USER_MODEL)
category = models.ManyToManyField(Category, related_name='posts')
title = models.CharField(max_length=100, blank=False)
slug = models.SlugField(unique=True)
body = models.TextField()
image = models.ImageField(upload_to='project/uploads/')
tag = models.ManyToManyField(Tag, related_name='tag_post')
date = models.DateTimeField(auto_now_add=True, auto_now=False)
date_mod = models.DateTimeField(auto_now=True, auto_now_add=False)
publis = models.BooleanField(default=True)
def __unicode__(self):
return self.title
def get_absolute_url(self):
return reverse("post_detail", kwargs={"slug": self.slug})
and views.py.
Can you tell me how to call the category field and related name here in views?
class CategoryDetail(DetailView):
model = Category
template_name = "cat_detail.html"
def get_context_data(self, *args, **kwargs):
context = super(CategoryDetail, self).get_context_data(*args, **kwargs)
context['cat'] = get_object_or_404(Category, slug=self.kwargs.get("slug"))
return context
Some help?
def get_context_data(self, *args, **kwargs):
context = super(CategoryDetail, self).get_context_data(*args, **kwargs)
posts = Category.objects.get(id=1).posts.all()
for post in posts:
post.category
print post
context['cat'] = get_object_or_404(Category, slug=self.kwargs.get("slug"))
return context
i now have this, but i got all posts whether be on that category or not