Liondancer
Liondancer

Reputation: 16469

displaying all images from directory Django

I am not sure how to display images from a directory onto a page. I am trying to create a gallery app. I am I am trying to do this bit by bit. My goal would be to create a thumbnail (first image of photos) for the album. When the album is clicked, all the images should be displayed. I think this would be done with an AJAX request. Not quite sure as I am new to web development. I need some help setting this up.

structure of images:

/gallery
   /static
      /images
         /album1
            img1
         /album2
            img2
         ...etc

I'm not sure how to get these images in my views.py and display them on an html page.

Here is the models.py I came up with but probably needs more work:

class Album(models.Model):
    title = models.CharField(max_length = 60)
    def __unicode__(self):
        return self.title

class Image(models.Model):
    title = models.CharField(max_length = 60, blank = True, null = True)
    tags = models.ManyToManyField(Tag, blank = True)
    albums = models.ManyToManyField(Album, blank = True)
    width = models.IntegerField(blank = True, null = True)
    height = models.IntegerField(blank = True, null = True)

I feel I might be missing some things in my Image class such as ImageField or FileField but I am putting the files in the directory manually so I'm not sure if there are required.

Upvotes: 1

Views: 5841

Answers (2)

Dr.Elch
Dr.Elch

Reputation: 2225

At this stage it is not quite possible to answer your questions in a whole, but let's see.

A: Directories and file organization

It isn't clear yet how your directory structure resembles your models.

Your images have a N:M Relationship with albums. That is ok so far. What's confusing is your structure of images.

The structure looks like a 1:1 Relationship of images and albums. Does this result in duplicate files if an image belongs to multiple albums?

So one thing you need to solve first: How are images organized on your hard drive?

B: Finding files and creating a URL from it

Now we need to find a way to find the path to your image files. We assume, your files reside on the same machine as your django application, so we can use local paths. If your pictures were in a different location like AWS, you would be required to provide a different mechanism to get the picture url.

Once you have sorted it out you can write a model method for your image model to retrieve the image path. A trivial approach would be that your title is a unique field and does equal your image file name, which had to be unique as well. I'll promise you, this will only work with hashed filenames or very strange filename conventions you had to make up on your own when files are uploaded to your gallery. Of course there are other options to ensure you get the right file, but let's keep things simple, just something to keep in mind.

C: Some example Code

Alright, let's write some code. This is just a contrived example, that wants to explain the basic idea. Some more information about directory traversal can be found here: Looking for File Traversal Functions in Python that are Like Java's

#models.py

import os
from os.path import join

class Image(models.Model):

def get_image_path(self):
    for root, dirs, files in os.walk('<parents of gallery>/gallery/static/images/<album_if_required>'):
       #debug information, just to get an idea how walk works.
       #currently we are traversing over all files with any extension
       print "Current directory", root
       print "Sub directories", dirs
       print "Files", files

       for file in files:
        if file.startswith(self.title):
            #now we have found the desired file.
            #value of file: "myimagetitle.jpg" <-- no path info
            #value of root: "/home/yourhome/gallery/static/images/myalbum"
            #we want to use this information to create a url based on our static path, so we need only the path sections past "static"
            #we can achieve this like so (just one way)
            mypath = os.sep.join(os.path.join(root, file).split(os.sep)[4:])

            #yields: /images/myalbum/myimagetitle.jpg

            return mypath

great, now we have a path we can use in our template with static as base.

#template.html
<!-- fancy html stuff goes here -->
<img src="{static myimage.get_image_path}">
<!-- more html -->

D: Explanation of the code

I think some parts of this code require explanation.

os.walk is a generator method that will traverse the path you pass to it. It will return the path to the current node it looks at (root) and what subdirectories (dirs) and files (files) you can find underneath. You can remove nodes or node pattern from the tree, hence you can filter on certain objects. But this would go to far right now.

Once we have found a candidate for our file, we need to build a path we can use in our application. The HTML template can't use the physical location of the file, so we need to transform it into a URL. You will have to know what your url scheme will be like. I assumed you rely on static folders.

URL creation happens here:

os.sep.join(os.path.join(root, file).split(os.sep)[4:])

let's look at it in parts:

  1. os.path.join(root, file) #join the root path and the file name for one long string

  2. .split(os.sep)[4:] #get the substring of the path. We split the path by the directory separator char which is os dependent. This will return a list. We only want the elements under the "static" part, in my example this resulted in element 4 of the list

  3. os.sep.join(...) # last but not least we have to build a string again. So we join all list elements with the directory separator, yielding '/images/myalbum/myimagetitle.jpg'

So as you can see, this is just one possible way to achieve what you want. If you provide more information about how your files are organized, I'm sure we can find a much better way. Please not the code above is not ready for production!

Upvotes: 5

mdargacz
mdargacz

Reputation: 1379

In Django you should use ImageField and define function that will generate "upload_to" parameter for your image :

def images_upload_to(instance, filename):
    return '/'.join(['images', instance.album.title])

class Image(models.Model):
    title = models.CharField(max_length = 60, blank = True, null = True)
    tags = models.ManyToManyField(Tag, blank = True)
    albums = models.ForeignKey(Album, blank = True)
    img = models.ImageField(upload_to=images_upload_to,null=True,blank=True)

demensions of image you can access in template by {{ image.img.height }} and {{ image.img.width }}

In this solution you cant use ManyToManyField to albums, becouse your directory structure is opposing it. If you wish to use ManyToManyField your images_upload_to function can't/shouldn't generate directory path based on one album. And in the first place, gallery images shouldn't be stored in static directory, but in media. Static files are are meant for js/css/images etc, that by definition are 'static' and won't change, but media files are for user-uploaded content.

Upvotes: 1

Related Questions