如何避免Django多对多关系中的孤立记录?

时间:2018-01-25 16:50:56

标签: python django django-models many-to-many

在从具有多对多关系的Django表中删除记录时,如何确保不留下任何孤立记录?

我创建了三个Django模型,允许用户创建表示他们想要参加的活动(例如电影,音乐会和体育赛事)的项目列表。由于每个用户可以在列表中包括一个或多个项目(即活动),并且多个用户可能在他们的一个列表中具有相同的项目(活动),因此列表和项目之间存在多对多关系: / p>

class Type(models.Model):
    TYPES = (
        (1, 'Movie'),
        (2, 'Concert'),
        (3, 'Sport'),
    )
    type = models.CharField(_('type'), max_length=16)
    class Meta:
        db_table = 'type'


class List(models.Model):
    user = models.ForeignKey(User)
    type = models.ForeignKey(Type, help_text=_('Type of list'))
    name = models.CharField(_('list'), max_length=128, help_text=_('Name of list'))
    class Meta:
        db_table = 'list'
        unique_together = (('user', 'type', 'name'), )   # Ensure no duplicate lists

class Item(models.Model):
    """item contains the pk of a movie, concert, or sporting event record"""
    lists = models.ManyToManyField(List, related_name='items').   # Results in creation of item_lists linking table
    type = models.ForeignKey(Type, help_text=_('Type of item'))
    item = models.IntegerField(_('item'), help_text=_('Item in list'))
    class Meta:
        db_table = 'item'
        unique_together = ('item', type',)

每当我创建一个新的列表项时,我都会使用Django的get_or_create()QuerySet方法。

为了防止孤立记录,我认为每当我从列表中删除整个列表或一个或多个项目时,我还需要检查删除的项目是否包含在任何其他列表中并删除项目表中的那些项目,如果它们不是。伪代码可能如下所示:

items_to_delete = (single item or items from a list)
for item in items_to_delete:
    if item is not in item_lists linking table:   # Prevent orphan records
        delete item from item table
    delete item from item_lists linking table

是否有"标准" Django方式执行上述记录删除?我应该覆盖Django的对象删除方法,以便如果链接表中没有更多实例,它还会从项目表中删除该项目吗?或者这是创建Django信号的情况吗?

其次,我应该在Django原子数据库事务中包含上述删除逻辑吗?是不是一个进程可能对现有项执行get_or_create并获取它,因为它认为它在表中但是然后第二个进程在第一个进程可以创建之前从项表中删除该项链接表中的记录?

1 个答案:

答案 0 :(得分:0)

您是否看过使用Signals?

from django.db.models.signals import post_delete
from django.dispatch import receiver

@receiver(post_delete, sender=models.List)
def check_orphan_items(sender, instance, **kwargs):
    for item in instance.items.all():
        if not item.lists.all().exists():
            item.delete()

关于信号的原子事务,请查看this answer.