除一个表外,一个表不能是其他表的外键

问题描述 投票:0回答:2

例如

class Room(models.Model):
    visitor = models.ForeignKey(Visitor)
    number = models.PositiveIntegerField()
    capacity = models.ForeignKey(Capacity, on_delete=models.PROTECT)
    floor = models.ForeignKey(Floor, on_delete=models.PROTECT)
    price = models.PositiveIntegerField()
    is_premium = models.BooleanField(default=False)
    is_vip = models.BooleanField(default=False)
    expiry_date = models.DateTimeField()

    class Meta:
        unique_together = ('')

    def __str__(self):
        return '№{0}'.format(self.number)


class Reserved(models.Model):
    room = models.ForeignKey(Room)
    begin_date = models.DateTimeField()

    def __str__(self):
        return 'Reserved Room {0}'.format(self.room)

class Busy(models.Model):
    room = models.ForeignKey(Room)

表格空间无法同时连接到“保留”和“忙碌”表。房间应该保留或忙碌。有没有办法对此进行验证?我尝试使用unique_together但是如果用于表的字段

谢谢

python django django-models
2个回答
0
投票

没有办法在数据库级别强制执行此操作,也无法在Django级别执行此操作。使用您的结构,您应该在创建(或修改)BusyReserved之前添加一些验证。就像是:

class Busy(models.Model):
    room = models.ForeignKey(Room)

    def __save__(self, *args, **kwargs):
        if Reserved.object.filter(room=self.room).exists():
            raise RuntimeError('Trying to make a reserved room busy.')
        super(Busy, self).__save__(*args, **kwargs)

如果您同时创建BusyReserved对象,则会受到竞争条件的影响。我建议将房间状态移动到Room模型本身并添加一些辅助函数(类似于room_manager.py旁边的models.py)来改变其状态并确保以一致的方式创建/修改相关模型。


0
投票

在数据库级别确保您在某个房间的给定时间内拥有一个“状态”的唯一方法是让您的关系反过来 - Room在代表状态的任何地方都有外键。为了完成这项工作,你需要使用某种形式的模型继承或django的“通用”关系(有时可以很方便,但实际上不是SQL友好的)。

这是一个使用最简单的“模型继承”形式的例子(实际上根本不是继承):

class Status(models.Model):
    BUSY = 1
    RESERVED = 2
    TYPES = (
        (BUSY,"busy"),
        (RESERVED,"reserved")
    )
    type = models.CharField("Status type", max_length=10, choices=TYPES)
    # only used for reservations
    begin_date = models.DateTimeField(null=True, blank=True)

    def save(self, *args, **kw):
        # TODO : this should belong to `full_clean()`, 
        # cf the FineManual model's validation
        if self.type == self.RESERVED and not self.begin_date:
            raise ValueError("RESERVED statuses need a begin_date")
        super(Status, self).save(*args, **kw)




class Room(models.Model):
    status = models.ForeignKey(Status)

请注意,这允许同时为多个房间使用相同的状态,这可能也是一个问题。使用OneToOneField字段可能对Django端有帮助,但在数据库级别仍将被视为外键。

© www.soinside.com 2019 - 2024. All rights reserved.