sgarza62
sgarza62

Reputation: 6238

Django: ManyToMany with ability to order AND to add/remove relationships?

I am building a web application that allows users to have a photo library, filled with photo objects, which they can put into photo albums. They can do the following:

Originally, I had thought to write the models something like this (simplified):

def Photo(models.Model):
    user = models.ForeignKey(User)
    img_file = models.ImageField(upload_to = img_get_file_path)
    upload_date = models.DateTimeField(auto_now_add = True)


def Album(models.Model):
    title = models.CharField(max_length = 50, required = False)
    cover_img = models.ForeignKey(Photo)
    album_contents = models.ManyToMany(Photo)

#  a user's "photo library" isn't defined in a model, but 
#  rather by running the query: 
#  Photo.objects.filter(user = request.user).order_by('upload_date')

This simple approach would have worked great, except that users can't change the order of the photos in their album (ManyToMany relationships aren't ordered). I've searched for a solution to this, and everyone's pointing to using intermediate models, using the through statement:

The intermediate model approach would work in ordering the photos in the album, but not in removing photos from an album. Intermediate models don't support .add(), .create(), .remove(), or assignment. They only support the .clear() method, which would clear the entire album. I need users to be able to remove one photo from an album at a time, while still being able to order the photos in the album.

How can I achieve this?

Upvotes: 2

Views: 1044

Answers (1)

You shouldn't let the fact that django removes add, create, remove deter you from doing anything.

Just because it "only" supports the .clear() method, doesn't mean you can't write normal python code to replace that functionality.

The intermediate model approach would work in ordering the photos in the album, but not in removing photos from an album. Intermediate models don't support .add(), .create(), .remove(), or assignment. They only support the .clear() method, which would clear the entire album. I need users to be able to remove one photo from an album at a time, while still being able to order the photos in the album.

I don't see what's stopping you from removing one relationship instead of all of them.

Just find the instance of the M2M intermediary table and delete the row. It's a normal django model.

# say you have a photo that the user wants to remove from album.
album = Album.objects.latest('id')
photo = Photo.objects.album_contents.latest('id')

# to remove that m2m relationship...
# delete the through table row which matches said relationship
MyThroughTable.objects.filter(album=album, photo=photo).delete()

Upvotes: 4

Related Questions