Aamu
Aamu

Reputation: 3601

django - Get a set of objects from different models field names

Please have a look at my models.

class BackgroundImage(models.Model):
    user = models.ForeignKey(User)
    image = models.ImageField(upload_to=get_upload_file_name)
    caption = models.CharField(max_length=200)
    pub_date = models.DateTimeField(default=datetime.now)

class ProfilePicture(models.Model):
    user = models.ForeignKey(User)
    image = models.ImageField(upload_to=get_upload_file_name)
    caption = models.CharField(max_length=200)
    pub_date = models.DateTimeField(default=datetime.now)

class Album(models.Model):
    user = models.ForeignKey(User)
    name = models.CharField(max_length=200)
    pub_date = models.DateTimeField(default=datetime.now)

    class Meta:
        ordering = ['-pub_date']
        verbose_name_plural = ('Albums')

    def __unicode__(self):
        return self.name

class Photo(models.Model):
    user = models.ForeignKey(User)
    album = models.ForeignKey(Album, default=3)
    image = models.ImageField(upload_to=get_upload_file_name)
    caption = models.CharField(max_length=200)
    pub_date = models.DateTimeField(default=datetime.now)

How do I get all the images of Photo, ProfilePicture and BackgroundImage from their image field in one set. And then filter them by -pub_date to display in the template? Please help me out. Will be much much appreciated! Thank you.

Edit

N.B: I need ProfilePicture and BackgroundImage to work with the UserProfile like this:

from django.db import models
from django.contrib.auth.models import User
from profile_picture.models import ProfilePicture
from background_image.models import BackgroundImage

class UserProfile(models.Model):
    user = models.OneToOneField(User)
    permanent_address = models.TextField()
    temporary_address = models.TextField()
    profile_pic = models.ForeignKey(ProfilePicture)
    background_pic = models.ForeignKey(BackgroundImage)

    def __unicode__(self):
        return self.user.username

User.profile = property(lambda u: UserProfile.objects.get_or_create(user=u)[0])

Upvotes: 2

Views: 954

Answers (1)

Henry Florence
Henry Florence

Reputation: 2866

There is an InheritanceManager provided as part of django-model-utils which allows you to do this, see docs.

To install in Linux / Mac:

sudo pip install django-model-utils

Annoyingly, installing using easy_install or pip on windows is not quite as straight forward, see: How do I install Python packages on Windows?. A quick and dirty method is to download the django-model-util/ directory from here into the top directory of your django project, this is handy if you intend to copy the entire project across for deployment to a production webserver.

In order to use the InheritanceManager, the models need to be refactored slightly:

from django.db import models
from django.contrib.auth.models import User
from datetime import datetime
from model_utils.managers import InheritanceManager

get_upload_file_name = 'images/' # I added this to debug models

class BaseImage(models.Model):
    user = models.ForeignKey(User)
    image = models.ImageField(upload_to=get_upload_file_name)
    caption = models.CharField(max_length=200)
    pub_date = models.DateTimeField(default=datetime.now)

    objects = InheritanceManager()

class BackgroundImage(BaseImage):
    pass

class ProfilePicture(BaseImage):
    pass

class Album(models.Model):
    user = models.ForeignKey(User)
    name = models.CharField(max_length=200)
    pub_date = models.DateTimeField(default=datetime.now)

    class Meta:
        ordering = ['-pub_date']
        verbose_name_plural = ('Albums')

    def __unicode__(self):
        return self.name

class Photo(BaseImage):
    album = models.ForeignKey(Album, default=3)

All the Image models now inherit from a common super class which creates an instance of the InheritanceManager. I've also moved up all the duplicated attributes into the superclass, but this isn't strictly necessary, using InheritanceManager means that any attributes which are not present in BaseImage can still be accessed in the template.

To retrieve a list ordered by -pubdate:

BaseImage.objects.select_subclasses().order_by("-pub_date")

To use in a view:

def recentImages(request):
    r = BaseImage.objects.select_subclasses().order_by("-pub_date")[:20]
    return  render_to_response("recentImages.html", { "imageList" : r })

To use in a template:

{% for photo in imageList %}
  <img src="{{ photo.image.url }}" />
{% endfor %}

Is this something like what you are looking for?

Edit

The following code will still work fine, with the new models:

class UserProfile(models.Model):
    user = models.OneToOneField(User)
    permanent_address = models.TextField()
    temporary_address = models.TextField()
    profile_pic = models.ForeignKey(ProfilePicture)
    background_pic = models.ForeignKey(BackgroundImage)

Just make sure the names of the last two models in the ForeignKey relationship are correct!

Upvotes: 4

Related Questions