Reputation: 2423
I need to understand a bit better how do FK/m2m relationships work. I've prepared Images model for uploading images and it has an additional feature - it can be categorized by adding to a specific gallery (m2m relation to gallery).
To access gallery name I just had to do a query set for example:
Images.objects.filter(gallery__gallery_name = '')
I'd like to reverse the query a little bit so from Gallery model I can access pictures which are in specific gallery (gallery_name).
How I can do that?
Models:
class Images(models.Model):
image = models.ImageField(upload_to=update_filename, blank=True, null=True, verbose_name="Obrazek")
gallery = models.ForeignKey('Gallery', blank=True, null=True)
class Gallery(models.Model):
gallery_name = models.CharField(max_length=128)
gallery_description = models.TextField(blank=True, null=True)
View:
def index(request):
p = Gallery.objects.filter(gallery_name="main").order_by('-id')
return TemplateResponse(request, 'gallery.html',
{'gallery': p,
},)
Template:
{% for n in gallery.all %}
<h2 class="center">{{n.gallery_name}}</h2>
<hr>
{% for n in gallery.images_set %}
<div class="grid_4">
{{ n.image }}
</div>
{% endfor%}
Upvotes: 1
Views: 335
Reputation: 13164
Try something along the lines of:
# models.py
class Gallery(models.Model):
name = models.CharField(max_length=30)
description = models.CharField(max_length=200, null=True)
images = models.ManyToMany(Image)
class Image(models.Model):
title = models.CharField(max_length=30)
caption = models.CharField(max_length=200, null=True)
image = models.ImageField(upload_to=SOMEPLACE_FOR_MEDIA)
From here you should be able to do things like:
image = Image.objects.get(title="Girl Holding Cheese")
related_galleries = image.gallery_set.all()
or something similar as needed to pull what you want. The same goes the other way. To pull all images in a gallery you would do
gallery = Gallery.objects.get(name="Cheesy Wimmin")
related_images = gallery.images.all()
Though the assignments at the end aren't necessary, I usually just pass gallery.images.all() or image.gallery_set.all() directly. Note the "_set" at the end of the reference from the object that does not contain the M2M definition.
On the subject of direct usage, you can do compound references like
Image.objects.get(title="Girl Holding Cheese").gallery_set.all()
as well, but you have to decide when this makes code more clear and concise and when it just makes it more confusing to read later.
I hope this put you in the right direction.
In your comment below you noticed that you cannot do
images = Images.objects.filter(gallery_set="Cheesy Wimmins")
related_galleries = images.gallery_set.all()
This is because you would be trying to filter() or all() on a queryset, not an individual model. So to make this work you can use a for loop in your template. Something like
# views.py
galleries = Gallery.objects.all()
return render(request, 'some/template.html', {'galleries': galleries})
And then
<!-- templates/some/template.thml -->
{% for gallery in galleries %}
<div class="gallery">
<h2>{{ gallery.name }}</h2>
{% for item in gallery.images.all %}
<div class="image">
{{ item.image }}
</div>
{% endfor %}
</div>
{% endfor %}
or something like this. Of course, you need to do whatever formatting steps you want to make this look right, but that's a way to get at your data.
Upvotes: 1
Reputation: 118538
gallery
is a QuerySet
- it doesn't have a images_set
.
This is where naming your variables more appropriately can easily start preventing these problems: for example, galleries
would be more appropriate for a list of Gallery objects... then, galleries.images_set
would immediately raise red flags.
Anyways, you need to call images_set
on what you've called n
{% for n in gallery.all %}
<h2 class="center">{{n.gallery_name}}</h2>
<hr>
{% for n in n.images_set.all %}
<div class="grid_4">
{{ n.image }}
</div>
{% endfor%}
Upvotes: 1
Reputation: 239460
The problem is with the {% for n in gallery.images_set %}
bit in your template. images_set
is a related manager, not a queryset. To get a queryset, you need to call all
or another of the DBAPI methods that return querysets. So, just change it to gallery.images_set.all
, and you're good.
Upvotes: 1