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 thumb
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:
os.path.join(root, file)
#join the root path and the file name for one long string
.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
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!
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.