Guys i am new to Django but i am bit clued up on a few things. I need help with urls. So in my models.py i defined category, subcategory and product models and all these models fields have got a slugfield. I have also managed to define the index page url and its working but after the index page i want when the user clicks the category link he will be able to see subcategories that are under categories, and when the user click on subcategories he will able to see products in the subcategory. So for example i would love to create an url like www.127.0000/electronics , electronics is the category and under electronics the user will be able to see subcategories like TV's , Microwaves...when the user click on TV's link the url will be www.127.0000/electronics/tvs and at this page the user will see the products. This is my models.py
class Category(models.Model):
name= models.CharField(max_length=100)
slug= models.SlugField(max_length= 100, unique= True)
class Meta:
ordering = ('name',)
verbose_name= 'category'
verbose_name_plural= 'categories'
def __str__(self):
return self.name
class SubCategory (models.Model):
name = models.CharField(max_length= 200)
slug = models.SlugField (max_length= 200, unique= True)
category= models.ForeignKey(Category, on_delete= models.CASCADE)
class Meta:
ordering = ('name',)
verbose_name= "SubCategory"
verbose_name_plural= 'SubCategories'
def __str__(self):
return self.name
class Product(models.Model):
name = models.CharField(max_length=250)
slug = models.SlugField(max_length=250)
price = models.DecimalField(max_digits=10 , decimal_places=2)
image = models.ImageField(max_length=20, blank= True)
subcategory = models.ForeignKey(SubCategory, on_delete= models.CASCADE)
class Meta:
ordering = ('name',)
verbose_name= 'product'
verbose_name_plural = 'products'
def __str__(self):
return self.name
and this is my app urls
urlpatterns= [
path('', views.index, name='Index'),
path('<slug:category_slug>/', views.category, name= 'Categories' )
views.py file
def index (request):
""""Defines homepage"""
return render (request, 'index.html')
def category (request, category_slug):
"""Defines categories slug"""
categories= get_object_or_404(Category, slug=category_slug)
context= {'categories': categories}
return render (request, 'category.html', context}
this is my category html gile
{% extends 'base.html' %}
{% block content %}
<p>
<ul>
{% for category in categories %}
<li> {{category}} </li>
{% empty %}
<li> No Category has been added yet</li>
{% endfor %}
</ul>
</p>
{% endblock content %}
Could you please guide in the right direction so that when i click on www.127.0000/clothes i see the subcategories in clothes and the i click on and subcategories the url will change to maybe 127.000/clothes/men clothes and display the products in men clothes subcategory.
Related
I am developing an ecommerce website with Django. In my home page displayed product cards as you see in the below image.
This product image in each card I take from my Product model (image field). When I hover over this image on the home page, the image is changing to another image. That is for I need another image, and I want to take the next image (display when I hover over) from my Product_images model. But I don't know how to do that.
urls.py
from django.urls import path
from . import views
from django.conf.urls.static import static
urlpatterns =
path('', views.home_page, name='amd-home'),
path('product/<int:id>/', views.product_detail, name='product-detail'),
path('about/', views.about, name='amd-about'),
]
views.py
from django.shortcuts import render, get_object_or_404
from django.views.generic import ListView, DetailView
from django.http import HttpResponse
from .models import Product, Product_image, Product_details
def home_page(request):
products = Product.objects.all()
images = Product_image.objects.all()
context = {'products':products, 'images':images}
return render(request, 'product/home.html', context)
models.py
from django.db import models
from django.utils import timezone
from django.contrib.auth.models import User
class Category(models.Model):
name = models.CharField(max_length=200)
parent_id = models.IntegerField(default=0)
description = models.TextField()
image = models.ImageField(upload_to='uploads/')
def __str__(self):
return f'{self.name}'
class Brand(models.Model):
name = models.CharField(max_length=200)
description = models.CharField(max_length=400)
image = models.ImageField(upload_to='uploads/')
def __str__(self):
return f'{self.name}'
class Product(models.Model):
title = models.CharField(max_length=200)
image = models.ImageField(upload_to='uploads/', blank=True, null=True)
sku = models.CharField(max_length=200)
price = models.IntegerField(default=0)
price_old = models.IntegerField(default=0)
description = models.TextField()
status = models.BooleanField(default=False)
date_posted = models.DateTimeField(auto_now_add=True)
internal_storage = models.CharField(max_length=50, blank=True, null=True, default=None)
ram = models.CharField(max_length=50, blank=True, null=True, default=None)
user = models.ForeignKey(User, on_delete=models.CASCADE)
brand = models.ForeignKey(Brand, on_delete=models.CASCADE)
category = models.ForeignKey(Category, on_delete=models.CASCADE)
def __str__(self):
return f'{self.title}, {self.description}'
class Product_image(models.Model):
image = models.ImageField(upload_to='uploads/')
product = models.ForeignKey(Product, on_delete=models.CASCADE)
def __str__(self):
return f'{self.product.title} image'
home.html
my template file is a very large file, so I only insert the element where I get an image from the Product model (this code word fine), but I don't know how to write code to take images from my Product_image model.
{% for product in products %}
<img alt="" src="{{ product.image.url }}">
{% endfor %}
First, in your model you can give a related_name field like :
class Product_image(models.Model):
image = models.ImageField(upload_to='uploads/')
product = models.ForeignKey(Product, on_delete=models.CASCADE, related_name="product_images)
def __str__(self):
return f'{self.product.title} image'
Then you can access the product's images in template like:
{% for product in products %}
{% for image in product.product_images.all %}
<img alt="" src="{{ image.image.url }}">
{% endfor %}
{% endfor %}
PS: You dont have to return all Product_image quesryset from the view
Expanding on the answer, if you want to order the images there are different approaches you can take:
Method1:
class Product_image(models.Model):
image = models.ImageField(upload_to='uploads/')
product = models.ForeignKey(Product, on_delete=models.CASCADE, related_name="product_images)
time_created = models.DateTimeField(null=True, blank=True)
def __str__(self):
return f'{self.product.title} image'
class Meta:
ordering = ['time_created']
This will order the query set from first created to last . If you don't want to add a time created field you can also choose to order by id.
Method2:
Add a property to your Product model:
class Product:
....
#property
def sorted_image_set(self):
return self.product_images.order_by('time_created')
Then you can access this property from the template
{% for image in product.sorted_image_set %}
Method 3 :
Creating a custom template tag to support order_by in template
#register.filter
def order_by(queryset, args):
args = [x.strip() for x in args.split(',')]
return queryset.order_by(*args)
Then you can do :
{% for image in product.product_images|order_by:"time_created" %}
After the list has been ordered you can access it just by the array indexes like for example images[0] or images[1]
change src in your HTML
{% for product in products %}
<a href="{% url 'product-detail' product.id %}"><img alt="" src="/media/uploads/{{
product.image }}"></a>
{% endfor %}
I have assumed that you have MEDIA_URL=/media/ in your settings. Change this in src if you have different MEDIA_URL
I have a following models.py for my Django blog, I made a following views.py to pass the value of the slug for my URL parameter.
However I am struggling to create a model in views to get other data(person & description) from Category class.
I have tried some patterns by myself but can not pass them to HTML. (always Error or not showing)
Can you please give me some idea of how to solve this.
models.py
class Category(models.Model):
person = models.CharField(max_length=20)
description = models.TextField()
slug = models.SlugField()
def __str__(self):
return self.person
views.py
def blog_category(request, category):
posts = Post.objects.filter(categories__slug__contains=category).order_by("-created_on").distinct()
context = {"category": category, "posts": posts}
return render(request, "blog_category.html", context)
HTML(Localhost:8000/slug)
{{ person }}
{{ description }}
this is full code of my models.py
class Category(models.Model):
person = models.CharField(max_length=20)
description = models.TextField()
slug = models.SlugField()
def __str__(self):
return self.person
class Recommender(models.Model):
recommender_name = models.CharField(max_length=20)
slug = models.SlugField()
def __str__(self):
return self.recommender_name
class Post(models.Model):
book_title = models.CharField(max_length=255)
author = models.CharField(max_length=255)
book_link = models.CharField(max_length=255)
recommenders = models.ForeignKey("Recommender", on_delete=models.CASCADE,)
source = models.TextField()
source_link = models.CharField(max_length=255)
created_on = models.DateTimeField(auto_now_add=True)
last_modified = models.DateTimeField(auto_now=True)
categories = models.ManyToManyField("Category", related_name="posts")
slug = models.SlugField()
def __str__(self):
return self.book_title
posts = Post.objects.filter(categories__slug__contains=category).order_by("-created_on").distinct()
Is going to return a queryset. It can have more than one instance of the model class (since you are using filter). In your context you are sending this queryset as posts to your templates.
So in your HTML you can use something like this. You need to use a for loop since there can be more than one item in posts.
{% for post in posts %}
{% for category in post.categories.all %}
{{ category.person }}
{{ category.description }}
{% endfor %}
{% endfor %}
I would look at this example.
Namely, if you render the template like it is shown in the example, you should be able to do
{{ category.person }} {{ category.description }}
am working on a Django project where showing the details of post and amount
here is my models.py of post
class Loader_post(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE ,related_name="Loader")
pick_up_station = models.CharField(max_length=150)
destination_station = models.CharField(max_length=150)
sender_name = models.CharField(max_length=150)
phone_number = PhoneNumberField(null=False, blank=False, unique=True)
receiver_name = models.CharField(max_length=150)
def __str__(self):
return self.user.username
def get_absolute_url(self):
return reverse("Loader:my_job", kwargs={"pk": self.pk})
this is my second models which I inherit Loader post
class price(models.Model):
my_post = models.ForeignKey(Loader_post, related_name='prices',on_delete=models.CASCADE,
null=True, default='')
user = models.ForeignKey(get_user_model(), on_delete=models.CASCADE, null=True, default='')
driver_price = models.CharField(max_length=150, null=True)
driver_name = models.CharField(max_length=150, null=True)
approved_price = models.BooleanField(default=False)
status = models.BooleanField(default=False)
def get_absolute_url(self):
return reverse("Driver:Driverview")
def __str__(self):
return self.driver_price
this is the view.py of both list and details view
class offer_view(ListView, SelectRelatedMixin):
context_object_name = 'offern'
model = Loader_post
template_name = "offer.html"
def get_queryset(self):
qs = Loader_post.objects.filter(user=self.request.user)
return qs
class offer_view_detail(DetailView):
context_object_name = 'offernew'
model = Loader_post
template_name = "offer_detail.html"
here is my HTML page of list view ...when someone clicks on it it shows the detail of next post
offer.html
{% for my in offern %}
{{my.sender_name}} {% endfor %}
and when someone clicks on its route to the detail page .. but it shows template doesn't exist
this is my detail page ie. offer_details.hml
<p>{{offernew.sender_name}}</p>
<p>{{offernew.receiver_name}}</p>
{% for x in offernew.prices.all %}
<p>
<p>{{x.driver_name}}</p>
</p>
and this is urls.py
path('offerdetail/<int:pk>', views.offer_view_detail.as_view(),name="offerdetail"),
path('offer/', views.offer_view.as_view(), name="offer"),
Following on from comments,
In you ListView,
{{my.sender_name}}
here, the url specified is not defined in your urls.py, that's why it was showing no template doesn't exist, changing to this would solve this.
{{my.sender_name}}
Now, To show prices model in your DetailView, i would do something like this.
class offer_view_detail(DetailView):
context_object_name='offernew'
model = Loader_post
template_name = "offer_detail.html"
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context['price_model'] = self.object.prices.all()
return context
and In your Template
<p>{{offernew.sender_name}}</p>
<p>{{offernew.receiver_name}}</p>
{% for x in offernew.price_model %}
<p>{{x.driver_name}}</p>
{% endfor %}
Django Docs for DetailView
Hello i need a little help.
I create django cms.
I cant filter category in my post page.
I want, If I'm in the post page, I would like to see other post titles in this category.
Let me explain;
i have three post. post title is like this;
1-bmw3series
2-bmw5series
3-teslaroadster
1st and 2nd post in "bmw" category
3nd post in the "tesla" category
I want to show post categories in the left area. but I want to show post title of that post categorie.
For example, if I'm in bmw5series page, I want only see left category area to bmw3series and bmw5series post titles.
When I use the following code
{% for category in category %}
{% for article in category.get_article %}
<li><a title="{{ article.title }}" href="{% url 'article:detail' slug=article.slug %}">{{ article.title }}</a></li>
{% endfor %}
{% endfor %}
All post titles are listed... so if im inside bmw5series post just I need to see articles in bmw category....
How do I filter them?
views.py
from django.shortcuts import render, get_object_or_404
from .models import Article, Category
def index(request):
articles = Article.objects.all()
category = Category.objects.all()
context = {
"articles": articles,
"category": category,
}
return render(request, 'index.html', context)
def detail(request,slug):
article = get_object_or_404(Article, slug = slug)
category = Category.objects.all()
return render(request, "detail.html", {"article":article, "category":category,})
def category_detail(request,slug):
template = "category_detail.html"
category=get_object_or_404(Category,slug=slug)
article=Article.objects.filter(category=category)
context = {
'article' : article,
}
return render(request,template,context)
models.py
class Category(models.Model):
name = models.CharField(max_length=120, verbose_name="name")
parent = models.ForeignKey('self',blank=True, on_delete = models.CASCADE, null=True ,related_name='children')
slug = models.SlugField(unique=True, max_length=130)
def __str__(self):
return self.name
def get_article(self):
return Article.objects.filter(category=self)
class Article(models.Model):
author = models.ForeignKey("auth.User",on_delete = models.CASCADE, verbose_name="Yazar")
title = models.CharField(max_length = 120, verbose_name="Başlık")
category = models.ForeignKey('Category', on_delete=models.CASCADE, null=True, blank=True)
content = RichTextField(verbose_name="İçerik")
created_date = models.DateTimeField(auto_now_add=True, verbose_name="Oluşturma Tarihi")
image = models.ImageField(blank=True, null=True, verbose_name="Foto Ekle (.jpg .png)")
slug = models.SlugField(unique=True, max_length = 130)
def __str__(self):
return self.title
def get_unique_slug(self):
slug = slugify(self.title.replace("ı","i"))
unique_slug = slug
counter = 1
while Article.objects.filter(slug=unique_slug).exists():
unique_slug = '{}-{}'.format(slug, counter)
counter += 1
return unique_slug
def save(self, *args, **kwargs):
if not self.slug:
self.slug = self.get_unique_slug()
return super(Article, self).save(*args, **kwargs)
Try renaming this
{% for category in category %}
{% for article in category.get_article %}
To this
{% for cat in category %}
{% for article in cat.get_article %}
UPDATE
If I understand you correctly, whenever you display an article, you want to display the articles of that article's category. If that is correct then you have to change
category = Category.objects.all()
to
category = Category.objects.filter(article=article)
Working on an application were I have a One to Many relationship where I have many Products and a few particular products will be related to only one Website.
On my Home page is where I display my listed sites from my Website Model I would like to show products for when the user clicks on anyone of the slugs on my Homepage the are redirected to go into a product page ( another template ) where I have all of the objects related from my Product Model to that particular website to display only.
Here is a User flow of my situation
Homepage --> click on website ('/browse/website_slug') ---> Go To --> Product page (filled with only Product Objects from related clicked slug)
Models.py in my product_extend app
Product Model:
class Product(models.Model):
"""
The product structure for the application, the products we scrap from sites will model this and save directly into the tables.
"""
product_name = models.CharField(max_length=254, verbose_name=_('Name'), null=True, blank=True)
product_price = CurrencyField( verbose_name=_('Unit price') )
product_slug_url = models.URLField(max_length=200, null=True, blank=True)
product_category = models.CharField(max_length=254, blank=True, null=True)
product_img = models.ImageField('Product Image', upload_to='product_images', null=True, blank=True)
product_website_url = models.URLField(max_length=200, null=True, blank=True)
product_website_name = models.CharField(max_length=254, blank=True, null=True)
#For Admin Purposes, to keep track of new and old items in the database by administrative users
date_added = models.DateTimeField(auto_now_add=True, null=True, blank=True, verbose_name=_('Date added'))
last_modified = models.DateTimeField(auto_now=True, null=True, blank=True, verbose_name=_('Last modified') )
#For Admin Purposes, to make sure an item is active by administrative users
active = models.BooleanField(default=True, verbose_name=_('Active') )
# Foreign Key
website = models.ForeignKey(Website, null=True, related_name='website_to_product')
Website Model
class Website(models.Model):
name = models.CharField(max_length=254, blank=True, null=True, unique=True)
description = models.TextField(null=True, blank=True)
website_slug = models.SlugField(verbose_name=_('Website Slug'), unique=True)
site_logo = models.ImageField('Websites Logo', upload_to='website_logo_images', null=True, blank=True)
menswear = models.BooleanField(default=False, verbose_name=_('Menswear'))
womenswear = models.BooleanField(default=False, verbose_name=_('Womenswear'))
active = models.BooleanField(default=True, verbose_name=_('Active'))
Views in my product_extend app
view.py
class ProductView(ListView):
context_object_name = 'product_list'
template_name = 'product_extend/_productlist.html'
# queryset = ProductExtend.objects.filter(id=1)
model = Product
def get_context_data(self, **kwargs):
context = super(ProductView, self).get_context_data(**kwargs)
return context
class WebsiteView(ListView):
context_object_name = 'home'
template_name = 'homepage.html'
queryset = Website.objects.order_by('name')
model = Website
def get_context_data(self, **kwargs):
context = super(WebsiteView, self).get_context_data(**kwargs)
return context
Templates
Homepage.html
{% for object in home %}
<li class="page_tiles-home home-website-reveal">
<a href="browse/website_slug" data-title="{{object.name}}" data-description="{{object.description}}">
<img alt="{{object.name}}" src="{{MEDIA_URL}}{{object.site_logo}}" />
</a>
</li>
{% endfor %}
Product.html
{% for object in product_list %}
<li class="col n-4">
<figure class="rollover site">
<div class="scrap-likes"><span class="icon-heart"></span></div>
<img src="{{object.product_img}}" width="470" height="700">
<!-- <div class="scrap-from"> Scrapped from:<a class="scrap-site" target="_blank" href="{{object.product_website_url}}">{{object.product_website_name}}</a></div> -->
<div class="scrap-designer"> Scrapped from: <a class="scrap-site" target="_blank" href="{{object.product_website_url}}">{{object.product_website_name}}</a></div>
<div class="scrap-title">{{object.product_name }}, <span class="scrap-price">${{object.product_price}}</span></div>
<a class="scrap-buy" target="_blank" href="{{object.product_slug_url}}">View Item</a>
</figure>
</li>
{% endfor %}
Urls
my apps urls.py
urlpatterns = patterns('',
url(r"^$", WebsiteView.as_view(), name="home"),
url(r'^browse/', include('product_extend.urls')),
)
my apps product_extend urls.py
urlpatterns = patterns('',
??? No clue what to put ???
)
You can add this in product_extend urls.py:
urlpatterns = patterns('',
url(r'^(?P<website_slug>[\w]+)$', ProductView.as_view(), name='products_list'),
)
Then in ProductView override the get_queryset method to use the website_slug for filtering the queryset:
class ProductView(ListView):
context_object_name = 'product_list'
template_name = 'product_extend/_productlist.html'
# queryset = ProductExtend.objects.filter(id=1)
model = Product
def get_context_data(self, **kwargs):
context = super(ProductView, self).get_context_data(**kwargs)
return context
def get_queryset(self):
qs = super(ProductView, self).get_queryset()
return qs.filter(website__website_slug__exact=self.kwargs['website_slug'])
after reading twice, think what you want is:
url(r'^product/website/(?P<slug>)$', "your_view_to_peform_product_search_for_slug_website_here"),
and in your view "HTML"
href="product/website/{{ website.slug }}"
something like this...