【问题标题】:Django REST: Serializer lookup by UUIDDjango REST:按 UUID 查找序列化程序
【发布时间】:2019-03-01 14:56:54
【问题描述】:

我正在 Django REST 中创建这个简单的购物 API。

在内部,我将 ID 用于外键约束,而 guuids 被带到外部世界。

对于结帐过程,用户提供他愿意购买的文章 ID 的列表。因此,POST 数据中的对象如下所示:

{
  assets: [
    {
       'product': 'd9d5044d-2284-4d15-aa76-2eee3675035b',
       'amount': 4
    },
    ....
  ]
}

我正在使用以下票证/资产模型:

# Ticket
class Ticket(models.Model):
    uuid = models.UUIDField(default=uuid.uuid4, editable=False, unique=True)
    owner = models.ForeignKey(settings.AUTH_USER_MODEL, related_name='tickets', on_delete=models.CASCADE)


# Assets
class Asset(models.Model):
    ticket = models.ForeignKey(Ticket, related_name='assets', on_delete=models.CASCADE)
    stock_item = models.ForeignKey(Stock, related_name='stock_item', on_delete=models.SET_NULL, null=True)
    amount = models.IntegerField(validators=[MinValueValidator(0)])

序列化器如下所示:

# Asset serializer
class AssetSerializer(serializers.ModelSerializer):

    class Meta:
        model = Asset
        fields = ('stock_item', 'amount')


# Ticket serializer
class TicketSerializer(WritableNestedModelSerializer):
    owner = serializers.ReadOnlyField(source='owner.username')
    assets = AssetSerializer(many=True)

    class Meta:
        model = Ticket
        fields = ('uuid', 'owner', 'assets', )

    def perform_create(self, serializer):
        serializer.save(owner=self.request.user)

发布上述指定类型的对象时,出现以下错误:

{"assets":[{"stock_item": ["Invalid type. Expected PK, received string"]}]}

我似乎无法解决,如何指示序列化程序使用 uuid 作为查找值?我之前通过使用lookup_field 成员解决了视图级别的类似问题,但这似乎并没有解决它。有什么建议吗?
在此输入代码

【问题讨论】:

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


    【解决方案1】:

    详细阐述@BjornW 的评论:

    class UUIDRelatedField(serializers.SlugRelatedField):
        slug_field = 'uuid'
    
        def __init__(self, **kwargs):
            super().__init__(slug_field=self.slug_field, **kwargs)
    
    
        def to_representation(self, obj):
            return getattr(obj, self.slug_field).hex
    

    【讨论】:

      【解决方案2】:

      如果我的理解正确,SlugRelatedField 应该能够找到正确的相关对象。

      class AssetSerializer(serializers.ModelSerializer):
          ticket = serializers.SlugRelatedField(
              read_only=True,
              slug_field='uuid',
              queryset=Ticket.objects.all() # Might be redundant with read_only=True
          )
      
          class Meta:
              model = Asset
              fields = ('ticket', 'stock_item', 'amount')
      

      【讨论】:

      • 你知道有什么方法可以让 SlugRelatedField 序列化程序在读取时返回紧凑的十六进制表示,而不是中间有破折号的烦人的东西吗? :)
      • @BjornW 我不太确定“紧凑的十六进制表示”是什么意思。如果您不想要 slug 字段,您可能应该使用 slug 字段以外的其他东西。
      • 据我所知(和 stackoverflow),如果您想在 PrimaryKey 以外的其他东西上做相关字段,除了 SlugField 之外,没有其他理智的替代 PrimaryKeyRelatedField。这是我要说的一个主要限制。因此,通常建议使用 SlugField,但它的缺点是不能按 Field 指定字段,如 PrimaryKeyRelatedField 可以(例如,pk_field 可以设置为 UUIDField(format='hex'),但 slug_field 只是一个字符串)。回答您的问题:UUID 的紧凑十六进制有时看起来比 API 中的虚线默认值更好。
      • 作为有同样问题的其他人的仅供参考。我只是对 SlugRelatedField 进行了子类化,并为 to_representation 添加了一个覆盖,返回 getattr(obj, self.slug_field).hex
      猜你喜欢
      • 2014-12-21
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-12-18
      • 2017-06-04
      • 1970-01-01
      • 1970-01-01
      • 2016-09-04
      相关资源
      最近更新 更多