Now that I've thought about it some more I'd like to suggest another solution using the Django contenttypes framework for generic relationships. I had not noticed before that you have 2 levels of inheritance (i.e. Asset->Picture->BackgroundImage). My previous answer would still work, but you'd have to add explicit links to the child models. This would allow you to cleanly have Asset
link to all your asset types and vice versa.
class Asset(models.Model):
user = models.ForeignKey(User, related_name = "user_objects")
likes = models.ManyToManyField(User, through="Like", related_name="Liked_user")
comments = models.ManyToManyField(User, through="Comment", related_name="Commented_user")
timestamp = models.DateTimeField(auto_now = True, auto_now_add= False)
updated = models.DateTimeField(auto_now = False, auto_now_add = True)
content_type = models.ForeignKey(ContentType)
object_id = models.PositiveIntegerField()
content_object = generic.GenericForeignKey('content_type', 'object_id')
class Meta:
ordering = ['-timestamp']
def __unicode__(self):
return self.__class__.__name__
class Like(models.Model):
asset = models.ForeignKey(Asset)
liked_by = models.ForeignKey(User)
liked_time = models.DateTimeField(auto_now = True, auto_now_add = False)
def __unicode__(self):
return "%s likes %s" % (self.liked_by, self.asset)
class Comment(models.Model):
asset = models.ForeignKey(Asset)
comment_by = models.ForeignKey(User)
liked_time = models.DateTimeField(auto_now = True, auto_now_add = False)
def __unicode__(self):
return "%s likes %s" % (self.comment_by, self.asset)
def get_upload_file_name(instance, filename):
return "uploaded_files/%s_%s" %(str(time()).replace('.','_'), filename)
class AlbumAsset(models.Model):
title = models.CharField(max_length=200)
description = models.TextField()
asset = generic.GenericRelation(Asset)
def __unicode__(self):
return self.__class__.__name__
class PictureAssetBase(models.Model):
description = models.TextField()
image = models.ImageField(upload_to=get_upload_file_name)
album = models.ForeignKey(Album, null=True, blank=True, default = None)
asset = generic.GenericRelation(Asset)
def __unicode__(self):
return self.__class__.__name__
class Meta:
abstract = True
class PictureAsset(PictureAssetBase):
pass
class BackgroundImageAsset(PictureAssetBase):
pass
class ProfilePictureAsset(PictureAssetBase):
pass
class Tag(models.Model):
title = models.CharField(max_length=40)
description = models.TextField()
def __unicode__(self):
return self.title
class QuestionAsset(models.Model):
title = models.CharField(max_length=200)
description = models.TextField()
tags = models.ManyToManyField(Tag)
asset = generic.GenericRelation(Asset)
def __unicode__(self):
return self.title
class AnswerAsset(models.Model):
description = models.TextField()
question = models.ForeignKey(Question)
asset = generic.GenericRelation(Asset)
def __unicode__(self):
return self.description
Notice the content_object
field in Asset
. I also suggest that you make an ABC for pictures PictureAssetBase
(notice abstract=True
as explain in the docs here) and have PictureAsset
, BackgroundImageAsset
& ProfilePictureAsset
inherit from that.
All asset type models have a reverse relation to Asset
via GenericRelation
. This way you're free to add new asset types with minimal impact to other models. In your Views etc. you will obviously need to provide special handling for each type, but you can determine the linked asset type via the content_type field in Asset
, or add an explicit type field and handle it yourself.