Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Django: GenericForeignKey and unique_together

In the application I'm working on I'm trying to share access tokens within a company. Example: a local office can use the headquarter's tokens to post something on their Facebook page.

class AccessToken(models.Model):
    """Abstract class for Access tokens."""
    owner = models.ForeignKey('publish.Publisher')
    socialMediaChannel = models.IntegerField(
        choices=socialMediaChannelList, null=False, blank=False
    )
    lastUpdate = models.DateField(auto_now=True)

    class Meta:
        abstract = True

Since Facebook, Twitter and other social media sites handle access tokens in their own way I made and abstract class AccessToken. Each site gets its own class e.g.

class FacebookAccessToken(AccessToken):
    # class stuff

After doing some reading I found out that I must use a GenericForeignKey to point to classes that inherit AccessToken. I made the following class:

class ShareAccessToken(models.Model):
    """Share access tokens with other publishers."""
    sharedWith = models.ForeignKey('publish.Publisher')
    sharedBy = models.ForeignKey(User)

    # for foreignkey to abstract model's children
    contentType = models.ForeignKey(ContentType)
    objectId = models.PositiveIntegerField()
    contentObject = GenericForeignKey('contentType', 'objectId')

    class Meta:
        unique_together = (('contentObject', 'sharedWith'))

When I run the django test server I get the following error:

core.ShareAccessToken: (models.E016) 'unique_together' refers to field 'contentObject' which is not local to model 'ShareAccessToken'. HINT: This issue may be caused by multi-table inheritance.

I don't understand why I get this error, first time using GenericForeignKey. What am I doing wrong?

If there is a smarter way to share the access tokens I would love to hear about it.

like image 798
CyberFly Avatar asked Feb 05 '16 16:02

CyberFly


1 Answers

Your use of the generic foreign key in this situation is correct.

The error is coming from your unique_together declaration in your model. unique_together can only be used with columns that exist in the database. Since contentObject is not a real column, Django complains about the constraint.

Instead, you can do the following:

unique_together = (('contentType', 'contentId', 'sharedWidth'),)

This is equivalent to what you had defined in your question because contentObject is really just the combination of contentType and contentId behind the scenes.

like image 135
Derek Kwok Avatar answered Oct 13 '22 22:10

Derek Kwok