I am trying to display the most up to date posts on the homepage. I can query the most recents topics and display them on the homepage however I am having trouble querying the entries associated with that topic. my plan is to display the first 50 or so words of the entries.
Models.py
class Topic(models.Model):
"""A topic that is associated with a certain Category"""
category = models.ForeignKey(Category, on_delete=models.CASCADE)
text = models.CharField(max_length=200)
date_added = models.DateTimeField(auto_now_add=True)
class Meta:
verbose_name_plural = 'Topics'
def __str__(self):
"""Return string represtation of the model."""
return self.text
class Entry(models.Model):
"""A entry associated with a certain topic"""
topic = models.ForeignKey(Topic, on_delete=models.CASCADE)
text = models.TextField()
date_added = models.DateTimeField(auto_now_add=True)
class Meta:
verbose_name_plural = 'Entries'
def __str__(self):
"""Return string represtation of the model."""
return self.text[:50] + "..."
views.py index view:
def index(request):
"""The home page for the blogging website"""
topics = Topic.objects.order_by('-date_added')[:3]
entries = Entry.objects.filter(id__in=topics)
context = {'topics': topics, 'entries': entries}
return render(request, 'blogging_logs/index.html', context)
index.html
{% for entry in entries %}
<li>
{{ entry }}
</li>
{% empty %}
<li>
empty
</li>
{% endfor %}
{% for topic in topics %}
<li>
{{ topic }}
</li>
{% empty %}
<li>
empty
</li>
{% endfor %}
Thanks for the help in advance.
When querying the entries you should filter via topic_id field of the Entry not via id field. So you should do entries = Entry.objects.filter(topic_id__in=topics) in your index view.
Related
I'm having a problem with an html template not displaying model fields sent from a view in a context dictionary called content. This dictionary holds a nested dictionary like:
content = {'indredients': {recipe id1: QuerySet 1,
recipe id2: QuerySet 2, ... } }
In model.py:
class Ingredients(models.Model):
id = models.IntegerField(primary_key=True)
recipe = models.ForeignKey(Recipes, on_delete=models.CASCADE, related_name='ingredients')
ingredient = models.CharField(max_length=128)
class Meta:
managed = False
db_table = 'ingredients'
verbose_name_plural = 'Ingredients'
def __str__(self):
return f"{self.id} {self.recipe} - {self.ingredient}"
class Recipes(models.Model):
id = models.IntegerField(primary_key=True)
category = models.TextField(db_column='Category', null=False)
submitted_by = models.TextField(
db_column='Submitted_By', null=False)
origin = models.TextField(db_column='Origin', null=False)
title = models.TextField(db_column='Title', null=False)
directions = models.TextField(
db_column='Directions', null=False)
comments = models.TextField(db_column='Comments', null=False)
created = models.DateTimeField(null=False)
modified = models.DateTimeField(null=True)
def __str__(self):
return f"{self.id} - {self.title}"
class Meta:
managed = False
db_table = 'recipes'
verbose_name_plural = 'Recipes'
In views.py:
recipes = Recipes.objects.all().order_by(
"category", "title")
content['ingredients'] = {}
for recipe in recipes:
ingredients = Ingredients.objects.filter(
recipe=recipe.id).order_by("id")
content['ingredients'][recipe.id] = ingredients
content['recipes'] = recipes
return render(
request,
"myApp/recipes.html",
context=content)
In recipes.html:
{% for recipe in recipes %}
<div id="id-{{recipe.id}}" class="grid-item {{recipe.category}} {{recipe.submitted_by}}">
<div class="row">
<div class="col-12 col-md-3 ingredients">
{% for queryQbject in ingredients.recipe.id %}
{{ queryQbject.ingredient }}<br>
{% empty %}
<span>No ingredients provided</span>
{% endfor %}
</div>
</div>
{% endfor %}
I do get the correct data from the sqlite database and the Queryset is stored in the dictionary 'content' that is passed correctly into the html file. However, the html template doesn't display any of the data and only prints the 'No ingredients provided' {% empty %} case.
See debug info:
What do I need to do to fix this problem?
nigel239's answer got me thinking and researching some more. I found this post
https://fedingo.com/how-to-lookup-dictionary-value-with-key-in-django-template/
to write a custom filter to lookup a dictionary value with a key.
This is my custom_tags.py:
#register.filter
def get_item(dictionary, key):
try:
key = int(key)
value = dictionary.get(key)
except:
value = None
return value
and my updated recipes.html:
<div class="col-12 col-md-3 ingredients">
{% for queryset in ingredients|get_item:recipe.id %}
{{ queryset.ingredient }}<br>
{% empty %}
<span>No ingredients provided</span>
{% endfor %}
</div>
Now the code correctly pulls all the ingredients from the Django Queryset that was passed into the html template in a dictionary called 'ingredients' using the 'recipe.id' as keys.
You are trying to loop over the ID, which is an integer. Not an iterable.
Change
{% for queryQbject in ingredients.recipe.id %}
To
{% for queryQbject in ingredients.recipe %}
I am working on MDN Django tutorial on LocalLibrary.
I am using get_absolute_url to render generic ListView and DetailView page.
App is rendering page with else statement i.e. There are no books in the library.
But when I add books in the library through admin portal in my models. Same pages are not rendering and reflecting below error
NoReverseMatch at /catalog/books/
Reverse for 'book-detail' not found. 'book-detail' is not a valid view function or pattern name.
Please find the models.py as follows
import uuid # Required for unique book instances
from django.db import models
# Create your models here.
# Used to generate URLs by reversing the URL patterns
from django.urls import reverse
class Genre(models.Model):
"""Model representing a book genre."""
name = models.CharField(
max_length=200, help_text='Enter a book genre (e.g. Science Fiction)')
def __str__(self):
"""String for representing the Model object."""
return self.name
class Language(models.Model):
name = models.CharField(max_length=200, help_text='Enter a book language(e.g. English)')
def __str__(self):
return self.name
class Book(models.Model):
"""Model representing a book (but not a specific copy of a book)."""
title = models.CharField(max_length=200)
# Foreign Key used because book can only have one author, but authors can have multiple books
# Author as a string rather than object because it hasn't been declared yet in the file
author = models.ForeignKey('Author', on_delete=models.SET_NULL, null=True)
summary = models.TextField(
max_length=1000, help_text='Enter a brief description of the book')
isbn = models.CharField('ISBN', max_length=13, unique=True,
help_text='13 Character ISBN number')
# ManyToManyField used because genre can contain many books. Books can cover many genres.
# Genre class has already been defined so we can specify the object above.
genre = models.ManyToManyField(
Genre, help_text='Select a genre for this book')
language = models.ManyToManyField(
Language, help_text='Select Language for this book')
def __str__(self):
"""String for representing the Model object."""
return self.title
def get_absolute_url(self):
"""Returns the url to access a detail record for this book."""
return reverse('book-detail', kwargs= {'pk': str(self.id)})
def display_genre(self):
"""Create a string for the Genre. This is required to display genre in Admin."""
return ', '.join(genre.name for genre in self.genre.all()[:3])
display_genre.short_description = 'Genre'
def get_language(self):
"""Create a string for the Genre. This is required to display genre in Admin."""
return ', '.join(language.name for language in self.language.all()[:3])
get_language.short_description = 'Language'
class BookInstance(models.Model):
"""Model representing a specific copy of a book (i.e. that can be borrowed from the library)."""
id = models.UUIDField(primary_key=True, default=uuid.uuid4,
help_text='Unique ID for this particular book across whole library')
book = models.ForeignKey('Book', on_delete=models.RESTRICT, null=True)
imprint = models.IntegerField()
due_back = models.DateField(null=True, blank=True)
LOAN_STATUS = (
('m', 'Maintenance'),
('o', 'On loan'),
('a', 'Available'),
('r', 'Reserved'),
)
status = models.CharField(
max_length=1,
choices=LOAN_STATUS,
blank=True,
default='m',
help_text='Book availability',
)
class Meta:
ordering = ['due_back']
def __str__(self):
"""String for representing the Model object."""
return f'{self.id} ({self.book.title})'
class Author(models.Model):
"""Model representing an author."""
first_name = models.CharField(max_length=100)
last_name = models.CharField(max_length=100)
date_of_birth = models.DateField(null=True, blank=True)
date_of_death = models.DateField('Died', null=True, blank=True)
class Meta:
ordering = ['last_name', 'first_name']
def get_absolute_url(self):
from django.urls import reverse
"""Returns the url to access a particular author instance."""
return reverse('author-detail', args=[str(self.id)])
def __str__(self):
"""String for representing the Model object."""
return f'{self.last_name}, {self.first_name}'
Attached is the urls.py
from django.urls import path
from catalog import views
from catalog.views import BookListView, BookDetailView
app_name = 'catalog'
urlpatterns = [
path('', views.index, name='index'),
path('books/', views.BookListView.as_view(), name='books'),
path('book/<int:pk>', views.BookDetailView.as_view(), name='book-detail'),
path('authors/', views.AuthorListView.as_view(), name='authors'),
path('author/<int:pk>', views.AuthorDetailView.as_view(), name='author-detail'),
]
Views.py
from django.shortcuts import get_object_or_404
from django.views.generic.list import ListView
from django.views.generic.detail import DetailView
from django.http import HttpResponse
from django.shortcuts import render
from catalog.models import *
def index(request):
num_books = Book.objects.all().count()
num_instances = BookInstance.objects.all().count()
num_genre = Genre.objects.all()
num_instances_available = BookInstance.objects.filter(status__exact='avail').count()
num_authors = Author.objects.count()
context = {
'num_books': num_books,
'num_instances': num_instances,
'num_instances_available': num_instances_available,
'num_authors': num_authors,
'num_genre': num_genre,
}
return render(request, 'catalog/index.html', context=context)
class BookListView(ListView):
model = Book
paginate_by = 2
class BookDetailView(DetailView):
model = Book
class AuthorListView(ListView):
model = Author
class AuthorDetailView(DetailView):
model = Author
Template of book_list.html
This is saved as per this method
catalog/templates/catalog/book_list.html
{% extends "catalog/base.html" %}
{% block title %}
<title>List of Books</title>
{% endblock %}
{% block content %}
<h1>Book List</h1>
{% if book_list %}
<ul>
{% for book in book_list %}
<li>
{{ book.title }}
({{ book.author }})
</li>
{% endfor %}
</ul>
{% else %}
<p>There are no books in the library.</p>
{% endif %}
{% endblock %}
book_detail.html
This is saved as per this method
catalog/templates/catalog/book_detail.html
{% block content %}
<h1>Title: {{ book.title }}</h1>
<p><strong>Author:</strong> {{ book.author }}</p>
<p><strong>Summary:</strong> {{ book.summary }}</p>
<p><strong>ISBN:</strong> {{ book.isbn }}</p>
<p><strong>Language:</strong> {{ book.language }}</p>
<p><strong>Genre:</strong> {{ book.genre.all|join:", " }}</p>
<div style="margin-left:20px;margin-top:20px">
<h4>Copies</h4>
{% for copy in book.bookinstance_set.all %}
<hr>
<p class="{% if copy.status == 'a' %}text-success{% elif copy.status == 'd' %}text-danger{% else %}text-warning{% endif %}">{{ copy.get_status_display }}</p>
{% if copy.status != 'a' %}<p><strong>Due to be returned:</strong> {{copy.due_back}}</p>{% endif %}
<p><strong>Imprint:</strong> {{copy.imprint}}</p>
<p class="text-muted"><strong>Id:</strong> {{copy.id}}</p>
{% endfor %}
</div>
{% endblock %}```
I also find error on the same page for bootstrap link which is getting extended from base file and working fine with index.html
whereas on books.html page
It is showing this error
In template /Users/rishipalsingh/Projects/notes/mdndjango/mdn/catalog/templates/catalog/base.html, error at line 7
base.html
```
Thank you
You have namespaced your urls by writing:
app_name = 'catalog'
Hence reverse('book-detail', ...) will not work and you need to specify the namespace along with the url name, hence it should be:
reverse('catalog:book-detail', kwargs= {'pk': str(self.id)})
Similarly for the author:
reverse('catalog:author-detail', args=[str(self.id)])
I have two models one is club details and the other is player structure. so my plan is to based on the club iteration which has values like'test', 'odi', 'listA' i need to represent its respective player structure in my Django template.
models.py
class Clubstate(models.Model):
name = models.CharField(max_length=255)
def __str__(self):
return self.name
class PlayerStructure(models.Model):
clubstate = models.ForeignKey('Clubstate', on_delete=models.CASCADE, related_name='clubstate')
country = models.ForeignKey('TeamStructure', on_delete=models.CASCADE, null=True, related_name='identifier1')
firstname = models.CharField(max_length=255)
lastname = models.CharField(max_length=255)
imageUri = models.ImageField(upload_to='images/', verbose_name='image')
JerseyNumber = models.IntegerField()
def __str__(self):
return self.firstname + self.lastname
In views.py I'm using DetailView to represent the data.
class PlayerStatistics(DetailView):
context_object_name = 'Clubstate_details'
model = models.Clubstate
template_name = 'CricketDetails/playerstatistics_details.html'
Template html
<div class="jumbotron">
<div class="container">
<div class="row">
{% for club in Clubstate_details %}
<h1>{{club.name</h1>
{% endfor %}
</div>
</div>
</div>
My thought, logic is like
{% for club in clubs %}
{{club.name}}
{{club.player_structure.firstname}}
{{club.player_structure.lastname}}
{% endfor%}
So that for indivdual club i get its respective player structure.
I get TypeError: 'Clubstate' object is not iterable error.
Hope that makes sense...
Detail view won't give a list of items, instead it gives a single view only so change the DetailView to ListView and iterate through the output
class PlayerStatistics(ListView):
context_object_name = 'Clubstate_details'
model = models.Clubstate
template_name = 'CricketDetails/playerstatistics_details.html'
if you want detail view can get it by
{{ Clubstate_details.name }}
with DetailView
FK instance can be accessed by
{% for obj in Clubstate_details.playerstructure_set.all %}
{{ obj.firstname }}
{% endfor %}
I'm trying to a menu system for my sport site project where the sports are grouped together. For example the main category would be "ballsports" and under that (the child menu) people would select football, baseball or whatever else. I've got that all setup and functioning but I can't workout how to call the child menus into the templates.
Models:
class Sport(models.Model):
name = models.CharField(max_length=100, db_index=True)
sport_slug = models.SlugField(max_length=100, db_index=True)
category = models.ForeignKey('Sport_Category', on_delete=models.CASCADE,)
class Sport_Category(models.Model):
name = models.CharField(max_length=100, db_index=True)
category_slug = models.SlugField(max_length=100, db_index=True)
Views:
class IndexView(generic.ListView):
template_name="sports/index.html"
context_object_name='all_sport_category'
def get_queryset(self):
return Sport_Category.objects.all()
def list_of_sports_in_category(self):
sport_cat = self.category.name
return sport_cat
class SportListView(generic.ListView):
template_name="sports/sport-home.html"
context_object_name='sport_list'
def get_queryset(self):
return Sport.objects.all()
Template:
{% for sport_category in all_sport_category %}
<li>{{ sport_category.name }} </li> *(Working)*
{% for sports in list_of_sports_in_category %}
hi
{% endfor %}
{% endfor %}
list_of_sports_in_category method seems to return the category name, rather than the list of sports. try replacing the second for-loop in your template with {% for sport in sport_list %}.
I have two models, Author & Book in models.py
class Author(models.Model):
first_name = models.CharField(max_length=30)
last_name = models.CharField(max_length=40)
email = models.EmailField()
age = models.IntegerField()
def __str__(self):
return '%s %s' %(self.first_name, self.last_name)
def __unicode__(self):
return '%s %s' %(self.first_name, self.last_name)
class Book(models.Model):
title = models.CharField(max_length=100) #name = title
pages = models.IntegerField()
price = models.DecimalField(max_digits=10, decimal_places=2)
rating = models.FloatField()
author = models.ManyToManyField(Author)
publisher = models.ForeignKey(Publisher)
publication_date = models.DateField()
def __str__(self):
return self.title
def __unicode__(self):
return self.title
Now i'm listing all the books using ListView. And on click of a book i'm getting information the book using following method
class BookDetailView(generic.DetailView):
template_name = 'books/book_detail1.html'
model = Book
context_object_name = 'book_detail'
I'm able to access title, pages, price, rating, publisher & publication_date but not getting all the Authors(Author list). While i'm going to simply print it, it prints None in template. I even try to iterate using For Loop but not done in template
views.py
<!DOCTYPE html>
<html>
<head>
<title></title>
</head>
<body>
<ul>
<li>Price:{{ book_detail.price }}</li>
<li>Pub Date:{{ book_detail.publication_date }}</li>
<li>Title: {{ book_detail.title }}</li>
<li>Pages: {{ book_detail.pages }}</li>
<li>Rating: {{ book_detail.rating }}</li>
<li>Publisher: {{ book_detail.publisher }}</li>
<li>Author: {{ book_detail.author }}</li>
</ul>
</body>
</html>
Can anyone help me to out from this?
You have defined a many-to-many relationship between Book and Author which means that a book can have any number of authors. In order to display them you need to loop through the set of authors:
Authors:
<ul>
{% for author in book_detail.author.all %}
<li>{{ author }}</li>
{% endfor %}
</ul>
You might want to change the name of that field to authors to be less confusing.
Alternatively if you want only one author for a book then you need to use a ForeignKey instead of a ManyToManyField. In that case your existing template logic would work.
Or if you use Function-Based Views, define this view:
#views.py
def book_detail_view(request, id):
book = get_object_or_404(Book, id=id)
authors_of_book = book.questions.all()
template = 'books/book_detail1.html'
context = {'authors_of_book': authors_of_book}
return render(request, template, context)
And also in your template:
#html.py
<ul>
{% for author in authors_of_book %}
<li>{{ author }}</li>
{% endfor %}
</ul>
For more detail read this document.