Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

[Question] dynamic included_serializers#1007

Unanswered
svazquezco asked this question inQ&A
Discussion options

Hi,

I am reading the current documentation but I didn't find the way to included a serializer dynamically with the included_serializers attribute.

I think is a common feature to use X or B serializer by N attribute of the request method, request user,... For example, the user type. I add this logic to the ViewSet overriding the get_serializer_class method but now I need to add an included with this behavior.

Following, you can see a simple example of this scenario:

# models.pyclass Author(models.Model):    id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)    name = models.CharField(max_length=300)class Comment(models.Model):    id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)    text = models.TextField()    author = models.ForeignKey(Author, on_delete=models.CASCADE)# serializers.pyclass CommentPublicSerializer(serializers.ModelSerializer):    class Meta:        model = Comment        fields =  ("text",)class CommentPrivateSerializer(serializers.ModelSerializer):    class Meta:        model = Comment        fields = ("id", "text")class AuthorSerializer(serializers.HyperlinkedModelSerializer):    class Meta:        model = Author        fields = ("id", "name", "last_comment")    last_comment = SerializerMethodResourceRelatedField(        model=Comment,        method_name="get_last_comment",        related_link_view_name="api:comment-list",        related_link_url_kwarg="author_pk",    )    def get_last_comment(self, instance: Author) -> Comment:        return Comment.objects.filter(author=instance).order_by("created_at").last()# views.pyclass CommentViewSet(ModelViewSet):    default_serializer_class = CommentSerializer    serializer_classes = {        "private" : CommentPrivateSerializer,    }    queryset = Comment.objects.all()    def get_serializer_class(self) -> Serializer:        return self.serializer_classes.get(self.request.user.type, self.default_serializer_class)

I would like to add in the current AuthorSerializer an included_serializer -> last_comment with the CommentPrivateSerializer or the CommentPublicSerializer depending of the request user type. Something like:

class AuthorSerializer(serializers.HyperlinkedModelSerializer):    included_serializers = {        "last_comment": ... # CommentPrivateSerializer or CommentPublicSerializer     }    ....

Is there any way to do this? If not, have you any idea to do it? It's possible you have in mind something so I don't mind to create a PR to add this feature.
IMHO, we could move the included serializer to the ResourceRelatedField adding a boolean attribute "includable" and use the ViewSet to get the serializer?

Thanks in advance!

You must be logged in to vote

Replies: 1 comment 3 replies

Comment options

I think what you are trying to do is not REST conform as you will end up with two instances of the same resource with different representation depending on user (see#901 (comment) for a similar discussion).

To be REST conform you would need to have two different APIs one private and one public returning different resources. The model can be the same simply the resource name of the serializer needs to be set differently. (by settingresource_name in serializer Meta class). Note thought in your example you are trying to hide theid of the comment, in JSON:API spec the id of a resource cannot be hidden

If you really wanna move forward with your current idea one resource different representation you could overwriteget_fields in aCommentSerializer and return fields according to the rights of a user.

Hope this is helpful.

You must be logged in to vote
3 replies
@svazquezco
Comment options

Thank@sliverc for a quick reaction!

Sorry, I've noticed the example I added is not very clear. I know the id cannot be hidden in JSON:API so you can change the id by other
"sensitive field", i.e the vat number, the bank account. Then you don't want that all the users know you have this information so if you are a user type A you can see this information but if you are a user of type B you cannot see them.

You have a Team manager and members (employees) of the team. All of them can access to all the members of the same team, the manager can see the salary but the rest of them cannot see. IMHO it's overkill to have a private / public API for this. How you deal with this kind of features?

About the get_fields it was my first option but we will have many types of users and it will be very complex to maintain. I am trying to keep simple avoiding have everything mixed.

@sliverc
Comment options

You could extract confidential employee data onto a different resource and protect that resource withpermission_classes. You could either do this on the database level withOneToOneField so you haveEmployeeModel andEmployeeConfidentialModel. It could also be done on on the serializer level like you have aEmployeeSerializer andEmployeeConfidentialSerializer both based on the same model but exposing different fields. After that you connect the two serializers withSerializerMethodResourceRelatedField.

@svazquezco
Comment options

I see your point and I agree with you the best way to handle this is split the fields in groups but, we have a complex case use. we have a model with N fields, we can called field_1, field_2, field_n with N types of users where the user_1 can access from field_1 to field_5, users_2 can access from field_2 to field_7, user_3 can access from field_1 to field_9. So I am thinking is crazy to have as many endpoints as cases uses we have due to there is not a easy way to split them.

It means you have more than one field confidential, for example, vat_number and you only want the admin user has access to this field but not for the TeamManagerUser. Furthermore, you want other user_type have access to the vat_number and the salary and other user_type has access to salary. All of them can see the first_name but only the admin user has access to the full name. We'll have a endpoint by field ->

  • vat_number
  • salary
  • first_name
  • last_name

I know the salary could be part of other model / endpoint (maybe Contracts?) but you can change it by security_social_number or field_x related directly with the Employee.

Thank you very much for your answer!

Sign up for freeto join this conversation on GitHub. Already have an account?Sign in to comment
Category
Q&A
Labels
None yet
2 participants
@svazquezco@sliverc

[8]ページ先頭

©2009-2025 Movatter.jp