两个相互引用的模型字段 - django rest

Two model fields referring to each other - django rest

我想更改 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)
        ...

基本上,'inbound' 和 'mobile' 应该引用相同的字段,并且可以使用 'inbound' 字段或 'mobile'.

发送请求

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

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

在同一个模型中拥有两个包含相同信息的字段是个坏主意,尤其是当您需要强制执行唯一性时,因为

  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