【问题标题】:Django model allow only once in manyDjango模型只允许一次
【发布时间】:2021-11-09 10:53:24
【问题描述】:

请原谅标题,但我不确定如何用语言表达。 我有一个模型“卡”和一个模型“计算机”:

class card(models.Model):
name=models.CharField(
    verbose_name = 'Name',
    max_length=50,
    null=True,
    blank=True,
)
serial=models.CharField(
    verbose_name = 'Serial',
    max_length=50,
    null=True,
    blank=True,
)

class computer(models.Model):
name=models.CharField(
    verbose_name = 'Name',
    max_length=50,
    null=True,
    blank=True,
)
slot1 = models.OneToOneField(
    'card',
    related_name='cardslot1',
    on_delete=models.SET_NULL,
    null=True,
    blank=True,
    verbose_name = 'Slot 1',
)
slot2 = models.OneToOneField(
    'card', 
    related_name='cardslot2',
    on_delete=models.SET_NULL,
    null=True,
    blank=True,
    verbose_name = 'Slot 2',
)

(当然这个电脑型号无效) 这些卡是独一无二的,只能在任何计算机的一个插槽中使用。实现这一目标的最佳方法是什么?我在考虑一个中间表,比如

卡片 n-1 卡片电脑 n-1 电脑

但我希望有更好的方法我现在还没有看到。 谢谢

【问题讨论】:

    标签: django django-models relationship


    【解决方案1】:

    为您的模型使用 constraints 元选项。

    from django.db import models
    from django.db.models import CheckConstraint, Q
    
    class computer(models.Model)
    
        name=models.CharField(
            verbose_name = 'Name',
            max_length=50,
            null=True,
            blank=True,
        )
        slot1 = models.OneToOneField(
            'card',
            related_name='cardslot1',
            on_delete=models.SET_NULL,
            null=True,
            blank=True,
            verbose_name = 'Slot 1',
        )
        slot2 = models.OneToOneField(
            'card', 
            related_name='cardslot2',
            on_delete=models.SET_NULL,
            null=True,
            blank=True,
            verbose_name = 'Slot 2',
        )
    
        class Meta:
            constraints = [
                CheckConstraint(
                    check = ~Q(slot1=slot2), 
                    name = 'unique_slot',
                ),
            ]
    

    【讨论】:

    • 我似乎做错了,而 makemigrations 我总是得到 NameError: name 'slot2' is not defined
    • @tesago,你当然需要定义你的字段。为简单起见,我只声明了 Meta 类。
    • 我已经像以前一样定义了 slot1 和 slot2,但仍然出现名称错误。我什至复制了你更新的代码,我看不出我做错了什么。
    • @tesago 我将 Meta 类放在字段定义之后。这应该可以完成工作。
    【解决方案2】:

    Yagus 的答案是正确的,但这是一个纯模型替代方案。

    class Card(models.Model):
        name = models.CharField(
            verbose_name='Name',
            max_length=50,
            null=True,
            blank=True,
        )
        serial = models.CharField(
            verbose_name='Serial',
            max_length=50,
            null=True,
            blank=True,
        )
    
    
    class Slot(models.Model):
        card = models.OneToOneField(Card,
            on_delete=models.SET_NULL,
            null=True,
            blank=True
        )
        computer = models.ForeignKey('Computer',
            on_delete=models.CASCADE, 
            related_name='slots'
        )
    
    
    class Computer(models.Model):
        name = models.CharField(
            verbose_name='Name',
            max_length=50,
            null=True,
            blank=True,
        )
    

    通过这种方式,您可以灵活地在管理面板中为每台计算机添加/更改插槽,并且内容比约束更易读。

    由于相关名称,您仍然可以访问Computer.slots

    【讨论】:

    • 现在我只需要弄清楚如何使插槽和卡可以从新计算机的表单中选择(在管理面板之外)。谢谢
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2019-10-06
    • 2015-10-13
    • 1970-01-01
    • 1970-01-01
    • 2017-06-04
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多