How to have Django templates display slugs - python

Hi guys i am new to django...i been watching youtube videos and reading books on Django but am still struggling with templates. I am working on a ecommerce project and i would love a bit of help with templates. So i want my template to display a list of categories as links on a sidebar. I have defined a slug field in my category models and i have managed to map a url...but i am still not getting a list of categories on my index page sidebar.
This is my url pattern and this is working perfect. When i click 127.0.0.1.000/food it's working (food is a category)
path('<slug:category_slug>/', views.category, name='category'),
the view function
def category(request, category_slug):
"""Defines category views"""
categories= get_object_or_404(Category, slug= category_slug)
context = {'categories': categories}
return render(request, "categories_list.html", context)
This is the categories_list.html template that i need help with
<h3> Shop by Category </h3>
{% if category in categories %}
<li>
{{category.name}}
</li>
{% endif %}
My wish is to have the categories displayed on the sidebar of my index page as links. I have used {% include 'category_list.html' %} on my index page template, and its only displaying the Shop by Category heading instead of the categories when i am on the index page. I have tried the for loop in my template but if didn't work, it kept on saying category object not iterable...so i ended up using the if statement. Any help will be appreciated

get_object_or_404() method returns single instance or None if it is not found.
You can't iterate that way on object.
Try next
View
def category(request, slug):
"""Defines category views."""
return render(request, 'categories_list.html', {'category': get_object_or_404(Category, slug=slug)})
Template
{{ category.slug }}

Related

Is it possible to customize individual pages associated with the same template? dynamic URL django

I am working on a blog website and have set up dynamic URLs in Django for each blog article. Is it possible to change the layout of paragraphs and images of specific pages so that there are slight differences between each page?
Yes it is possible to have different layout for the same template rendered in Django. You can pass some variable in context to achieve this goal like this :
views.py
def detail(request, id):
object = Model.objects.get(pk=id)
context = {'layout': f"layout_for_{id}"}
return render(request, 'template.html', context)
template.html
{% if layout == 'layout_for_2' %}
Layout for 2 here
{% endif %}
You can add more condition as you want, but it can become hard to for too much {% if %} block.

How can I lists all the products according to their foreign key?

I am working on my first eshop website using django framework and I got stuck on a problem.
I have created a general model for different kinds of products (like laptops, books etc.). Each product that is added to the website can be found by on its foreign key that links that product to a specific category.
The question is how can I display on laptops.html only the products that have the foreign key which points to the right category? Like, to display only the products from laptops category.
Thank you very much for your time!
EDIT:
in urls:
urlpatterns=[
path('', views.HomePage.as_view(), name='home'),
path('ComputerScience/', views.ComputerScience.as_view(), name='computer_science'),
path('category/<int:category_pk>/list-products/', views.CompSProd.as_view(), name='category_products_list')]
In computerscience.html I render all the cateogries.
Here in views.py I have the two controllers, first for categories and second for laptops for instance.
views.py
class ComputerScience(ListView):
model = ComputerScienceCategory
template_name = "computer_science.html"
context_object_name = "category"
class CompSProd(ListView):
model = ComputerScienceProducts
template_name = "laptops.html"
context_object_name = "products"
def get_queryset(self):
queryset = super().get_queryset()
# If you wish to still keep the view only for specific category use below line
category = get_object_or_404(ComputerScienceCategory, pk=self.kwargs.get('category_pk'))
queryset = queryset.filter(category=category)
return queryset
Here I have the template where I want to display all categories.
computer_science.html
<div class="computerScienceContent" id="slide">
{% for cat in category %}
<a href="{% url 'category_products_list' category.pk %} " id="aBar">
<div>
<h4 class="cSh">{{ cat.name }}</h4>
<img src="{{ cat.img.url }}" alt="image" class="img">
</div>
</a>
{% endfor %}
Here is laptops html, where I'd like to have the whole products displayed.
laptops.html
{% extends 'index.html' %}
{% block title %}
<title>Laptops</title>
{% endblock %}
{% block cont2 %}
{% endblock %}
My main goal is that to have a page (computerscience.html) where I have displayed a list with all available categories and when you click on one category, to redirect you to another page where you have listed all the products that belongs to that category.
This is the error that has been thrown to me:
Reverse for 'category_products_list' with arguments '('',)' not found. 1 pattern(s) tried: ['category/(?P<category_pk>[0-9]+)/list\\-products/$']
You should override get_queryset to filter your objects. Also as you are writing a view for a specific instance of category you would end up writing a lot of views, also when a new category would be added this would be very tedious you should use one view for all categories instead. Try this:
from django.shortcuts import get_object_or_404
class CompSProd(ListView):
model = ComputerScienceProducts
template_name = "laptops.html"
context_object_name = "products"
def get_queryset(self):
queryset = super().get_queryset()
category = get_object_or_404(ComputerScienceCategory, pk=self.kwargs.get('category_pk')) # Assuming category_pk will be passed in url
# If you wish to still keep the view only for specific category use below line
# category = get_object_or_404(ComputerScienceCategory, pk=<pk-of-category-here>)
queryset = queryset.filter(category=category)
return queryset
To pass the categories primary key in the url you need to do something as follows:
In your urls.py:
urlpatterns = [
...
path('category/<int:category_pk>/list-products/', views.CompSProd.as_view(), name='category_products_list'),
...
]
Now in the page where you display all categories:
{% for cat in category %}
<a href="{% url 'category_products_list' cat.pk %}" id="aBar">
<div>
<h4 class="cSh">{{ cat.name }}</h4>
<img src="{{ cat.img.url }}" alt="image" class="img">
</div>
</a>
{% endfor %}
Also you write id="aBar" but this line is in a loop meaning you would end up with multiple same ids you should use a class instead.

How to display the children of a wagtail page

My requirement sounds simple, but I am struggling to make it work
In my wagtail project I have a BlogListingPage which has many child pages. I am trying to create a list of the children in a web page. Here is my code:
models.py
class BlogListingPage(Page):
...
def get_context(self, request, *args, **kwargs):
context = super().get_context(request, *args, **kwargs)
context['blog_pages'] = BlogDetailPage.objects.live().child_of(self)
return context
class BlogDetailPage(Page):
...
blog_listing = models.ForeignKey(BlogListingPage,
on_delete=models.PROTECT,
blank=True,
null=True,)
views.py
def blog(request):
url = 'blog/blog_listing_page.html'
context = {'data': BlogListingPage.objects.all()}
return render(request, url, context)
blog_listing_page.html
{% block content %}
{% for blog_listing in data %}
{% for post in blog_listing.blogdetailpage %}
{{ post.blog_title }}
{% endfor %}
{% endfor %}
{% endblock content %}
I am lost in the fog of the django/wagtail pages/objects/querysets/all()/specific
Can someone please lead me to clear blue water?
A couple of suggestions regarding your approach:
Having a foreign key from BlogDetailPage to BlogListingPage is not the Wagtail way to organise parent-child relationships. All Page objects already have a tree hierarchy and you should rely on that, otherwise you lose all the built-in tree handling provided by Wagtail.
You should use the parent/subpage rules to specify how page types can be related to each other. In you case it would look something like:
class BlogListingPage(Page):
subpage_types = ['myapp.BlogDetailPage']
class BlogDetailPage(Page):
parent_page_types = ['myapp.BlogListingPage']
The get_context() method on BlogListingPage only runs when Wagtail is serving that specific page in a view. It doesn't run when you're iterating over these pages in your blog view. In order to access the children there, you need to do something like this:
{% for blog_listing in data %}
{% for post in blog_listing.get_children.live %}
{{ post.blog_title }}
{% endfor %}
{% endfor %}
i.e., you need to use the get_children() method on the page to obtain it's children. live() further filters this to exclude unpublished pages. Note that this will only work if the blog posts are children (in the Wagtail page tree sense) of the listing page. specific() isn't important here if you're only using the post URL and title - it is relevant if you want to display fields that are part of your model rather than the base Page model.

populate bootstrap dropdown on the base.html using django

Im using django 1.9 and python 3.5 which i'm both really new too, and i'm having trouble populating a bootstrap dropdown which is located in the base.html.
So far i have this:
base.html:
<li class="dropdown">
<a href="#" class="dropdown-toggle" data-toggle="dropdown">Events
<b class="caret"></b></a>
<ul class="dropdown-menu">
{% if categories %}
{% for cat in category %}
<li><a href="{% url 'categories' pk=cat.pk %}">
{{ cat.name }}</a></li>
{% endfor %}
{% else %}
There are no categories present.
{% endif %}
</ul>
</li>
views.py:
def categories(request, pk):
category = Category.objects.get(pk=pk)
return render(request, 'categories.html', {'category': category})
urls.py:
url(r'^categories/(?P<pk>\d+)/$', views.categories, name='categories'),
So i want the drop down to display the available categories from the database and then when i click on one it will obviously load up the categories.html displaying the relevant category.
any help would be much appreciated.
Edit: sorry i forgot to say the problem i am having.
Im not getting the drop down populated, and is only giving me the "there is no categories present"
There are a couple of issues here:
Firstly, you don't have any context in your view called categories, yet you're checking for them in your template. Your view function is called 'categories', which might be creating some confusion for you. However, this is not context that is accessible to your view. It's just a function.
Secondly, you're not getting a list of categories (which you could iterate as you are in your template) in your view, you're getting a single category with:
category = Category.objects.get(pk=pk)
# using the get() method means you're requesting a single object
So you need to do something more like:
categories = Category.objects.all()
# here, we're getting a QuerySet (list of objects), rather a single object
Then add the categories to your context. So your view would end up looking like this:
def categories(request, pk):
categories = Category.objects.all()
return render(request, 'categories.html', {'categories': categories})
Also, you'll need to change your iterator to iterate over categories, not category:
{% for cat in categories %}
<li><a href="{% url 'categories' pk=cat.pk %}">
{{ cat.name }}</a></li>
{% endfor %}
So, "categories" variable will never give you "true", while you do not define it, and add it to template context.
Do this in your python code
def categories(request, pk):
categories = Category.objects.all()
return render(request, 'categories.html', {'categories': categories})

Django Dynamic Links NoReverseMatch

I'm trying to dynamically create pages based on the movie title of the link clicked. I keep getting an error though when I try to set the link though "u'app_name' is not a registered namespace"
my index.html looks like this and it works when the link isn't set:
{% for movie in movies %}
<li data-id="{{ movie.id }}"><span class="title">{{ movie.title }}</span> ({{ movie.year }}) - {{ movie.genre}}<a class="delete">X</a></li>
{% endfor %}
my views.py for the dynamic url pages look like this:
def detail(request, movie_title):
return render(request, 'detail.html', {'movie_object':movie_object})
my urls.py for this specific section looks like this:
url(r'(?P<movie_title>[_\w+])$', views.detail, name='detail')
The problem was in
return render(request, 'detail.html', {'movie_object':movie_object})
movie_object did not correspond with any of the fields for the movie object

Categories

Resources