Question on filtering images tied to a post

I am unable to filter images which are tied to a particular post.
As you can see in the code below, I have a foriegnkey called post in my image model. I am able to upload lumtiple images from the admin page without issues. But when I call these image objects in my views.py as shown below, the page breaks into error.

In view.py if I use Image.objects.all() instead of Image.objects.get(blogpost=pk)

#models.py
class BlogPost(models.Model):
title = models.CharField(max_length=255)
body = models.TextField()
created_on = models.DateTimeField(auto_now_add=True)
last_modified = models.DateTimeField(auto_now=True)
categories = models.ManyToManyField(‘Category’, related_name=‘posts’)

class Image(models.Model):
image = models.ImageField(upload_to=‘images/’)
content_type = models.ForeignKey(ContentType, on_delete=models.CASCADE)
object_id = models.PositiveIntegerField()
content_object = GenericForeignKey(“content_type”, “object_id”)
post = models.ForeignKey(‘BlogPost’, on_delete=models.CASCADE)

#views.py
def blog_detail(request, pk):
blogpost = BlogPost.objects.get(pk=pk)
myimages_objs = Image.objects.get(blogpost=pk)

#blogdetail.html
{% for item in myimages_objs %}
image
{% endfor %}

What am I doing wrong? Please advise.
Instead of the Foreignkey for the “post” attribute inside the “Image” model, should I try using the manytoone key? My idea is each of the images that are uploaded need to be tied to that post only.

Just at first glance, your code Image.objects.get(blogpost=pk) is not correct

You should be able to use myimages_objs = blogpost.image_set.all() instead

When you create a relationship with ForeignKey, Django will automatically set up a “related manager” for the other side of the relationship using the modelname_set syntax. You might find this section of the Django documentation helpful: https://docs.djangoproject.com/en/3.0/ref/models/relations/

If that doesn’t fix your issue, post the error message you are getting and I can try and help further.

Hi @jimwritescode thanks for the response. I get this error:
AttributeError: type object ‘BlogPost’ has no attribute ‘image_set’

I am using python 3.7 & Django 3.0.6

def blog_detail(request, pk):
   blogpost = BlogPost.objects.get(pk=pk)   
   myimages_objs = blogpost.images.get()

MultipleObjectsReturned at /myblog/1/

get() returned more than one Image – it returned 2!

Request Method: GET
Django Version: 3.0.6
Exception Type: MultipleObjectsReturned
Exception Value: get() returned more than one Image – it returned 2!
def blog_detail(request, pk):
    blogpost = BlogPost.objects.get(pk=pk)
    myimages_objs = blogpost.image_set.all()

AttributeError at /myblog/1/

‘BlogPost’ object has no attribute ‘image_set’

Request Method: GET
Django Version: 3.0.6
Exception Type: AttributeError
Exception Value: ‘BlogPost’ object has no attribute 'image_set
def blog_detail(request, pk):
    blogpost = BlogPost.objects.get(pk=pk)
    myimages_objs = blogpost.images.all()



{% if blogpost.image %}
        {% for item in myimages_objs %}
           <img src="{{ item.image.url }}" alt="image" style="width: 50%; height: auto;" />
        {% endfor %}
{% endif %}

With the above code, I get the page displayed, but there are no images displayed.

When you say that there are no images displayed, are you saying that the HTML for the images isn’t being rendered, or that the images themselves aren’t showing up on the page?

Also, have you verified in the database that the ForeignKey field in Images is being populated correctly?

(It’s possible that you’re dealing with a data issue here and not a template rendering issue.)

@KenWhitesell thanks for the response. The html is rendering fine. But images are not being displayed. I have two images uploaded from the admin page. I can see the images in the media folder after the sucessful upload.

def blog_detail(request, pk):
    blogpost = get_object_or_404(BlogPost, pk=pk)

I tried modiyfing code. Issue remains the same. The blog detail html page is endering fine, but no images are displayed.

   <div class="divi">
        {% if blogpost.image %}
                {% for item in blogpost.images %}
                   <img src="{{ item.image.url }}" alt="image" style="width: 50%; height: auto;" />
                {% endfor %}
        {% endif %}
    </div>

there are two images uploaded in my test blog page. i verified the images are loaded correctly in the media/images folder.

What do you mean the “blog detail html page is rendering fine”? Are you saying that the img tags are being rendered? If so, can you actually post the html showing that the src attributes are correct?

@KenWhitesell As you can see above in the html page, a # symbol shows up where the images are supposed to be displayed.

Can you please post the actual html being rendered? It looks like the src attribute isn’t being properly populated, which would imply a data error, so you should confirm that the url attribute is right.

Hi @KenWhitesell I am not sure how to post the html being rendered. Above I have posted a screenshot of the html page. Is that what you are referring to?

How do I verify if the src atribute is or isnt being properly populated? Thanks.

I am not sure how to post the html being rendered. Above I have posted a screenshot of the html page. Is that what you are referring to?

How do I verify if the src atribute is or isnt being properly populated? Thanks.

You need to use tools in your browser to inspect the HTML. In e. g. Firefox you can go to the menu at the top right, click “Web Developer” in the dropdown menu, then “Page source”. This should let you see the whole page’s HTML. You can then share the HTML here, preferably formatted by putting ``` in the line directly preceding the HTML code as well as the line directly following the HTML code,

# So that the HTML is presented like this, making it easier to read.

You can also right-click an object, e. g. the area where the image should appear, in Firefox and select “Inspect element” in the dropdown menu. That will lead to a subwindow popping up at the bottom of your browser. You should see an <img src=“…” …> tag somewhere there. What value is ‘src’ set to?

I think you might be having trouble related to where/how media is stored and at what URL it can be accessed. Maybe this page could help? :slight_smile: https://matthiasomisore.com/web-programming/display-image-in-a-django-template-using-imagefield/

2 Likes

Hi @datalowe
thanks for the details.
When I tried a static image, the picture rendered fine without issues.
But, when I tried object.image.url style, as you can see below page source that there is no src link shown.

<div class="col-md-8 offset-md-2">
    <h1>first post title</h1>

    <small>
        May 24, 2020 |&nbsp;
        Categories:&nbsp;

        
        <a href="/myblog/general/">
            general
        </a>&nbsp;
        

    </small>

    <br clear="all" />

    <p>first post body</p>
    <br clear="all" />

    <img src="" >
<!--    <img src="/static/images/sto-pho-195123.jpg" alt="Django Photo Gallery" class="opaque">-->

corresponding html code is:


    <img src="{{ blogpost.image.url }}" >
<!--    <img src="{% static 'images/sto-pho-195123.jpg' %}" alt="Django Photo Gallery" class="opaque">-->


1 Like

I almost hate to ask this, but we’ve been through many iterations to get to this point, and I can’t be sure any more what the status is of the various components involved. Please (re)post the current models, views, template, and your MEDIA_ROOT settings.

Also, as a general rule, when I’m trying to debug a template like this, I either change my template to just output the text, use the Django Debug Toolbar to help understand the context being rendered, or just use the shell to help me understand what’s going on.

For examples:

  1. Instead of rendering the urls as part of an image tag, I might change my template to be something like this:
<div class="divi">
        {% if blogpost.image %}
                <hr>
                {% for item in blogpost.images %}
                   {{ item }}<br>
                   {{ item.image }}<br>
                   {{ item.image.url }}<br>
                   <hr>
                {% endfor %}
        {% endif %}
    </div>

The whole idea here is just to give me more usable information - and it’s quicker/faster/easier than installing Django Debug Toolbar if it’s not already installed and configured.

  1. Or, from within the Django shell (I always use Django extensions and shell_plus)
blogpost = BlogPost.objects.get(pk=1)
images = blogpost.image_set.all()

for i in images:
    print(i)
    print(i.image)
    print(i.image.url)

The idea behind all this is to follow the process from beginning to end to see what is failing. Once you know where it has stopped working, then you can figure out why it stopped working and fix it!

1 Like

Like @KenWhitesell writes, it’s a bit hard to follow what is going on with your models, views etc. (e. g. in your description of the models, you seem to reference a “Category” model, but it’s not described), and hence what’s causing the behavior you see. Before writing my first reply I actually tried to recreate your project just to understand how everything was linked, and for my own practice. I don’t understand it all myself but at least I got it to work. I’ve now uploaded the project as a github repo, maybe comparing what you’ve done to it might help?

Thanks. Using the Django shell for torubleshooting is a great idea.

>>> from myblog.models import BlogPost
>>> BlogPost.objects.all()
<QuerySet [<BlogPost: BlogPost object (3)>]>

>>> blogpost = BlogPost.objects.get(pk=3)
>>> images = blogpost.images.all()
>>> for i in images:
...     print(i)
...     print(i.image)
...     print(i.image.url)
... 
Image object (5)
images/flowers-garden-colorful-colourful.jpg
/media/images/flowers-garden-colorful-colourful.jpg
Image object (6)
images/sto-pho-195123.jpg
/media/images/sto-pho-195123.jpg

The two images that I had uploaded from the admin page of the blog are listed above using the django shell queryset sucessfully. This means that the images are correctly associated withe corresponding blogpost pk=3.

So far so good.

Now I copied the above statements into the views.py as shown below:

#views.py
def blog_detail(request, pk):
    blogpost = BlogPost.objects.get(pk=pk)
    images = blogpost.images.all()

the html code is as below:

#blog_detail.html

    <div class="divi">
        {% for item in images %}
            <img src="{{ item.image.url }}">
        {% endfor %}
    </div>

on the html page rendering I see the below:

    <div class="divi">
            <img src="/media/images/flowers-garden-colorful-colourful.jpg">
            <img src="/media/images/sto-pho-195123.jpg">
    </div>

So far so good!
Pictures are rendering fine now!
Thanks again for the guidance. Very informative.