【问题标题】:Two model fields referring to each other - django rest相互引用的两个模型字段 - django rest
【发布时间】:2021-10-15 19:35:46
【问题描述】:

我想更改 Django 模型中现有的字段名称之一。但是,为了向后兼容,我们不想用新的字段覆盖现有字段,暂时保留它们。有没有办法让多个字段引用同一个数据库对象?即

立即编码:

class NetworkPackage:
        name = models.CharField(unique=True, blank=False, null=False)
        inbound = models.CharField(unique=True, blank=False, null=False)
        ...

我要实现:

class NetworkPackage:
        name = models.CharField(max_length=32, unique=True, blank=False, null=False)
        inbound = models.CharField(max_length=128, unique=True, blank=True)
        mobile = models.CharField(max_length=128, unique=True, blank=True)
        ...

基本上,“入站”和“移动”应该引用相同的字段,并且可以使用“入站”字段或“移动”发送请求。

【问题讨论】:

    标签: python django django-models django-rest-framework django-serializer


    【解决方案1】:

    不知道你为什么要重复字段,但我有一些建议给你。

    1.自定义属性

    class NetworkPackage:
        name = models.CharField(unique=True, blank=False, null=False)
        inbound = models.CharField(unique=True, blank=False, null=False)
        
        @poperty
        def mobile(self):
            return self.inbound
    

    2。序列化器

    class NetworkPackageSerializer(serializers.Serializer):
    
        mobile = serializers.CharField(source='inbound')
    
        class Meta:
            model = NetworkPackage
            fields = (
                'id',
                'inbound',
                'mobile',
                'name',
                ...
            )
    

    【讨论】:

    • 感谢您的想法 :)
    【解决方案2】:

    在同一个模型中使用两个字段来保存相同的信息是个坏主意,尤其是当您需要强制唯一性时,因为

    1. 您需要保持这两个字段的奇偶性,这意味着如果请求设置inbound,那么您还必须设置mobile
    2. 由于唯一性,数据库现在必须同时索引 inboundmobile

    您可以做的是利用 python 属性,因为属性是您具有遗留属性的情况的完美解决方案:

    class NetworkPackage(models.Model):
        name = models.CharField(unique=True, blank=False, null=False)
        inbound = models.CharField(unique=True, blank=False, null=False)
        ...
    
        @property
        def mobile(self):
            return self.inbound
    
        @mobile.setter
        def mobile(self, value):
            self.inbound = value
    

    然后在您的序列化程序中,您需要:

    1. mobile 作为附加字段来源添加到inbound
    2. 覆盖两个字段上的 requiredallow_blank 参数,因为序列化程序可以允许任一字段...
    3. 但是,您随后需要编写自定义验证方法,以确保 2 个字段中的至少 1 个字段填充了值。
    4. 如果两个字段都已填充,则还要优先考虑 inbound 值而不是 mobile 值。
    class NetworkPackageSerializer(serializers.ModelSerializer):
        inbound = serializers.CharField(required=False, allow_blank=True)
        mobile = serializers.CharField(source="inbound", required=False, allow_blank=True)
    
        class Meta:
            model = NetworkPackage
            fields = ("inbound", "mobile", ...)
    
        def validate(self, data):
            """Validate `inbound` and/or `mobile`."""
            if not data["inbound"] and not data["mobile"]:
                raise serializers.ValidationError("missing value on inbound or mobile")
            if data["inbound"]:
                del data["mobile"]
            else:
                del data["inbound"]
            return data
    

    【讨论】:

    • 感谢您的详尽解释。这真的很有帮助:)
    猜你喜欢
    • 2012-12-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-11-10
    • 2021-12-07
    相关资源
    最近更新 更多