0

我需要在 ModelSerializer 上的已登录用户中获取 FK 信息以添加新模型。

在这种情况下,用户-> 业务和客户-> 业务。发布客户端时,我需要使用登录的用户业务设置业务 ID。

重要的是要说所有其他模型具有相同的行为。我正在为这个问题寻找一些通用的解决方案。

客户模型

class Client(SoftDeletionModel):
    object = ClientManager
    business = models.ForeignKey(Business, related_name='business_clients', on_delete=models.CASCADE)
    company_name = models.CharField(max_length=511, verbose_name=_('Company Name'))
    cnpj = models.CharField(max_length=14, verbose_name=_('CNPJ'))

用户模型

class User(AbstractUser):
"""User model."""

    username = None
    email = models.EmailField(_('email address'), unique=True)
    business = models.ForeignKey(Business, related_name='business', on_delete=models.CASCADE, null=True)

客户端序列化器

class ClientSerializer(serializers.ModelSerializer):
    business = serializers.IntegerField() # here how can I get user.business?
    deleted_at = serializers.HiddenField(default=None)
    active = serializers.BooleanField(read_only=True)
    password = serializers.CharField(write_only=True, required=False, allow_blank=True)
    password_contract = Base64PDFFileField()

class Meta:
    model = Client
    fields = '__all__'
    validators = [
        UniqueTogetherValidator2(
            queryset=Client.objects.all(),
            fields=('cnpj', 'business'),
            message=_("CNPJ already exists"),
            key_field_name='cnpj'
        ),
        UniqueTogetherValidator2(
            queryset=Client.objects.all(),
            fields=('email', 'business'),
            message=_("Email already exists"),
            key_field_name='email'
        )
    ]
4

2 回答 2

1

序列化程序内的访问请求

在序列化程序中,您可以访问可以包含请求实例的序列化程序上下文

class ClientSerializer(serializers.ModelSerializer):
    ...

    def create(self, validated_data):
        return Client.objects.create(
            business=self.context['request'].user.business,
            **validated_data
        )

只有在实例化序列化程序时传递请求才能访问

通过将额外的参数传递给序列化程序save()

也可以在save()方法调用期间将额外的参数传递给序列化程序

def create(self, request, **kwargs)
    serializer = ClientSerializer(data=request.data)
    serializer.is_valid(raise_exception=True)
    serializer.save(business=request.user.business)
    ...

创建一个mixin来设置业务

create最后,一种更可重用的方法是为提供和/或操作的视图创建一个 mixin update,然后覆盖perform_create()perform_update()方法

class BusinessMixin:
    def perform_create(self, serializer):
        serializer.save(business=self.request.user.business)

    def perform_update(self, serializer):
        serializer.save(business=self.request.user.business)


class ClientViewSet(BusinessMixin, ModelViewSet):
    serializer_class = ClientSerializer
    queryset = Client.objects.all()
    ...

ModelViewSet(基本上CreateModelMixin和)在执行其操作时UpdateModelMixin使用这些方法从序列化程序调用方法( 、和、即和)save()create()update()partial_update()POSTPUTPATCH

于 2019-01-04T16:03:02.850 回答
0

受 serializers.CurrentUserDefault() 魔术的启发,我编写了 CurrenUserBusinessDefault 但 set_context 与当前用户业务。

class CurrentUserBusinessDefault(object):
    def set_context(self, serializer_field):
        self.business =  serializer_field.context['request'].user.business

    def __call__(self):
        return self.business

    def __repr__(self):
        return unicode_to_repr('%s()' % self.__class__.__name__)

所以它可以像默认方法一样访问

class ClientSerializer(serializers.ModelSerializer):
    business = BusinessSerializer(default=CurrentUserBusinessDefault())
于 2019-01-04T09:11:43.200 回答