将基于外键的常规 class 的实例化限制为常规 class 和抽象 class

Constraining instantiation of a regular class based on foreginkeys to a regular class and an abstract class

我正在创建我的第一个 Django 项目,在创建模型 A 之后,我意识到我想创建其他模型 B、C ...,它们具有与 A 相同的某些特征,但需要是单独的模型。因此,我创建了具有这些特征的抽象 class 'InteractableItem'。 我希望用户能够喜欢可交互的项目,但是我也想限制 'Like' 模型的实例化,以便每个用户只能喜欢给定的可交互项目一次。为了解决这个问题,我尝试在字段 'user' 和 'interactableitem' 之间的 like 模型中创建一个 models.UniqueConstraint。这给了我以下错误

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'.

我意识到我的错误是通过外键引用抽象 class,但是如果 'user' 喜欢并且 'interactableitem' 不是 'like' 中的两个字段。这是我需要帮助的地方。

如何在这样的 'Like' 模型上建立实例化约束?

这里提供我参考的模型:

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'),
        ]

在测试了不同的方法来限制 'like' 模型的实例化之后,我意识到有一种方法可以解决这个问题。 我让抽象 class 'BaseItem' 有一个外键到常规 class 'interactableitem'。 'Like' 现在有一个 models.Uniqueconstrait 有两个 ForeignKey 字段到正常的 classes 是有效的。这样我只需要确保 interactableitem 只被创建一次,我确信有更好的方法可以做到这一点但是这个 if self.pk 应该适用于我能想到的所有场景,因为它检查项目是否是在创建之前的数据库中。

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'),
        ]