简体   繁体   中英

Django REST: ViewSet custom dictionary

My goal is to retrieve a dictionary where the key is the id of a target group object, and the value is the corresponding target group object.

Additionally I want a custom field "enabled" which represents whether the target_group is paired to the given category (cat_id).

The url would be for example:

http://localhost:8000/api/ctg/?cat_id=61

Example of resulting dictionary:

{
    1:  {
            id: 1,
            name: "target group name",
            employer: 175,
            enabled: false,
        },
    5:  {
            id: 5,
            name: "another target group name",
            employer: 175,
            enabled: true,
        },
    ...
}

The way I do it currently:

  1. I first retrieve all target groups for an employer (user).
  2. I retrieve the target groups which are connected to the given category id.
  3. I make a dict programmatically in the front end, by looping over the retrieved lists...

Obviously this is very inefficient and requires 2 calls to the database.

If possible I would like to retrieve the dictionary which I can use right away in my front end. I have been searching for solutions but I can't really find much about DRF beyond the basics... could someone point me in the right direction as to how to achieve this?

ViewSets:

# get all target groups
class TargetGroupViewset(viewsets.ModelViewSet):
    queryset = TargetGroup.objects.all()
    serializer_class = TargetGroupSerializer

    def list(self, request):
        queryset = TargetGroup.objects.filter(employer=self.request.user.pk)
        serializer = TargetGroupSerializer(queryset, many=True)
        return Response(serializer.data)


# get target groups which are connected to a given category
class GetTargetGroupsForCategory(viewsets.ModelViewSet):
    queryset = TargetGroup.objects.all()
    serializer_class = TargetGroupSerializer

    def list(self, request):
        queryset = TargetGroup.objects.filter(employer=self.request.user.pk)
        if request.query_params:
            cat_id = request.query_params['cat_id']
            ctg_ids = list(CategoryTargetGroup.objects.filter(category=cat_id).values_list('target_group_id', flat=True))
            queryset = TargetGroup.objects.filter(id__in=ctg_ids)
        serializer = TargetGroupSerializer(queryset, many=True)
        return Response(serializer.data)

Models

# target group model
class TargetGroup(models.Model):
    employer = models.ForeignKey(CustomUser, on_delete=models.CASCADE, null=False)
    name = models.CharField(max_length=255, blank=False, null=False)
    
# category-targetgroup model
class CategoryTargetGroup(models.Model):
    category = models.ForeignKey(Category, on_delete=models.CASCADE, null=False)
    target_group = models.ForeignKey(TargetGroup, on_delete=models.CASCADE, null=False)

Currently your TargetGroupSerializer returns this:

[
    {
        id: 1,
        name: "target group name",
        employer: 175,
        enabled: false,
    },
    {
        id: 5,
        name: "another target group name",
        employer: 175,
        enabled: true,
    },
    ...
]

In order to transform it to desired result, you could use a dict comprehension, like this:

def list(self, request):
    ...
    result = {item['id']: item for item in serializer.data}
    return Response(result)

As for the second part of the question, I don't think you need the GetTargetGroupsForCategory viewset. To add a field enabled , you can declare a SerializerMethodField in TargetGroupSerializer :

class TargetGroupSerializer(serializers.ModelSerializer):
    # your serializer fields + new `enabled` field
    enabled = serializers.SerializerMethodField()

    class Meta:
        # your options

    def get_enabled(self, obj):
        return self.context['cat_id'] == obj.id

And finally pass the cat_id to the serializer context in your TargetGroupViewset :

def list(self, request):
    queryset = TargetGroup.objects.filter(employer=self.request.user.pk)
    cat_id = request.query_params.get('cat_id', None)

    serializer = TargetGroupSerializer(queryset, many=True, context={'cat_id': cat_id})
    
    result = {item['id']: item for item in serializer.data}
    return Response(result)

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