populate bootstrap dropdown on the base.html using django - python

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})

Related

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 use Django template filter in for loop?

How can I filter specific field of a model in template while using for loop.
code:
{% for news in news_list|position:3 %}
<img class="d-block w-100 rounded slideimage" style="height:415px" src="{{news.image_link}}" alt="First slide">
<h1 class="mb-2">
{{news.title}}
</h1>
{% endfor %}
there is a 'position' field in news model,I want to get all the news that position equal 3.I tried
{% for news in news_list|position:3 %}
any friend can help?
You should not filter in your template. Templates should only be concerned with making thinks look nice, not about the content of the things it is rendering. Filtering belongs in the view, since the view is concerned with business logic.
You thus filter with:
def myview(request):
# …
news_list = News.objects.filter(position=3)
# …
context = {
'news_list' : news_list
}
return render(request, 'my_template.html', context)

Django display a page title based on a variable stored in a view

I’m a bit stuck on how to display the titles for 2 pages that list articles of different categories using the same template. My article models have content, category (sport, politics, tech etc) and status. I want to display a page listing all sport articles and a page listing politics and I want to use the same template. I have tried storing the title as a variable in the view but this doesn't work
Views.py
def sport_landing(request):
page_title = 'Sport'
cat_landing = Article.objects.filter(status='published', category='sport', published_date__lte=timezone.now()
).order_by('-published_date')
return render(request, "categorylanding.html", {'cat_landing': cat_landing}
Template
{% extends 'base.html' %}
{% load humanize %}
{% block content %}
<div class="row category-landing-title">
<div class="col-xs-12">
{% page_title %}
</div>
</div>
.
.
.
Is this even the best way to do this?
You need to pass the variable to the context :
def sport_landing(request):
page_title = 'Sport'
cat_landing = Article.objects.filter(status='published', category='sport', published_date__lte=timezone.now()
).order_by('-published_date')
return render(request, "categorylanding.html", {'cat_landing': cat_landing, 'page_title':page_title }
and use double braces { in the template ({% %} is used for template tags):
{{page_title}}
To answer about the whole pattern, you can avoid to repeat the code for each category by using a parameter inside the url pattern :
Add and adapt this line in the file urls.py, this will allow you to pass the category as a parameter to your view :
url(r'^category/(?P<category>\w+)', views.cat_landing) # i.e : mysite/category/sport
You need to declare a generic view like :
def cat_landing(request, category=None):
if category:
cat_landing = Article.objects.filter(status='published', category=category,
published_date__lte=timezone.now()
).order_by('-published_date')
return render(request, "categorylanding.html",
{'cat_landing': cat_landing, 'page_title':category.title() }
else:
return [...redirect to main menu... ]
Pass title as context
def sport_landing(request):
page_title = 'Sport'
cat_landing=Article.objects.filter(tatus='published',category='sport',published_date__lte=timezone.now()
).order_by('-published_date')
return render(request, "categorylanding.html", {'cat_landing': cat_landing,'page_title':page_title}
{% extends 'base.html' %}
{% load humanize %}
{% block content %}
<div class="row category-landing-title">
<div class="col-xs-12">
{{ page_title }}
</div>
</div>

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

Django: Named URLs / Same Template, Different Named URL

I have a webapp that lists all of my artists, albums and songs when the appropriate link is clicked. I make extensive use of generic views (object_list/detail) and named urls but I am coming across an annoyance. I have three templates that pretty much output the exact same html that look just like this:
{% extends "base.html" %}
{% block content %}
<div id="content">
<ul id="starts-with">
{% for starts_with in starts_with_list %}
<li>{{ starts_with|upper }}</li>
{% endfor %}
</ul>
<ul>
{% for song in songs_list %}
<li>{{ song.title }}</li>
{% endfor %}
</ul>
</div>
{% endblock content %}
My artist and album template look pretty much the same and I'd like to combine the three template's into one. The fact that my variables start with song can easily be changed to the default obj. It's my <ul id="starts-with"> named url I don't know how to correct. Obviously I want it to link to a specific album/artist/song using the named urls in my urls.py but I don't know how to make it context aware. Any suggestions?
urls.py:
urlpatterns = patterns('tlkmusic.apps.tlkmusic_base.views',
# (r'^$', index),
url(r'^artists/$', artist_list, name='artist_list'),
url(r'^artists/(?P<starts_with>\w)/$', artist_list, name='artist_list_x'),
url(r'^artist/(?P<artist_id>\d+)/$', artist_detail, name='artist_detail'),
url(r'^albums/$', album_list, name='album_list'),
url(r'^albums/(?P<starts_with>\w)/$', album_list, name='album_list_x'),
url(r'^album/(?P<album_id>\w)/$', album_detail, name='album_detail'),
url(r'^songs/$', song_list, name='song_list'),
url(r'^songs/(?P<starts_with>\w)/$', song_list, name='song_list_x'),
url(r'^song/(?P<song_id>\w)/$', song_detail, name='song_detail'),
)
You could define url patterns for a generic object_type instead of individually for artists, albums and songs:
urlpatterns = patterns('tlkmusic.apps.tlkmusic_base.views',
# (r'^$', index),
url(r'^(?P<object_type>\w+)/$', music_object_list, name='music_object_list'),
url(r'^(?P<object_type>\w+)/(?P<starts_with>\w)/$', music_object_list, name='music_object_list_x'),
url(r'^(?P<object_type>\w+)/(?P<object_id>\d+)/$', music_object_detail, name='music_object_detail'),
)
Then in your template, your url tag becomes
{% url music_object_list_x object_type starts_with %} *
You may find you only need one view, music_object_list. If you find you need different functions for each object type, then call the individual functions in music_object_list.
def music_object_list(request, object_type, starts_with=None):
if object_type == 'artists':
return artist_list(request, starts_with=starts_with)
elif object_type == 'albums':
return album_list(request, starts_with=starts_with)
...
If you are using django.views.generic.list_detail.object_list, then remember to add object_type to the extra_context dictionary. This will add object_type to the template context, allowing the url tag to work.
extra_context = {'object_type': 'songs', ...}
* This is the new url tag syntax for Django 1.2. For older versions you would use a comma.
{% url music_object_list_x object_type,starts_with %}
See the docs (Current, 1.1) for more information

Categories

Resources