简体   繁体   中英

Get logged user information in serializers Django Rest + Django JWT

I need to get a FK info in logged User on ModelSerializer to add a new models.

In this case User->Business and Client->Business. When post client I need to set Business id using the logged user Business.

It's important to say all other models have the same behavior. I'm looking for some generic solution for this problem.

Client Model

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

User Model

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)

ClientSerializer

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'
        )
    ]

Access request inside a serializer

Within the serializer you have access to the serializer context that can include the request instance

class ClientSerializer(serializers.ModelSerializer):
    ...

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

Request is only acessible if you pass it when instantiate the serializer

Pass extra arguments to a serializer via save()

It is also possible to pass extra arguments to a serializer during the save() method call

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

Create a mixin to set business

Finally, a more reusable way is create a mixin for views that provides create and/or update actions, then overwrite perform_create() and perform_update() methods

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 (basically CreateModelMixin and UpdateModelMixin ) use these methods to call the save() method from serializer when executing its actions ( create() , update() and partial_update() , ie POST , PUT and PATCH )

Inspired by serializers.CurrentUserDefault() magic I wrote CurrenUserBusinessDefault but set_context with current user business.

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__)

So it's accessible like the default method

class ClientSerializer(serializers.ModelSerializer):
    business = BusinessSerializer(default=CurrentUserBusinessDefault())

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM