简体   繁体   中英

Creating a model related to an arbitrary number of other models

I deleted my previous question, since it was terribly worded and my non-working examples were just confusing.

I have a series of models, such as Vehicle , Computer , Chair , and whatnot. My goal is to be able to attach an arbitrary number of images to each of them. That's my question: what's the best design pattern to achieve this?

What I've tried so far is to create an abstract model, AttachedImage . I then inherit from this model, and create more specific models, like VehicleImage , ComputerImage , or ChairImage . But this doesn't feel like the right way to pursue this.

As I mentioned in the comment on the deleted question, the correct way to do this would be to use generic relations .

Make your AttachedImage model concrete, but add content_type and object_id fields and the content_object GenericForeignKey. That content_object field can now point to an instance of any model.

To make the reverse relationships easier, you can add GenericRelation accessors to your Vehicle, Computer and Chair models.

If you don't want to use the GenericForeignKey, you can implement your own polymorphic models, with multiple table inheritance. Following are the pseudo-models for the same:

class Attachable(models.Model):
    pass

class Image(models.Model):
    attachable = models.ForeignKey(Attachable, related_name='images')

class Video(models.Model):
    attachable = models.ForeignKey(Attachable, related_name='videos')


class Vehicle(Attachable):
    vehicle attrs...

class Computer(Attachable):
    computer attrs... 

class Chair(Attachable):
    chair attrs...   

For later optimizations, Attachable can also have an attribute which describes its subtype.

Thanks to Daniel Roseman's, I found out about generic relationships . You can find a great overview and tutorial about them here . There are basically two ways to achieve this.

The first one is using generic relationships as explained in the tutorial I linked. This system is very versatile and powerful, but in my case, this would add an additional layer of complexity that quite frankly I don't need.

If you're a newbie with Django like I am, you can consider a much more straightforward, but less 'systematic' pattern, also detailed in that tutorial I linked: simply add a ForeignKey field for each one of the objects you want your main model to be related to. Following the example I used in my question:

class AttachedImage(models.Model):
    uuid = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
    author = models.ForeignKey(User, on_delete=models.CASCADE)
    image = models.ImageField(upload_to=image_path)  # TO FIX: añadir la ruta
    is_default = models.BooleanField(default=False)

To this, you just add fields for the relationships you will need, such as:

parent_vehicle = models.ForeignKey(Vehicle, on_delete=models.CASCADE, null=True)
parent_computer = models.ForeignKey(Computer, on_delete=models.CASCADE, null=True)
parent_chair = models.ForeignKey(Chair, on_delete=models.CASCADE, null=True)

And just use them as you regularly would. The downside is ending up with all those extra fields you don't really need, but being NULLable, they won't take up much space. The other downside is that doing this with a big number of models is probably overkill, in which case you should really use the first solution.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM