How to deal with a previous model to display existing images

The title of the topic isn’t really satisfying but I couldn’t find anything better for now :slight_smile:

Following my recent questions regarding the app I’m building on top of a legacy database, I now have to deal with images upload and storage.

The database was designed to serve a first version of the app, on totally different technologies (Silverlight). There is a principal table called objetarchi, and many secondary tables connected to objetarchi with foreign keys. I’ve migrated the base to PostgreSQL/PostGIS.

For every object in objetarchi, the web app displays a description of the object, including fields coming both from the main table or from the secondary ones.

There was also the possibility to upload various images for one object. There’s a table called images with a field called link that contains the name of the image with its extension (eg “image.jpg”) and a ForeignKey field that points to objetarchi.

I retrieved all the images and put them inside media/images/, and declared MEDIA_URL and MEDIA_ROOT in settings.py.

I’d like to :

  • in the admin, give the ability to users to upload one or several images for every new object created in objetarchi;
  • on the public page, display the images on their objects pages, including the old ones.

How could I do this?
I tried various approaches but I’m kind of stuck here, mostly for the existing images. Any new idea greatly appreciated!

Actually, you probably should be using a FileField object.

Sounds like a job for an InlineModelAdmin to insert multiple images on your objectarchi ModelAdmin page.

Have you (or are you) going to create images instances for those old pictures?

1 Like

Could you elaborate? Not sure to understand what are instances here.

You mentioned you have a table named images to contain the references to pictures.
Have you already, or are you going to, create rows in the images table for each of the old (pre-existing) pictures?

OK, I got it!
Yes, rows already exist for every pre-existing picture. I’d like to keep this as is and not lose the information.

Hi,

I managed to implement the InlineModelAdmin in the admin area, and see the images already referenced in the database. However, I am struggling to display these images in my detail.html template.

Here is the code:

  • settings.py:
BASE_DIR = Path(__file__).resolve().parent.parent
MEDIA_URL = 'media/'
MEDIA_ROOT = os.path.join(BASE_DIR, 'media/')
  • views.py:
class DetailView(generic.DetailView):
    model = ObjetArchi
    template_name = 'notices/detail.html'
  • detail.html:
{% for object in 'object.images' %}
<img src="{% get_media_prefix %}{{ object.images.image }}"/>
{% endfor %}

(image being the name of the ImageField on the Images table)

I tried various values after get_media_prefix but none seems to work. It’s definitely not object.images.image. I understand that views.py loads the ObjetArchi model, but I’m not sure what to write in the template to indicate "display every images present in the Images table related to ObjetArchi".

Any indication will be greatly appreciated! And once again, thanks a lot for the support :slight_smile:

To recap and confirm my understanding - Images (the model) has an fk to ObjetArchi.

So, for a given ObjetArchi, let’s call it object, the set of images associated with it would be object.images_set.all. (A reverse fk reference set)

So, if you’re looking to iterate over that set, it would be something like:
{% for image in object.images_set.all %}
Within that loop, image is then a reference to one instance of Images.

Ken,

That’s correct.

So, for a given ObjetArchi, let’s call it object, the set of images associated with it would be object.images_set.all. (A reverse fk reference set)
So, if you’re looking to iterate over that set, it would be something like:
{% for image in object.images_set.all %}
Within that loop, image is then a reference to one instance of Images.

OK! Thanks, that clears the loop part :slight_smile:

Then I’m struggling with the URL to indicate in the img tag.

I’m trying to get the URLs as following: https://mysite.com/media/img/photo.jpg, where:

  • https://mysite.com/media is defined as MEDIA_ROOT in settings.py, so I assume I can use {% get_media_prefix %}
  • photo.jpg is extracted from the ImageField in Images model (The ImageField is called… image. My bad for the ambiguous names!)

So something like this should work:
<img src="{% get_media_prefix %}img{{ ??? }}"/>
I just can’t figure out how to pass the name of the ImageField at the end of the line…

I think you want to look at the url property. If everything’s configured correctly, it should return the appropriate url. Otherwise, you might be able to make something work using the name property. (Also see the docs at Model field reference | Django documentation | Django)

1 Like

Well, I got carried away: the loop part doesn’t work. It seems to fail silently so it’s hard to understand what doesn’t work. :confused:

I don’t really know what to do right now - apart from taking a break!

It’s frequently helpful to me to try different things in the shell.

You could do something like:

o = ObjetArchi.objects.get(<something to identify an instance>)
images = o.images_set.all() 
# Note, using "images_set" assumes no "related_name" was defined in the FK definition.
for i in images:
  print(i.pk, i.name, i.url)

just to see what you get.
Any errors showing up will help identify the source of any problems.

Yes I was precisely trying things in the shell!

And there might be an elephant in the room, I was just wondering about it as you answered:

using "images_set" assumes no "related_name" was defined in the FK definition.

I did define it as images_objet_archi

So I’ll try again in the shell and report here :slight_smile:

Edit: loop is working \o/

…So loop is working now, and the images are visible too:

{% for image in object.images_objet_archi.all %}
<img src="{% get_media_prefix %}{{ image.image.name }}">
{% endfor %}

Or

{% for image in object.images_objet_archi.all %}
<img src="{{ image.image.url }}">
{% endfor %}

The second proposition is shorter and looks more elegant, so I’m probably gonna stick with it.
It always seems obvious once it’s done.

Thanks again for you help Ken!