Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is it possible to add a datetime column to a manytomany field?

I was wondering if there was a way to add a datetime auto_now_add=True column to a manytomany field. I have the following model.

class Photographer(models.Model):
     user = models.OneToOneField(User, primary_key=True)
     bio = models.CharField(max_length=140, blank=True)
     favorites = models.ManyToManyField('Photo', through='Favorites', related_name = 'photographer_favs')
     likes = models.ManyToManyField('Photo', related_name='likedby', blank=True)

In my postgresql database, I have a separate table for likes called "djangoapp_photographer_likes".

In this table, I have three columns:

id                 photographer_id        photo_id
[PK] serial        integer                integer
    1                  3                    6
    2                  3                    7
    3                  3                    8

After several months of going into production, I realized that I would require the datetime of when these photos we're liked. So instead of three columns I would have four:

    id             photographer_id        photo_id      liked
[PK] serial        integer                integer       timestamp with time zone
    1                  3                    6           2013-07-10 23:30:19.559463+00
    2                  3                    7           2013-07-11 17:00:53.39614+00
    3                  3                    8           2013-07-11 17:25:28.4953+00

Is it possible to add this extra column even though it is not in the models? I want it so that every time a picture is liked, the time at which it is liked is recorded. If this is not possible, what other work arounds should I look into?

EDIT

This is my Photo model:

class Photo(models.Model):
     title = models.CharField(max_length=40, blank=True)
     photographer = models.ForeignKey(Photographer, related_name = 'shot_owner')
     postTime = models.DateTimeField(auto_now_add=True)
     description = models.CharField(max_length=255, blank=True)
     url = models.CharField(max_length=128)
like image 781
deadlock Avatar asked Feb 16 '23 20:02

deadlock


1 Answers

Yes, this is normal. You'll declare an explicit model for the Likes relationship and add the datetime field on it. Check the many-to-many field docs for full details and some examples - the group membership example includes a 'date joined' field that's the same idea as your like timestamp. Using auto_now_add=True in the field's definition should automate the recording of the timestamp.

class Photographer(models.Model):
    # as above, but:
    likes = models.ManyToManyField('Photo', through='PhotoLikes', related_name='likedby', blank=True)

class PhotoLikes(models.Model):
    class Meta:
        db_table = 'djangoapp_photographer_likes'
        # or whatever your table is called
    photo = models.ForeignKey(Photo)
    photographer = models.ForeignKey(Photographer)
    liked = models.DateTimeField(null=True, blank=True, auto_now_add=True)

As the docs note, the methods to create likes are a bit more restricted with this setup:

Unlike normal many-to-many fields, you can’t use add, create, or assignment (i.e., beatles.members = [...]) to create relationships

Why? You can’t just create a relationship between a Person and a Group - you need to specify all the detail for the relationship required by the Membership model. The simple add, create and assignment calls don’t provide a way to specify this extra detail. As a result, they are disabled for many-to-many relationships that use an intermediate model. The only way to create this type of relationship is to create instances of the intermediate model.

In this case, it would theoretically be possible to determine the additional detail, since it's an automatic timestamp, but Django isn't quite able to detect that.

like image 58
Peter DeGlopper Avatar answered Feb 27 '23 10:02

Peter DeGlopper