I have 2 model objects, Business & BusinessImage as so, listed with views and index.html. I am trying to list the business's featured image, but it's not happening. I am getting the following error:
'QuerySet' object has no attribute 'businessimage_set'
How can I get the business featured image for a list?
Business
class Business(models.Model):
name = models.CharField("Name", max_length=70, default="Business Name")
slug = models.SlugField()
description = models.TextField("About", max_length=400)
category = models.ManyToManyField(Category, verbose_name="Categories", blank=True)
order = models.IntegerField("Order", default=0)
claimed = models.BooleanField("Claimed", default=False)
featured = models.BooleanField("Featured", default=False)
class Meta:
ordering = ['order']
verbose_name = "Business"
verbose_name_plural = "Businesses"
def __str__(self):
return self.name
BusinessImage
class BusinessImage(models.Model):
business = models.ForeignKey(Business)
image = models.ImageField(upload_to="images/business")
title = models.CharField(max_length=120)
featured = models.BooleanField(default=False)
timestamp = models.DateTimeField(auto_now_add=True, auto_now=False)
updated = models.DateTimeField(auto_now_add=False, auto_now=True)
def __str__(self):
return self.title
view.py
from .models import Business, BusinessImage
def index_view(request):
latest_business_list = Business.objects.all()
images = latest_business_list.businessimage_set.all()
template = loader.get_template('index.html')
context = RequestContext(request, {
'latest_business_list': latest_business_list,
'images': images,
})
return HttpResponse(template.render(context))
index.html
{% block content %}
<div class="text-center business_title">
<h2>Featured</h2>
</div>
{% if latest_business_list %}
{% for business in latest_business_list|slice:":4" %}
{% if business.active %}
<div class="col-sm-6 col-md-3">
<li>{{ business.name }}</li>
{% for image in latest_business_list.businessimage_set.all %}
{% if image.featured %}
<a href="{% url 'single_product' product.slug %}">
<img src="{{MEDIA_URL}}{{image.image}}" alt="{{image}}">
</a>
{% endif %}
{% endfor %}
</div>
{% endif %}
{% endfor %}
{% endif %}
{% endblock %}
businessimage_set is an attribute of a Business instance, but you're trying to access it as an attribute of a queryset (i.e. list of businesses). If your goal is just to be able to access the images for each business in a template, you can leave out images entirely. Instead your template would have:
{% for image in business.businessimage_set.all %}
(Though look into prefetch_related for efficiency.)
Related
I am working on a To-do app. The individual to-dos reference a to-do list via a foreign key and the to-do lists reference a project via a foreign key.
I want the to-do's status to be set to true when clicked. I have seen some tutorials where this is done but I haven't been able to get this to work yet.
Here are the models:
class Project(models.Model):
title = models.CharField(max_length= 200)
description = tinymce_models.HTMLField()
status = models.CharField(max_length=20, choices=PROJECT_CHOICES, default="active")
date = models.DateTimeField(auto_now_add=True, null=True)
def __str__(self):
return self.title
def get_absolute_url(self):
return reverse ('project_detail', args=[str(self.id)])
class ProjectTodoGroup(models.Model):
title = models.CharField(max_length=250)
description = tinymce_models.HTMLField()
project = models.ForeignKey(Project, blank=True, on_delete=models.CASCADE, related_name='todo_group')
date = models.DateTimeField(auto_now_add=True, null=True)
def __str__(self):
return self.title
class ProjectTodo(models.Model):
title = models.CharField(max_length= 250)
notes = tinymce_models.HTMLField()
status = models.BooleanField(default=False)
projectgroup = models.ForeignKey(ProjectTodoGroup, blank=True, null=True, on_delete=models.CASCADE, related_name='todo_set')
date = models.DateTimeField(auto_now_add=True, null=True)
def __str__(self):
return self.title
The view:
model = ProjectTodo
fields = ['status']
def get_context_data(self, **kwargs):
# Call the base implementation first to get a context
context = super().get_context_data(**kwargs)
context['project'] = get_object_or_404(Project, id=self.kwargs.get('pk'))
return context
def get_success_url(self):
return reverse('company_project:todo_group_detail', args=[self.kwargs.get('pk'), (self.object.id)])
Everything I have tried to far with the view hasn't worked.
The template:
{% extends 'base.html' %}
{% load crispy_forms_tags %}
{% block content %}
<div class="section-container container">
<div class="todo-group">
<h2>{{ projecttodogroup.title }}</h2>
<p>{{ projecttodogroup.description | safe }}</p>
</div>
<div><b>Todos</b></div>
{% if projecttodogroup.todo_set.all %}
{% for todo in projecttodogroup.todo_set.all %}
<div class="todos" style="padding: 10px;">
{{ todo.title }}
</div>
{% endfor %}
{% else %}
<p>No Todos have been have been added yet.</p>
{% endif %}
<h1>Add Todo</h1>
<form action="" method="post">
{% csrf_token %}
{{ form.media }}
{{ form|crispy }}
<input type="submit" value="save">
</form>
</div>
{% endblock content %}
I have multiple users in my project
my models.py file is
class User(AbstractUser):
is_student = models.BooleanField(default=False)
is_teacher = models.BooleanField(default=False)
class Teacher(models.Model):
user = models.OneToOneField(User,on_delete=models.CASCADE,primary_key=True,related_name='Teacher')
name = models.CharField(max_length=250)
subject_name = models.CharField(max_length=250)
email = models.EmailField(max_length=254)
phone = models.IntegerField()
teacher_profile_pic = models.ImageField(upload_to="classroom/teacher_profile_pic",blank=True)
def __str__(self):
return self.name
class Announcement(models.Model):
title = models.CharField(max_length=30)
content = models.TextField()
date_posted = models.DateTimeField(default=timezone.now)
teacher = models.ForeignKey(Teacher, on_delete=models.CASCADE)
def __str__(self):
return self.title
If the logged in user is a teacher it is allowed to create an announcement
Now i want that only the teacher who posted the announcement should be able to see the delete button
My html file is
{% extends "classroom/base.html" %}
{% block content %}
<h1>Announcements</h1>
{% for announcement in announcements %}
<!-- starting loop (posts is keyword from view) -->
<div style="border-style: solid;">
{% if object.teacher.id == request.teacher %}
<div>
Delete
</div>
{% endif %}
<a class="mr-2">Posted by: {{ announcement.teacher }}</a>
<h2><a class="article-title">{{ announcement.title }}</a></h2>
<p class="article-content">{{ announcement.content}}</p>
</div>
{% endfor %}
{% endblock content %}
the if statement is supposed to be true if logged in teacher is the teacher who originally posted it. However the delete button is visible for every announcement
my views.py has
class AnnouncementListView(ListView):
context = {
'announcements' : Announcement.objects.all()
}
model = Announcement
template_name = 'classroom/all_announcements.html'
context_object_name = 'announcements'
Try using this.
{% if announcement.teacher.user == request.user %}
<div>
Delete
</div>
{% endif %}
Your models are a bit "unconventional".
However, this should work:
{% if announcement.teacher.user == request.user %}
...
{% endif %}
I'm having trouble rendering related objects in a template. I have a Page model, that has a ForeignKey relationship to itself to define parent-child relationships.
class Page(BaseModel):
title = models.CharField(
max_length=280,
blank=False,
null=False,
)
description = models.CharField(
max_length=280,
blank=False,
null=False,
)
slug = models.SlugField(
blank=False,
null=False,
)
is_home = models.BooleanField(
default=False,
)
is_parent = models.BooleanField(
default=False,
)
parent = models.ForeignKey(
'self',
on_delete=models.PROTECT,
default='Home',
blank=True,
null=True,
related_name='children',
)
content = RichTextField(
blank=False,
null=False,
)
def __str__(self):
return self.title
def get_absolute_url(self):
return reverse('page_detail', args=[str(self.slug)])
My views.py filters out non-parent pages:
class PageListView(ListView):
queryset = Page.objects.filter(is_parent=True, is_home=False)
template_name = 'pages/page_list.html'
context_object_name = 'page'
But when it comes to rendering 'child' objects in my template, I'm stuck. I've figured that I need a loop within a loop (first for parent pages, second for child pages per parent page), but can't get the second loop to work. Here was my latest attempt, which got me a "'Page' object is not iterable" error.
{% extends '_base.html' %}
{% block content %}
<div class="container">
{% for page in page %}
<p>{{ page.title }}</p>
{% for children in page %}
<p>{{ page.title }}</p>
{% endfor %}
{% endfor %}
</div>
{% endblock content %}
You can iterate over the manager constructed by the related_name:
{% block content %}
<div class="container">
{% for page in page %}
<p>{{ page.title }}</p>
{% for child in page.children.all %}
<p>{{ child.title }}</p>
{% endfor %}
{% endfor %}
</div>
{% endblock content %}
You can boost efficiency with a .prefetch_related(…) [Django-doc] clause:
class PageListView(ListView):
queryset = Page.objects.filter(
is_parent=True, is_home=False
).prefetch_related('children')
template_name = 'pages/page_list.html'
context_object_name = 'page'
I would furthermore advise not to create an extra field is_parent, since this is a form of data duplication. It turns out that keeping fields in sync, even on the same database, might be harder than what it appears to be at first sight. You can check if the object is a parent with:
class PageListView(ListView):
queryset = Page.objects.filter(
children__isnull=False, is_home=False
).distinct().prefetch_related('children')
template_name = 'pages/page_list.html'
context_object_name = 'page'
There is a model with three classes of category-subcategory-products
class Category(models.Model):
name_category = models.CharField(verbose_name = 'name cat', max_length = 100, null=True)
image = models.ImageField(null=True, blank=True, upload_to="media/", verbose_name='pic')
slug = models.SlugField(max_length=160, unique=True, null=True)
def __str__(self):
return self.name_category
class Subcategory(models.Model):
category = models.ForeignKey(Category, on_delete=models.CASCADE, verbose_name='категория', related_name='sub')
name_subcategory = models.CharField(verbose_name = 'name subcat', max_length = 100, null=True)
image = models.ImageField(null=True, blank=True, upload_to="media/", verbose_name='pic')
slug = models.SlugField(max_length=160, unique=True, null=True)
def __str__(self):
return self.name_subcategory
class Product(models.Model):
subcategory = models.ForeignKey(Subcategory, on_delete=models.CASCADE, verbose_name='категория',related_name='prod')
name_product = models.CharField(verbose_name = 'name product', max_length = 100, null=True)
image = models.ImageField(null=True, blank=True, upload_to="media/", verbose_name='pic')
price = models.IntegerField('price')
def __str__(self):
return self.name_product
views.py
class CategoryView(ListView):
"""all category"""
model = Category
class CategoryDetailView(DetailView):
"""all sub category"""
model = Category
class SubcategoryView(ListView):
"""all product"""
model = Subcategory
url.py
urlpatterns = [
path("", views.CategoryView.as_view()),
path('<slug:slug>/', views.CategoryDetailView.as_view(), name='category_detail'),
path('<slug:slug>/<slug:slug_sub>/', views.SubcategoryView.as_view(), name='subcategory_list'),
]
page template from which I go to the page with all products (category_detail.html)
{% extends 'base.html' %}
{% block content %}
<h2>{{ category.name_category }}</h2>
{% for sub in category.sub.all %}
{{sub.name_subcategory}}
<img src="{{sub.image.url}}" width="100px" height="100px">
{% endfor %}
{% endblock %}
page template (subcategory_list.html) with all products (here I did not write the output of the products because even the name of the subcategory is not transmitted)
{% extends 'base.html' %}
{% block content %}
{{sub.name_subcategory}}
{% endblock %}
I just can’t understand why it doesn’t display anything on the last page. Perhaps the problem is in the classes in views since previously tried to write only through functions
By default, on DetailView, Django sends an object to the context and therefore that's what you should access in your template. You can see it here
{% extends 'base.html' %}
{% block content %}
<h2>{{ object.name_category }}</h2>
{% for sub in object.sub.all %}
{{ sub.name_subcategory }}
<img src="{{ sub.image.url }}" width="100px" height="100px">
{% endfor %}
{% endblock %}
You also will need a SubCategoryDetailView if you want to see details of that. If you want to override how Django passes data to the context, you can declare context_object_name with whatever you like. Please also have a look here
I'm trying to set up magnific popup on django.
My goal is to have one main picture in the homepage overview gallery view, which when clicked, would open a popup with the related images from the same photoshoot i.e. images with the same ID or PK.
I tried to apply the following approach
but i just cannot get it to work, maybe someone could help me out in this
My models.py
class Item(models.Model):
name = models.CharField(blank=False, max_length=200)
category = models.ForeignKey(Category, blank=True, null=True, on_delete=models.SET_NULL)
order = models.IntegerField(blank=True, null=True)
active = models.BooleanField(blank=True, default=False)
objects = models.Manager()
class Meta:
verbose_name_plural = 'items'
def __str__(self):
return self.name
class ItemImage(models.Model):
image = ProcessedImageField(
blank=True,
null=True,
processors=[ResizeToFit(width=1680, upscale=False)],
format='JPEG',
options={'quality':90})
order = models.IntegerField(blank=True, null=True)
main = models.BooleanField(blank=True, default=False)
cover = models.BooleanField(blank=True, default=False)
item = models.ForeignKey(Item, related_name='items', blank=True, null=True, on_delete=models.SET_NULL)
objects = models.Manager()
class Meta:
verbose_name_plural = 'item images'
Views.py
def portraits(request):
port = ItemImage.objects.filter(item__category__slug='portraits', item__active=True, main=True,).order_by('item__order')
portall = ItemImage.objects.filter(item__category__slug='portraits', item__active=True).order_by('item__order')
context = {
'main_portraits': port,
'all_portraits': portall
}
return render(request, 'gallery/portraits.html', context)
and Template:
{% block content %}
<div class="grid">
{% for pic in main_portraits %}
<div class="item">
<div class="item">
<div class="outer-text">
<div class="text">
{{ pic.item.name }}
<p>Click to view gallery</p>
</div>
</div>
<a><img class="lazy" alt=""
sizes="(min-width:1400px) 1220px
(min-width:1000px) 1000px,
(min-width:500px) 700px,
(min-width:320px) 420px,
280px"
srcset="{{ pic.image_xs.url }} 280w,
{{ pic.image_s.url }} 420w,
{{ pic.image_m.url }} 700w,
{{ pic.image_l.url }} 1000w,
{{ pic.image_xl.url }} 1220w" />
</a> {{ pic.item.pk }}
</div>
<div class="lazy">
{% for p in all_portraits %}
{% endfor %}
</div>
</div>
{% endfor %}
</div>
{% endblock %}
I have set
z.item.pk
just as a test, to see if any of my manipulations result in the pk's to bunch up. For example the first for-loop returns a picture with PK "24", I need for the second for-lop to return only images with the same PK; and so for every image. I think the answer might be connected with _set.all function, just like in the related question above, but I cant seem to get it to work in my case. Feels like I'm missing something here.
current output:
<div class="grid">
<div class="item">
<div class="item">
<div class="outer-text">
<div class="text">
Palagā tītā
<p>Click to view gallery</p>
</div>
</div>
<a><img class="lazy" alt=""
sizes="(min-width:1400px) 1220px
(min-width:1000px) 1000px,
(min-width:500px) 700px,
(min-width:320px) 420px,
280px"
srcset="/media/CACHE/images/IMG_8329_3Vi8mYO_GD621ql/958ba5dbee5efe28fd2f5054b8f819e1.jpg 280w,
/media/CACHE/images/IMG_8329_3Vi8mYO_GD621ql/02d12ca7f0633fee2fc762cf96f7889e.jpg 420w,
/media/CACHE/images/IMG_8329_3Vi8mYO_GD621ql/ba5fa6633e92a288e3b2f47a713d64c2.jpg 700w,
/media/CACHE/images/IMG_8329_3Vi8mYO_GD621ql/fe0d559fef5b02434c43f841005d4961.jpg 1000w,
/media/CACHE/images/IMG_8329_3Vi8mYO_GD621ql/96d0e52dff14d1bc4b60bbec674565db.jpg 1220w" />
</a> 24
</div>
<div class="lazy">
</div>
</div>
You need prefiltered querysets containing the related images for every main image before handing over to the template.
def portraits(request):
ports = ItemImage.objects.filter(item__category__slug='portraits', item__active=True, main=True,).order_by('item__order')
for p in ports:
# You may not need the item__category__slug filter
# if there are only images of the same category
# associated with an item.
# Also, if you want to exclude the main image
# from the set of related images, you need to add the filter
# main=False
p.related_images = ItemImage.objects.filter(item__category__slug='portraits', item__id=p.item.id)
context = {
'main_portraits': ports,
}
return render(request, 'gallery/portraits.html', context)
Then you can loop over main_portraits in the template, and get the related images for each main image in a nested loop:
{% for mainp in main_portraits %}
{% for im in mainp.related_images %}
{# do something with the related images #}
{% endfor %}
{% endfor %}
You can break down the models like this it will make the querying easier.
# models.py
class Item(mdoels.Model):
name = models.CharField(blank=False, max_length=200)
category = models.ForeignKey(Category, blank=True, null=True, on_delete=models.SET_NULL)
...
display_image = models.ProcessedImageField(...)
class ItemImage(models.Model):
item = models.ForeignKey(Item, related_name='images', blank=True, null=True, on_delete=models.SET_NULL)
image = models.ProcessedImageField(...)
...
#views.py
def portraits(request):
items = Item.objects.filter(category__slug='portraits', active=True)
return render(request, 'gallery/portraits.html', context={items: items})
#template
{% for item in items %}
<h1> {{item.name}} </h1>
<img src={{item.display_image}} />
{% for item_image in item.images.all %}
<img src={{item_image.image}} />
{% endfor %}
{% endfor %}