Python DRF PrimaryKeyRelatedField使用uuid而不是PK

3npbholx  于 2023-02-11  发布在  Python
关注(0)|答案(3)|浏览(142)

我正在写一个DjangoREST框架API。我的模型有默认的DjangoPK供内部使用,uuid字段供外部引用。

class BaseModel(models.Model):
    uuid = models.UUIDField(default=uuid.uuid4, editable=False)

class Event(BaseModel):
    title = models.TextField()
    location = models.ForeignKey('Location', null=True, on_delete=models.SET_NULL)

class Location(BaseModel):
    latitude  = models.FloatField()
    longitude = models.FloatField()

以及我的序列化器:

class BaseSerializer(serializers.ModelSerializer):
    default_fields = ('uuid',)                                                                        

class EventSerializer(BaseSerializer):                                                                                                                   
    class Meta:                                                                  
        model = Event                                                                                 
        lookup_field = 'uuid' # This does not work                                                                      
        fields = BaseSerializer.default_fields + ('title', 'location',)

class LocationSerializer(BaseSerializer):
    class Meta:
        model = Location
        lookup_field = 'uuid' # This does not work 
        fields = BaseSerializer.default_fields + ('latitude', 'longitude',)

这工作正常,这是我得到的当我检索一个事件:

{
    "uuid": "ef33db27-e98b-4c26-8817-9784dfd546c6",
    "title": "UCI Worldcup #1 Salzburg",
    "location": 1 # Note here I have the PK, not UUID
}

但我想要的是:

{
    "uuid": "ef33db27-e98b-4c26-8817-9784dfd546c6",
    "title": "UCI Worldcup #1 Salzburg",
    "location": "2454abe7-7cde-4bcb-bf6d-aaff91c107bf" # I want UUID here
}

当然,我希望这个行为对我所有的ForeignKeys和ManyToMany字段都有效。有没有一种方法可以定制DRF用于嵌套模型的字段?谢谢!

0sgqnhkj

0sgqnhkj1#

from django.utils.translation import ugettext_lazy as _
from django.core.exceptions import ObjectDoesNotExist
from rest_framework.relations import RelatedField
from django.utils.encoding import smart_text

class UUIDRelatedField(RelatedField):
    """
    A read-write field that represents the target of the relationship
    by a unique 'slug' attribute.
    """
    default_error_messages = {
        'does_not_exist': _('Object with {uuid_field}={value} does not exist.'),
        'invalid': _('Invalid value.'),
    }

    def __init__(self, uuid_field=None, **kwargs):
        assert uuid_field is not None, 'The `uuid_field` argument is required.'
        self.uuid_field = uuid_field
        super().__init__(**kwargs)

    def to_internal_value(self, data):
        try:
            return self.get_queryset().get(**{self.uuid_field: data})
        except ObjectDoesNotExist:
            self.fail('does_not_exist', uuid_field=self.uuid_field, value=smart_text(data))
        except (TypeError, ValueError):
            self.fail('invalid')

    def to_representation(self, obj):
        return getattr(obj, self.uuid_field)

样本使用:

class ProductSerializer(serializers.ModelSerializer):
    category = UUIDRelatedField(
        queryset=Category.objects.all(),
        uuid_field='alias'
    )

    class Meta:
        model = Product
        fields = (
            'id',
            'alias',
            'name',
            'category',
        )
        read_only_fields = (
            'id',
            'alias',
        )

请注意,从Django版本4开始,smart_textugettext_lazy被移除,请使用smart_strgettext_lazy来代替它们:

from django.utils.encoding import gettext_lazy
from django.utils.encoding import smart_str
cgfeq70w

cgfeq70w2#

我的一个朋友给我这个解决方案:它适用于我所有的相关对象。

from rest_framework import serializers                                                                
from rest_framework.relations import SlugRelatedField                 

class UuidRelatedField(SlugRelatedField):                                                             
    def __init__(self, slug_field=None, **kwargs):                                                    
        slug_field = 'uuid'
        super().__init__(slug_field, **kwargs)                                                        

class BaseSerializer(serializers.ModelSerializer):                                                    
    default_fields = ('uuid',)                                                                        
    serializer_related_field = UuidRelatedField

    class Meta:                                                                                       
        pass
ih99xse1

ih99xse13#

对于嵌套模型字段,可以在序列化程序中使用source参数,如下所示

class EventSerializer(BaseSerializer):
    location = serializers.CharField(source='location.uuid')

    class Meta:
        model = Event
        lookup_field = 'uuid'  # This does not work
        fields = BaseSerializer.default_fields + ('title', 'location',)

相关问题