0

I have the following models:

class User(AbstractBaseUser, PermissionsMixin):
    SUPERVISOR = 1
    REVIEWER = 2
    VERIFIER = 3
    READ_ONLY = 4
    USER_TYPE = [
        (SUPERVISOR, 'Supervisor'),
        (REVIEWER, 'Reviewer'),
        (VERIFIER, 'Verifier'),
        (READ_ONLY, 'Read Only'),
    ]
    email = models.EmailField(max_length=50, unique=True)
    name = models.CharField(max_length=100)
    phone = models.CharField(max_length=50, null=True)
    role = models.IntegerField(
        choices=USER_TYPE,
        default=READ_ONLY
    )
    is_active = models.BooleanField(default=True)


class Comment(models.Model):
    text = models.TextField()
    user = models.ForeignKey(
        settings.AUTH_USER_MODEL,
        on_delete=models.PROTECT
    )

View:

class CommentViewSet(BaseCertViewSet):
    queryset = Comment.objects.all()
    serializer_class = serializers.CommentSerializer

Serializer:

class CommentSerializer(serializers.ModelSerializer):
    user = serializers.SlugRelatedField(
        read_only=True,
        slug_field='name'
    )


    class Meta:
        model = Comment
        fields = ('id', 'text', 'user',)
        read_only_fields = ('id',)

My question: when I hit the comment API endpoint, I'd like it to return the user role from the user model as well. How do I go about doing that?

bluebuddah
  • 297
  • 3
  • 12

2 Answers2

0

I believe you can use a QuerySet.annotation:

EDIT: F is from django.db.models so you have to import that as well.

queryset = Comment.objects.annotate(user_role=F("user__role")) in your CommentViewSet

EDIT: In order to get the serializer to recognize the field that you are trying to add to the QuerySet, you must also define the field on the serializer like this:

class CommentSerializer(serializers.ModelSerializer):
    user = serializers.SlugRelatedField(
        read_only=True,
        slug_field='name'
    )

    # add line below to your code
    user_role = IntegerField()

    class Meta:
        model = Comment
        # you have to add it to the list of fields as well
        fields = ('id', 'text', 'user', 'user_role')
        read_only_fields = ('id',)
efischency
  • 473
  • 2
  • 14
  • Thanks. I get: `django.core.exceptions.ImproperlyConfigured: Field name 'user_role' is not valid for model 'Comment'.` – bluebuddah Dec 13 '19 at 20:38
  • it is two underscores between `user` and `role` - that is how you access properties of related objects, two underscores. in your comment here you only have one – efischency Dec 13 '19 at 20:44
  • I should clarify - it is two within the `F('user__role')` that you use the two underscores – efischency Dec 13 '19 at 20:46
  • that's just the error returned by django, I do have it exactly as you suggested with double underscore. Is there anything I need to do on the serializer side? – bluebuddah Dec 13 '19 at 20:58
  • ah - I see what you are saying now – efischency Dec 13 '19 at 21:36
  • this could also be a duplicate of https://stackoverflow.com/questions/31920853/aggregate-and-other-annotated-fields-in-django-rest-framework-serializers – efischency Dec 13 '19 at 22:04
  • @kloster there are two comments in the snippet that I put - make sure you read and see both changes - and I think that it will work for you – efischency Dec 13 '19 at 22:06
  • thanks, but unfortunately this solution with edits still yields the same error. – bluebuddah Dec 16 '19 at 01:43
  • huh - what versions of django and django-rest-framework are you on? because I actually did have this work for me when I tested it – efischency Dec 16 '19 at 16:06
  • django 2.2.7 and drf 3.10.3 – bluebuddah Dec 16 '19 at 16:20
  • interesting - if you could share your updated code (especially the serializer) I might be able to spot something – efischency Dec 16 '19 at 16:25
  • I've updated my view and serializer above with the latest. The queryset expression works when I print the values, however I still get the same error of ```django.core.exceptions.ImproperlyConfigured: Field name 'user_role' is not valid for model 'Comment'.``` - I should also mention that I have tested it exactly as you've suggested but got the same result. – bluebuddah Dec 16 '19 at 16:37
  • I ended up doing it in a different way. Couldn't make it work with the above suggestion, although the F expression was working on its own. Thanks for taking the time to guide me through this. – bluebuddah Dec 16 '19 at 17:22
0

The solution that worked for me (not sure it's the most elegant one, happy to change to a better way of doing that):

class CommentSerializer(serializers.ModelSerializer):
    """Serializer for Comment object"""

    user = serializers.SlugRelatedField(
        read_only=True,
        slug_field='name'
    )

    role = serializers.SerializerMethodField()

    def get_role(self, obj):
        user = obj.user_id
        role = User.objects.only('id').get(
            id=user).role
        return role

    class Meta:
        model = Comment
        fields = ('id', 'value', 'text', 'user', 'role',
                  'date_created', 'date_updated')
        read_only_fields = ('id',)
bluebuddah
  • 297
  • 3
  • 12