How to send multiple model from a classbased view in django - python

I made a booklist where cover image can be uploaded inside Booklist class. For more image I added another class called Bookcover. Now in Views.py how can I send both Booklist and Bookcover's by using BookListView
models.py file is below
from django.db import models
from django.utils import timezone
class Booklist(models.Model):
title = models.CharField(max_length=100)
author = models.CharField(max_length = 100)
cover = models.ImageField(null=True, blank=True, default='default-book.jpg')
description = models.TextField()
date_posted = models.DateTimeField(default=timezone.now)
price = models.DecimalField(decimal_places=3, max_digits=100)
def __str__(self):
return self.title
class Bookcover(models.Model):
post = models.ForeignKey(Booklist, default=None, on_delete=models.CASCADE)
covers = models.ImageField(upload_to = 'images/')
def __str__(self):
return self.post.title
here is views.py file
from django.shortcuts import render
from django.views.generic import ListView
from .models import Booklist, Bookcover
def home(request):
return render(request, template_name='home/index.html')
class BookListView(ListView):
model = Booklist
template_name = 'home/index.html'
context_object_name = 'books'
ordering = ['-date_posted']

If you make a ForeignKey, Django automatically will generate a relation in reverse to access - in this case - the related BookCovers for a specific Book. Since you did not specify the related_name=… parameter [Django-doc], the name of this relation is modelname_set, so in this case, bookcover_set.
In the template you can access the book covers of a book with:
{% for book in books %}
{{ book.title }}
{% for cover in book.bookcover_set.all %}
<img src="{{ cover.covers.url }}">
{% endfor %}
{% endfor %}
This will result in an N+1 problem however. You can avoid that by using .prefetch_related(…) [Django-doc]:
class BookListView(ListView):
queryset = Booklist.objects.prefetch_related('bookcover_set')
template_name = 'home/index.html'
context_object_name = 'books'
ordering = ['-date_posted']

Related

How to render view from differents applications in the same template?

I have two applications (blog and category). On the post list template I would like to get the category blog name and description.
I have tried to put the import category model in the blog view, but nothing show up. So I have made two views rendering the same template, but it does not work.
Blog models:
from django.db import models
from django.utils import timezone
from autoslug import AutoSlugField
from category.models import Category
class Post(models.Model):
author = models.ForeignKey('auth.User', on_delete=models.CASCADE)
category = models.ForeignKey(Category, on_delete=models.CASCADE,
default = '')
title = models.CharField(max_length=200)
...
class Meta:
verbose_name = "Post"
verbose_name_plural = "Posts"
ordering = ['created_date']
def publish(self):
self.published_date = timezone.now()
self.save()
def __str__(self):
return self.title
category models:
class Category(models.Model):
name = models.CharField(max_length=200)
slug = AutoSlugField(populate_from='name', default='')
parent = models.ForeignKey('self', blank=True, null=True, related_name='children', on_delete=models.CASCADE)
description = models.TextField(max_length=200)
class Meta:
unique_together = ('slug', 'parent',) # Enforcing that there can not be two
verbose_name_plural = "categories" # categories under a parent with same
# slug
def __str__(self): # __str__ method elaborated later in
full_path = [self.name] # post. use __unicode__ in place of
# __str__ if you are using python 2
k = self.parent
while k is not None:
full_path.append(k.name)
k = k.parent
return ' -> '.join(full_path[::-1])
Blog view:
def post_list(request):
posts = Post.objects.all()
cat_blog = Category.objects.get(pk=1)
context = {
'posts': posts,
'cat_blog': cat_blog
}
return render(request, 'blog/post_list.html', context)
Category view:
def cat_blog(request):
cat_blog = Category.objects.get(pk=1)
return render(request, 'blog/post_list.html', {'cat_blog': cat_blog})
post_list.html:
<div class="section-header text-center">
{% for category in cat_blog %}
<h1>{{ category.name }}</h1>
<p class="tag">{{ category.description }}</p>
{% endfor %}
</div>
<div class="row py-5">
{% for post in posts %}
// This part is fine
{% endfor%}
The post loop is fine. How can't I get the category name and description in my section header?
One URL gives one View gives one template.
You use the View to give context to the template to render.
def post_list(request):
posts = Post.objects.all()
cat_blog = Category.objects.get(pk=1)
context = {
'posts': posts,
'cat_blog': cat_blog
}
return render(request, 'blog/post_list.html', context)
Your url.py file should point to the post_list view.

How do I sort my topics by category in Django?

Alright so I want to order my topics by the category in Django. What's the best way of doing this?
views.py:
from django.shortcuts import render
from .models import Category
from .models import Topic
# Create your views here.
def forums(request):
categorys = Category.objects.all()
topics = Topic.objects.all()
return render(request, 'forums.html', {'categorys': categorys, 'topics': topics})
models.py:
from django.db import models
# Create your models here.
class Attachment(models.Model):
file = models.FileField()
def __str__(self):
return self.file
class Category(models.Model):
title = models.CharField(max_length=150)
def __str__(self):
return self.title
class Topic(models.Model):
title = models.CharField(max_length=150)
description = models.TextField()
category = models.ForeignKey('Category', on_delete=models.CASCADE)
def __str__(self):
return self.title
class Post(models.Model):
title = models.CharField(max_length=150)
body = models.TextField()
forum = models.ForeignKey('Topic', on_delete=models.CASCADE)
def __str__(self):
return self.title
Also, yes I know that categories is spelled wrong, I still need to add the Meta.
You can get all the topics inside categories in following way:
{% for category in categorys %}
<h1>{{category.title}}</h1>
<ul>
{% for topic in category.topic_set.all %}
<li>{{topic.title}}</li>
{% endfor %}
</ul>
{% endfor %}

can't find data in django

I have some questions about django orm with mysql.
This is my models.py
from django.db import models
#电影列表
class Movieinfo(models.Model):
movienum = models.IntegerField(primary_key=True)
moviename = models.CharField(max_length=100)
movierelease_time = models.CharField(max_length=20)
movietype = models.CharField(max_length=100)
class Meta:
ordering = ["movienum"]
def __str__(self):
return self.moviename
#短评论
class Moviescritic(models.Model):
movieinfo = models.ForeignKey(Movieinfo)
movienum = models.IntegerField()
moviescrit= models.TextField()
class Meta:
ordering = ["movienum"]
def __str__(self):
return self.moviescrit
#长影评
class Movielcritic(models.Model):
movieinfo = models.ForeignKey(Movieinfo)
movienum = models.IntegerField()
movielcrittitle = models.TextField()
movielcrit = models.TextField()
class Meta:
ordering = ["movienum"]
def __str__(self):
return self.movielcrit
This is my views.py
import logging
from django.http import HttpResponse
from django.views.generic import DetailView
from django.template import loader
from yingping.models import Moviescritic
logger = logging.getLogger('__name__')
def cdview(request):
template = loader.get_template('worldcloud.html')
movie_shu = Moviescritic.objects.filter(
movieinfo__movienum='10014'
)
content = {
'movie_shu':movie_shu,
}
return HttpResponse(template.render(content,request))
But I can't find any data in html, is my understanding of django onetomany wrong?
{% block worldcloud %}
{% if movie_shu %}
{% for x in movie_shu %}
<p>{{x}}</p>
{% endfor %}
{% else %}
print("err")
{% endif %}
<!--SERVICES SECTION END -->
{% endblock %}
the html just find print("error"), when i find data in itself table I can find data in HTML. so what's wrong with my code?

Django tree query spanning multi model relation

Please consider code the following code. I'd like to create something like a tree structure (it will be in a table) related to a specific loged-in user. I'd like to have an overviewpage in which all categories are shown for which this user has items in the subcategories. My query works, but gives me all subcategory records and all posible items in those subcategories (so not just the subset for which the user has records.
I have another way working by starting with the itemmodel and then going up in the tree, but thats not what i'm looking for (this makes creating a dynamic set of tables far to depended on the django template layer).
I've looked at select_related and prefetch, but I can't get close to a solution. Any help would be appriciated.
models.py:
from django.db import models
from model_utils.models import TimeStampedModel
from django.conf import settings
User = settings.AUTH_USER_MODEL
class MainCat(TimeStampedModel):
name = models.CharField(max_length=100, unique=True)
rank = models.IntegerField(default=10)
icon_class = models.CharField(max_length=100, null=True, blank=True)
class SubCat(TimeStampedModel):
name = models.CharField(max_length=100, null=False, blank=False)
slug = models.SlugField(null=True, blank=True)
icon_class = models.CharField(max_length=100, null=True, blank=True)
main_cat = models.ForeignKey(MainCat)
class Item(TimeStampedModel):
user = models.ForeignKey(User, blank=True, null=True)
item_name = models.CharField(max_length=100, null=False, blank=False)
sub_cat = models.ForeignKey(SubCat, blank=True, null=True)
views.py:
from django.views.generic import ListView
from django.contrib.auth.mixins import LoginRequiredMixin
from .models import MainCat
class MainCatByUserListView(LoginRequiredMixin, ListView):
model = MainCat
def get_queryset(self):
qs = super(MainCatByUserListView, self).get_queryset()
qs = qs.filter(subcat__item__user=self.request.user)
return qs
template:
< html >
< body >
{% for maincat in object_list %}
< ul >
<li> {{maincat.name}} </li>
<ul>
{% for subcat in maincat.subcat_set.all %}
<li> {{subcat.name}} </li>
{% for item in subcat.item_set.all %}
<li> {{item.name}} </li>
</ul>
</ul>
{% endfor %}
{% endfor %}
{% endfor %}
< / body >
< / html >
{% endfor %}
You should be able to use something like: Subcat.objects.filter(item_set__user=self.request.user).select_related('main_cat')
Finaly got to an answer to my question. For future reference:
class MainCatListView(LoginRequiredMixin, ListView):
model = MainCat
template_name = 'app/main_cat_overview.html'
def get_queryset(self):
qs = super(MainCatListView, self).get_queryset()
qs_user_cat_set = SubCat.objects.filter(item__user=self.request.user).prefetch_related(Prefetch(
"item_set",
queryset=Item.objects.filter(user=self.request.user),
to_attr="item_attr")
).distinct()
qs = qs.filter(subcat__item__user=self.request.user).prefetch_related(Prefetch(
"subcat_set",
queryset=qs_user_subcat_set,
to_attr="subcat_attr")
).distinct()
return qs

How to display objects related through ManyToMany via prefetch_related?

UPDATE
I was able to accomplish this in my Project models.py, but I feel this belongs in my view. How would I go about doing this? Code:
#property
def related_project_set(self):
category_id_list = self.category.values_list("id", flat=True)
return Project.live.filter(category__id__in=category_id_list).exclude(id=self.id)[:5]
I'd like to display "projects" related by "category" in my generic class-based detail view for project. I'm also using the Django-Braces PrefetchRelated Mixin. But I don't understand why the Python interpreter displays different results than my template.
For example, given two projects in the db, I get the following result:
>>> from projects.models import Project
>>> Project.objects.all().prefetch_related('category')
[<Project: Avalon Road>, <Project: Piedmont Avenue>]
Models:
class Project(models.Model):
"""
A project completed by ICON.
"""
LIVE_STATUS = 1
DRAFT_STATUS = 2
STATUS_CHOICES = (
(LIVE_STATUS, 'Live'),
(DRAFT_STATUS, 'Draft'),
)
title = models.CharField(max_length=200)
slug = models.SlugField(help_text='Populates from title field.')
date_completed = models.DateField(null=True, blank=True)
vison_description = models.TextField(help_text='Please use Markdown syntax. No HTML is allowed.')
work_description = models.TextField(help_text='Please use Markdown syntax. No HTML is allowed.')
category = models.ManyToManyField(Category)
lead_photo = models.ImageField(upload_to='projects/photos', help_text='Will also be used as thumbnail for category listing.')
gallery = models.ForeignKey(Gallery)
status = models.IntegerField(choices=STATUS_CHOICES, default=2, help_text="Only projects with a status of 'live' will be displayed publicly.")
objects = models.Manager()
live = LiveProjectManager()
class Category(models.Model):
title = models.CharField(max_length=100)
slug = models.SlugField(help_text='Populates from title field.')
description = models.TextField(help_text='Please use Markdown syntax. No HTML is allowed.', blank=True)
class Meta:
verbose_name_plural = 'Categories'
ordering = ('title',)
def __str__(self):
return self.slug
#models.permalink
def get_absolute_url(self):
return ('categories:detail',
(),
{'slug': self.slug})
Views:
from __future__ import absolute_import
from braces.views import PrefetchRelatedMixin
from django.shortcuts import render
from django.views.generic import DetailView, ListView
from .models import Project
from categories.models import Category
from testimonials.models import Testimonial
class ProjectDetailView(PrefetchRelatedMixin, DetailView):
prefetch_related = ['category']
queryset = Project.live.all()
def get_context_data(self, **kwargs):
"""
Allow the project detail view to display a list of testimonials.
"""
context = super(ProjectDetailView, self).get_context_data(**kwargs)
context['testimonial_list'] = Testimonial.displayed.all()
return context
class ProjectListView(ListView):
queryset = Project.live.all()
def get_context_data(self, **kwargs):
"""
Allow the project list view to display a list of categories.
"""
context = super(ProjectListView, self).get_context_data(**kwargs)
context['category_list'] = Category.objects.all()
return context
Template snippet:
<ul>
{% for project in object.category.all %}
<li>{{ project.title }}</li>
{% endfor %}
</ul>

Categories