1

Im very new to Django, struggling to find the answer Im looking for. Please bear with me.

In my app/urls.py file I have

router = routers.DefaultRouter()
router.register(r'drugs', views.DrugViewSet)

In my views.py file I have

class DrugViewSet(viewsets.ModelViewSet):
    queryset = Drug.objects.all().order_by('name')
    serializer_class = DrugSerializer

And my DrugSerializer class looks like

class DrugSerializer(serializers.HyperlinkedModelSerializer):
    class Meta:
        model = Drug
        fields = ('id', 'name', 'description', 'recommended_dose_mg', 'count', 'create_date', 'update_date')

So when I do a GET on /drugs, I correctly get the list of drugs. And when I take a UUID (primary key) on a specific drug and do a GET on /drugs/<primary_key>, it correctly pulls the specific drug.

However, I want the GET on /drugs/<primary_key> to display different data. I want to join it with another model that I have and return a new json response. How exactly would I do this?

CTH
  • 75
  • 4
  • please add more details about the data you want to show and what is the relation between the models – Feras Alfrih Dec 29 '21 at 17:31
  • @FerasAlfrih I have another table for SideEffects, and im trying to do a join on the Drug and SideEffect table and display the drug name with the list of SideEffects for that drug. – CTH Dec 29 '21 at 17:41

2 Answers2

0

You can use Nested Serializer

For example, the following serializer:

class TrackSerializer(serializers.ModelSerializer):
    class Meta:
        model = Track
        fields = ['order', 'title', 'duration']

class AlbumSerializer(serializers.ModelSerializer):
    tracks = TrackSerializer(many=True, read_only=True)

    class Meta:
        model = Album
        fields = ['album_name', 'artist', 'tracks']

Would serialize to a nested representation like this:

{
    'album_name': 'The Grey Album',
    'artist': 'Danger Mouse',
    'tracks': [
        {'order': 1, 'title': 'Public Service Announcement', 'duration': 245},
        {'order': 2, 'title': 'What More Can I Say', 'duration': 264},
        {'order': 3, 'title': 'Encore', 'duration': 159},
        ...
    ],
}
Yevhen Bondar
  • 4,357
  • 1
  • 11
  • 31
  • Im still not sure how this connects to the urls/views file. How would those needed to be modified? – CTH Dec 29 '21 at 17:37
  • @Taylor Your url file can stay the same. In ViewSet you can add [prefetch_related](https://docs.djangoproject.com/en/4.0/ref/models/querysets/#prefetch-related) `queryset = Drug.objects.prefetch_related('related_model').all().order_by('name')` to avoid [N+1 problem](https://stackoverflow.com/questions/97197/what-is-the-n1-selects-problem-in-orm-object-relational-mapping) , where RelatedModel is relation that you want to add to resulting JSON. – Yevhen Bondar Dec 29 '21 at 17:42
0

Lookup field

There is a field in ViewSet called lookup_field. It actually defines a field of the model to use in such query variable.

So you can do this:

class DrugViewSet(viewsets.ModelViewSet):
    queryset = Drug.objects.all().order_by('name')
    serializer_class = DrugSerializer
    lookup_field = 'id'

Here is the link of the documentation: https://www.django-rest-framework.org/api-guide/generic-views/#attributes

But actually it is generated automatically for retrieve action in ViewSet and id is used. You can install some of swagger plugins to see it. For example:

Different serializers

If you want to set different serializers for different actions you can override a model of the ViewSet called get_serializer_class:

class DrugViewSet(viewsets.ModelViewSet):
    queryset = Drug.objects.all().order_by('name')
    serializer_class = DrugSerializer

    def get_serializer_class(self):
         if self.action == 'detail': 
              return DrugDetailSerializer
         return DrugSerializer

Documentation here: https://www.django-rest-framework.org/api-guide/generic-views/#get_serializer_classself

In the DrugDetailSerializer you can specify what data to serialize when GET /drug/<primary_key> field is called.

voilalex
  • 2,041
  • 2
  • 13
  • 18
  • With the "different serializers" approach.. My new DrugDetailSerializer now looks like this, class `DrugDetailSerializer(serializers.HyperlinkedModelSerializer): side_effects = SideEffectSerializer(many=True, read_only=True) class Meta: model = SideEffect fields = ('__all__')` But the values it is supposed to join on with the drug are null. – CTH Dec 29 '21 at 18:17