I am creating my first django project and after having created a model A I realize that I want to create other models B, C ... that have certain traits in common with A but which needs to be separat models. Thus I created an abstract class 'InteractableItem' with these traits. I want users to be able to like interactable items, however I also want to constrain the instantiation of a 'Like' model such that each user only can like a given interactable item once. To solve this I tried creating a models.UniqueConstraint in the like model between the fields 'user' and 'interactableitem'. This gave me the following error
ERRORS:
feed.Like.interactableitem: (fields.E300) Field defines a relation with model 'InteractableItem', which is either not installed, or is abstract.
feed.Like.interactableitem: (fields.E307) The field feed.Like.interactableitem was declared with a lazy reference to 'feed.interactableitem', but app 'feed' doesn't provide model 'interactableitem'.
I realise that my error is the referencing of an abstract class through a ForeignKey, however I dont see a way to constrain the instantiation of the like if the 'user' liking and the 'interactableitem' being like are not both fields in 'like'. This is where I need help.
How do you establish an instantiation constraint on such a 'Like' model?
Here I provide my referenced models:
class InteractableItem(models.Model):
date_created = models.DateTimeField(auto_now_add=True)
date_update = models.DateTimeField(auto_now=True)
author = models.ForeignKey(User, on_delete=models.CASCADE, null=True, blank=True)
class Meta:
abstract = True
class Like(models.Model):
date_created = models.DateTimeField(auto_now_add=True)
user = models.ForeignKey(User, on_delete=models.CASCADE, blank=True)
interactableitem = models.ForeignKey(InteractableItem, on_delete=models.CASCADE, null=True, blank=True)
class Meta:
constraints = [
models.UniqueConstraint(fields=['user', 'interactableitem'], name='user_unique_like'),
]
After having tested different ways to constrain the instatiation of the 'like' model I realised that there was a way around this. I let the abstract class 'BaseItem' have a ForeignKey to a regular class 'interactableitem'. 'Like' now has a models.Uniqueconstrait with two ForeignKey fields to regular classes which works. This way I just have to makesure that interactableitem is only created once, I'm sure there are better ways of doing this but this if self.pk should work for all scenarios I can think of, as it checks if the item is in the database before creation.
class InteractableItem(models.Model):
pass
class SomeItem(models.Model):
date_created = models.DateTimeField(auto_now_add=True)
date_update = models.DateTimeField(auto_now=True)
interactableitem = models.ForeignKey(InteractableItem, on_delete=models.CASCADE, null=True, blank=True)
author = models.ForeignKey(User, on_delete=models.CASCADE, null=True, blank=True)
class Meta:
abstract = True
def save(self, *args, **kwargs):
if not self.pk:
self.interactableitem = InteractableItem.objects.create()
super(SomeItem, self).save(*args, **kwargs)
class Like(models.Model):
date_created = models.DateTimeField(auto_now_add=True)
user = models.ForeignKey(User, on_delete=models.CASCADE, blank=True)
interactableitem = models.ForeignKey(InteractableItem, on_delete=models.CASCADE, null=True, blank=True)
class Meta:
constraints = [
models.UniqueConstraint(fields=['user', 'interactableitem'], name='user_unique_like'),
]