Rendering list of query_set as row on html template - python

I would like a list of Articles tagged associated with Stories to be rendered on rows exclusive to their Story. Currently the template returns only articles from the last Story on three separate rows. The code as written and understood is:
Many Articles can belong to a single Story.
/models.py
class Story(models.Model):
title = models.CharField(max_length=200, default= "")
description = models.TextField()
publication_date = models.DateTimeField()
class Article(models.Model):
feed = models.ForeignKey(Feed)
title = models.CharField(max_length=200)
url = models.URLField()
publication_date = models.DateTimeField()
story = models.ManyToManyField(Story, default=None, blank=True)
Using queries, get a list of all story_ids. If entry in story_id_lst is equal to story_id in articles then append that story to row list.
/views.py
def articles_list(request):
articles = Article.objects.all()
story_id_lst = articles.values_list('story').distinct()
for entry in story_id_lst:
rows = articles.filter(story=entry)
Running that code in the shell returns three list, one empty, one with all articles matched to story 1 and one with all articles matched to story 2. I believe the problem is somewhere in the following code.
/views.py
return render(request, 'news/articles_list.html', {'rows': rows})
/articles_list.html
<div class="container" style="background-color: #DCDCDC; border-radius: 25px;">
<div class="row">
{% for row in rows %}
<div class="col-md-12">
{% for entry in row %}
<div class="container-fuild">
<div class="col-md-4" >
<h2>{{entry.title}}</h2>
<div>
<p>View Details</p>
</div>
</div>
</div>
{% endfor %}
</div>
{% endfor %}
</div>
</div>

I see you've made extensive changes to your question..
If an Article can belong to a single Story, then Article should have a foreign key to Story (not a many-to-many relation):
class Story(models.Model):
title = models.CharField(max_length=200, default= "")
class Article(models.Model):
story = models.ForeignKey(Story, default=None, blank=True)
title = models.CharField(max_length=200)
url = models.URLField()
then the view can be written as:
def articles_list(request):
articles = Article.objects.all()
return render(request, 'news/articles_list.html', {'articles': articles})
and the template:
{% regroup articles by story as story_list %}
<ul>
{% for story in story_list %}
<li>{{ story.grouper }}
<ul>
{% for article in story.list %}
<li>{{ article.title }}</li>
{% endfor %}
</ul>
</li>
{% endfor %}
</ul>

Related

How to access a field through a sub table Django

I Have a table Product and a table Variation, Variation has ManyToOne relation i.e. ForeignKey with the table.
I want only first object of Variation, so that I can render it fields, which I want.
The way I am currently implementing to call the first object in html page:
{{item.variation.price_set.first}}
Note: {{item}} is my product object or instance.
Html file:
<div class="carousel-inner">
{% for item in TopItems %}
{% if item.image %}
<div class="carousel-item active">
<img class="d-block img-fluid mx-auto m-auto" src="{{item.image.url}}" alt="{{item.name}}">
<p>{{item.name}}</p>
<p>{{item.variation.price_set.first}}</p>
<p>{{item.variation_set.first}}</p>
{% if item.variation.promotion_price_set.first%}
<h2 class="text-primary">
{{item.variation.promotion_price}}
</h2>
<h2 class="text-primary">
{{item.variation.price}}
</h2>
{% else %}
<h2 class="text-primary">
{{item.variation.price}}
</h2>
{% endif %}
</div>
{% endif %}
{% endfor%}
</div>
Models.py
class Product(models.Model):
name = models.CharField(max_length=255)
short_description = models.TextField(max_length=255)
long_description = models.TextField(max_length=255, blank=True)
image = ResizedImageField(
size=[550, 300], quality=70, upload_to='product_images/%Y/%m/%d')
#image = models.ImageField(upload_to='product_images/%Y/%m/%d')
slug = AutoSlugField(unique=True, always_update=False,
populate_from="name")
top_item = models.BooleanField(default=False)
is_available = models.BooleanField(default=True)
category = models.ForeignKey(
Category, related_name="product", on_delete=models.CASCADE)
subcategory = models.ForeignKey(
SubCategory, related_name="sub", on_delete=models.CASCADE, null=True, blank=True)
objects = models.Manager()
available = AvailableManager()
class Meta:
ordering = ("name",) # vai ser ordenado pelo nome não o ID
def get_absolute_url(self):
return reverse("product:detail", kwargs={"slug": self.slug})
class Variation(models.Model):
product = models.ForeignKey(Product, on_delete=models.CASCADE)
name = models.CharField(
max_length=80, blank=True, null=True)
price = models.FloatField()
promotion_price = models.FloatField(blank=True, null=True)
stock = models.PositiveIntegerField(default=1)
is_available = models.BooleanField(default=True)
availableVariation = AvailableManagerVariation()
objects = models.Manager()
def __str__(self):
return self.name or self.product.name
Views.py, the below method is passing all records to the template.
def get_context_data(self, **kwargs):
context["TopItems"]= Product.objects.filter(top_item=True)
So, How can I get only first record of variaton, so that I can show respective prices?
You can use nested loops, for accessing only first promotion price as well as price in the following way:
This is a minimal reproducible example, as not able to understand your design.
{% for item in TopItems %}
<div>
<p> {{item.name}} </p>
<p>{{forloop.counter}}st variation</p>
{% for variation in item.variation_set.all %}
{% if forloop.counter0 < 1 %}
<p>First variation price of - {{variation.price}}</p>
{% comment %}It will give only first price {% endcomment %}
<p>First variation promotion price - {{variation.promotion_price}}</p>
{% comment %}It will give only first promotion price{% endcomment %}
{% endif %}
{% endfor %}
</div>
<br>
{%endfor%}
Note: There must be a space between template tags, as so write it as {% endif %} not {%endif%}, similarly for {% endfor %} not {%endfor%}.
Note: It will be better, if you pass your context keys in snake_case rather than PascalCase, so it can be passed as top_items rather than TopItems.

How to show sub-sub category of sub-category in Django?

I have the following models:
class TutorialCategory(models.Model):
category_title = models.CharField(max_length=150)
category_summary = models.CharField(max_length=150)
category_slug = models.SlugField(default=1, blank=True)
class TutorialSeries(models.Model):
series_title = models.CharField(max_length=200)
series_maincategory = models.ForeignKey(
TutorialCategory, default=1, on_delete=models.SET_DEFAULT)
series_summary = models.CharField(max_length=200)
class Tutorial(models.Model):
tutorial_title = models.CharField(max_length=150)
tutorial_content = models.TextField()
tutorial_published = models.DateTimeField(
"date Published", default=datetime.now())
tutorial_series = models.ForeignKey(
TutorialSeries, default=1, on_delete=models.SET_DEFAULT)
tutorial_slug = models.SlugField(default=1, blank=True)
As shown above TutorialCategory is main category, TutorialSeries is sub category and Tutorial is sub-sub-category. I created a simple view that shows sub categories of main categories, but don't know how to show the sub-sub categories of sub category.
Please check out views.py and urls.py if you can improve its quality and if there is an easy and better way of doing it. Anyway, this is view:
def single_slug(request, single_slug):
matching_series = TutorialSeries.objects.filter(
series_maincategory__category_slug=single_slug)
series_urls = {}
for i in matching_series.all():
part_one = Tutorial.objects.filter(
tutorial_series__series_title=i.series_title).earliest("tutorial_published")
series_urls[i] = part_one.tutorial_slug
return render(request, 'tutorial/sub-category.html', context={
"tutorial_series": matching_series,
'part_ones': series_urls
})
urls here:
urlpatterns = [
path('', views.home_page, name='home'),
path('tutorial/<int:id>/', views.tutorial_detail, name='tutorial_detail'),
path('<single_slug>/', views.single_slug, name='single_slug'),
]
the template that shows sub-category of main category:
{% for tut, partone in part_ones.items %}
<div class="card">
<div class="card-body">
<h5 class="card-title">{{ tut.series_title }}</h5>
<p>{{ tut.series_summary }}</p>
Read more
</div>
</div>
{% endfor %}
Please help me how to do it and if you know any better way of doing it please let me know and help me. Thank you so much in advance.
edit: #ruddra
I changed views.py to this passing matching_series
def single_slug(request, single_slug):
matching_series = TutorialSeries.objects.filter(
series_maincategory__category_slug=single_slug)
series_urls = {}
for i in matching_series.all():
part_one = Tutorial.objects.filter(
tutorial_series__series_title=i.series_title).earliest("tutorial_published")
series_urls[i] = part_one.tutorial_slug
return render(request, 'tutorial/sub-category.html', context={
"matching_series": matching_series,
'part_ones': series_urls
})
and replaced the previous template with yours. template here:
{% for tutorial in matching_series %}
{% for sub_cat in tutorial.tutorialseries_set.all %}
{{ sub.series_title }}
{% for sub_sub_cat in sub.tutorial_set.all %}
{{ sub_sub_cat.tutorial_title }}
{% endfor %}
{% endfor %}
{% endfor %}
You can try like this:
{% for sub_cat in matching_series %}
{% for sub_sub_cat in sub_cat.tutorial_set.all %}
{{ sub_sub_cat.tutorial_title }}
{% endfor %}
{% endfor %}
Here I am assuming matching_series is being passed through context from view in single_slug. Then I am using backward relation between different models to fetch the data.
Explanation: Assuming there is object named tutorial_category which is instance of TutorialCategory. As there is ForeignKey from TutorialSeries to TutorialCategory, I can use tutorial_category.tutorialseries_set.all() or .filter() etc to fetch the tutorial series from tutorial_category object( As I am rendering it in template, I removed parenthesis after all). Similarly I fetch Tutorial from TutorialSeries.

How to work with Choices in Django - How to display specific content?

I try to create a book database in Django. I have to do one more thing. So i have a model with CHOICES:
#model Book
class Book(models.Model):
#book types and placed
BIOGRAPHY = 1
FANTASY = 2
HISTORICAL = 3
HORROR = 4
CLASSIC = 5
YOUTH_LITHERATURE = 6
NON_FICTION = 7
MODERN_LITERATURE = 8
POETRY = 9
ADVENTURE = 10
ESSAYS = 11
ROMANCE = 12
SATIRE = 13
THRILLER = 14
DRAMA = 15
NONE = 0
B00K_CHOICES = (
(BIOGRAPHY,'Biography'),
(FANTASY, 'Fantasy/Sci-Fi'),
(HISTORICAL, 'Historical'),
(HORROR, 'Horror'),
(CLASSIC, 'Classic'),
(YOUTH_LITHERATURE, 'Youth Litherature'),
(NON_FICTION, 'Non-Fiction'),
(MODERN_LITERATURE, 'Modern Literature'),
(POETRY, 'Poetry'),
(ADVENTURE, 'Adventure'),
(ESSAYS, 'Essays'),
(ROMANCE, 'Romance'),
(SATIRE, 'Satire'),
(THRILLER, 'Thriller'),
(DRAMA, 'Drama'),
(NONE, 'No Information'),
)
book_image = models.ImageField(upload_to='book_image', blank=True, null=True)
book_name = models.CharField(max_length=255, unique=True)
book_author = models.ForeignKey(Author, on_delete=models.CASCADE)
book_types = models.IntegerField(choices=B00K_CHOICES, default= NONE)
book_description = models.TextField(null=True, blank=True)
book_pages = models.PositiveIntegerField(null=True, blank=True)
book_published = models.DateField(null=True, blank=True)
book_ratings = GenericRelation(Rating, related_query_name='book', default=NONE)
def __str__(self):
return '{}'.format(self.book_name)
And i create a simple view with display this choices:
def book_types_list(request):
book = Book.objects.all()
context = {'book': book, 'book_types': Book.B00K_CHOICES}
return render(request, 'plibrary_core/book_types_list.html', context)
I create also a html template with list of this choices:
{% extends 'base.html' %}
{% load static %}
{% block custom %}
<link rel='stylesheet' type="text/css" href="{% static 'css/background_color_styles.css' %}">
{% endblock %}
{% block title %}
<title>Book Types List | Private Library</title>
{% endblock %}
{% block content %}
<div class="container">
<div class="col">
<div id="background-color-content">
<h3>Book Types</h3>
<hr>
{% for book_type in book_types %}
<ul>
<h6>{{ book_type }}</h6>
</ul>
{% endfor %}
</div>
</div>
</div>
{% endblock %}
And in this moment, i need to have something like this - User click on the book type (for example Horror) and then he see another template with all books with only this types. I try to do something like this but it doesn't work. I don't know how to fix it. Somebody know what i need to do?;X
Firt use ul apropiatelly, with each item in a li tag, and in the correct place:
<ul> <!-- ul is outside the loop -->
{% loop %}
<li> ...</li>
{% endloop %}
</ul>
Then in your view you don't need to call the object Book.objects.all() unless you want to show all your books. It looks like you are just displaying the book choices.
def book_types_list(request):
book = Book.objects.all() # why do you need this in your view?
context = {'book': book, 'book_types': Book.B00K_CHOICES}
return render(request, 'foo/books.html', context)
Then in your template you just need to:
<ul>
{% for book_type in book_types %}
<li>
<!-- you have to handle the logic of the url here -->
{{ book_type.1 }}
</li>
{% endfor %}
</ul>
urls.py
url(r'^my_url/(?P<book_type_id>\d+)/$', my_view, name='my_url'),
with this element you get to render a select element on screen, and it will use the choices you are providing in choices, use that instead of the for loop of book types
{{ book.booktypes }}

Django display limited images in grid row

As mentioned in the title. Is it possible to display a specific number of photos in a particular grid-container? For example, a maximum of 3 columns with a card in the row using a loop?
I was able to achieve the effect of displaying all the photos from the defined model,but I don't know how to set the limit.
Below I present fragments of the code responsible for displaying the created model
forms.py
class ProductsForm(forms.ModelForm):
class Meta:
model = Product
fields = ('name', 'description', 'image', 'file_type')
models.py
class Product(models.Model):
name = models.CharField(max_length=20, default='')
description = models.CharField(max_length=100, default='')
file_type = models.CharField(max_length=256, choices=[('image', 'image'), ('thumbnail', 'thumbnail')], default='')
image = models.ImageField(upload_to='products', default='')
def __str__(self):
return self.name
views.py
def gallery(request):
image = Product.objects.filter(file_type='image')
thumbnail = Product.objects.filter(file_type='thumbnail')
return render(request, 'products/fruits.html', {'img': image, 'thumb': thumbnail})
fruits.html
<!DOCTYPE html>
{% load staticfiles %}
{% load thumbnail %}
{% block body_block %}
<div class="grid-container">
<div class="card-deck">
{% for i in thumb %}
{% thumbnail i.image "150x150" crop="center" as im %}
<!-- Card -->
<div class="card mb-4">
<!--Card image-->
<div class="view overlay">
<img src="{{ im.url }}"
alt="Card image cap">
<a href="#!">
<div class="mask rgba-white-slight"></div>
</a>
</div>
<!--Card content-->
<div class="card-body">
<!--Title-->
<h4 class="card-title">Card title</h4>
<!--Text-->
<p class="card-text">Some quick example text to build on the card title and make up
the
bulk
of
the
card's
content.</p>
<!-- Provides extra visual weight and identifies the primary action in a set of buttons -->
<button type="button" class="btn btn-light-blue btn-md">Read more</button>
</div>
</div>
{% endthumbnail %}
{% endfor %}
</div>
</div>
{% endblock %}
The build-in Django filter divisibleby may work, inside your loop, you check whether the iteration is divisible by (in your case) 3, then you break the row to jump to another one:
{% for i in thumb %}
{% if forloop.counter|divisibleby:3 %}
----------
{% endif %}
{% endfor %}
I was able to get what you want to do by creating a list of lists of images in the view, then send this list to the HTML template and display it with two loops. The advantage of this approach is that you can control the number of columns by changing one variable. Each element of the main list contains X number of columns.
The idea is to send a list like the one represented below (more or less)
photos_list = [[photo1, photo2, ... photoN], [photo1, photo2, ... photoN]]
the view code is:
def index(request):
photos = Photo.objects.all()
counter = -1
columns_qty = 5 # << Just change this number for the columns you want
photos_row = []
photos_list = []
for photo in photos:
counter += 1
if counter < columns_qty:
photos_row.append(photo)
else:
photos_list.append(photos_row)
photos_row = []
counter = -1
context = {'photos_list': photos_list}
return render(request, 'photos/index.html', context)
the model code is:
class Photo(models.Model):
file_name = models.CharField(max_length= 250)
original_path = models.CharField(max_length=250)
saved_path = models.CharField(max_length=250)
file_size = models.IntegerField(null=True)
file_created = models.DateTimeField(null=True)
file_last_modified = models.DateTimeField(null=True)
loaded_datetime = models.DateTimeField(default=timezone.now())
def __str__(self):
return self.file_name
and the html template code is:
{% extends 'photos/base.html' %}
{% load static %}
{% block content %}
<table>
{% for photo_row in photos_list %}
<tr>
{% for photo_col in photo_row %}
<td><img src="{% static photo_col.file_name %}" width="300px"
height="auto"></td>
{% endfor %}
</tr>
{% endfor %}
</table>
{% endblock %}
I hope this helps!

Django 1.6 getting fk objects

I have a this models
class Project(models.Model):
name = models.CharField(max_length=20)
description = models.CharField(max_length=200, null=True, blank=True)
creation_date = models.DateTimeField(auto_now_add=True, auto_now=False)
group_owner = models.ForeignKey(User)
def __str__(self, y):
return smart_str(self.name)
class Note(models.Model):
title = models.CharField(max_length=50, null=True, blank=True)
content = models.CharField(max_length=1000)
creation_date = models.DateTimeField(auto_now_add=True, auto_now=False)
updated_date = models.DateTimeField(auto_now_add=False, auto_now=True)
projectId = models.ForeignKey(Project, on_delete=models.CASCADE)
userid = models.ForeignKey(User, on_delete=models.CASCADE)
def __str__(self):
return smart_str(self.title)
which i would like to join them in one view, which would be shown when someone enters to this url http://localhost.com:8000/project/ID.
obviously the ID will depend in Project.id and it will have to get all the Notes that are related to it.
Meanwhile my views.py looks like this
class ProjectDetail(generic.DetailView):
model = Project
template_name = 'scribere/project/detail.html'
def get_queryset(self):
return Project.objects.filter(group_owner__exact=self.request.user.id)
class ProjectNoteList(generic.ListView):
context_object_name = 'project_note_list'
template_name = 'scribere/note/index.html'
def get_queryset(self):
return Note.objects.filter(userid__exact=self.request.user.id, projectId__exact=self.kwargs['pk'])
and the template
{% extends "base/adminsNavBar.html" %}
{% load i18n %}
{% block head_title %}{% trans 'Projects Details' %}{% endblock %}
{% block breadcrumbs %}
<div class="breadcrumb"><p>{% trans 'Project Details' %}</p></div>
{% endblock %}
{% block content %}
<div class='row'>
{% trans 'Back' %}
{% trans 'Notes' %}
</div>
<div>
{{project.name}}
</div>
<div class = "note-list">
<ul>
{% for note in project_note_list %}
<li>
{{note}}
</li>
{% endfor %}
</ul>
</div>
{% endblock %}
which doesn't load any information about the note. What am i missing?
Unless you are populating project_note_list with some information, there will be nothing to iterate over.
By virtue of the ForeignKeys, and having a Many to one relation the project object will have a set of notes associated with it, without having to look them up.
You should be able to query them using project.note_set.all() or in your template by using:
{% for note in project.note_set %}

Categories