Skip to content

Instantly share code, notes, and snippets.

@ar45
Last active August 31, 2022 14:23
Show Gist options
  • Star 4 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save ar45/18d654d1aacbb9497241 to your computer and use it in GitHub Desktop.
Save ar45/18d654d1aacbb9497241 to your computer and use it in GitHub Desktop.
Dynamic QuerySet serializer
from rest_framework import serializers
from django.db.models.manager import Manager
from django.db.models.query import QuerySet
class LimitQuerySetSerializerFieldMixin:
"""
Serializer mixin with a special `get_queryset()` method that lets you pass
a callable for the queryset kwarg. This enables you to limit the queryset
based on data or context available on the serializer at runtime.
"""
def get_queryset(self):
"""
Return the queryset for a related field. If the queryset is a callable,
it will be called with one argument which is the field instance and
should return a queryset or model manager.
.. code::
def get_my_limited_queryset(field):
root = field.root
if root.instance is None:
return MyModel.objects.none()
return root.instance.related_set.all()
MySerializer(queryset=get_my_limited_queryset)
"""
# noinspection PyUnresolvedReferences
queryset = self.queryset
if hasattr(queryset, '__call__'):
queryset = queryset(self)
if isinstance(queryset, (QuerySet, Manager)):
# Ensure queryset is re-evaluated whenever used.
# Note that actually a `Manager` class may also be used as the
# queryset argument. This occurs on ModelSerializer fields,
# as it allows us to generate a more expressive 'repr' output
# for the field.
# Eg: 'MyRelationship(queryset=ExampleModel.objects.all())'
queryset = queryset.all()
return queryset
class DynamicQuersetPrimaryKeyRelatedField(LimitQuerySetSerializerFieldMixin, serializers.PrimaryKeyRelatedField):
"""Evaluates callable queryset at runtime."""
pass
from rest_framework import serializers
from .custom_serializers import DynamicQuersetPrimaryKeyRelatedField
class MyModelSerializer(serializers.ModelSerializer):
"""
MyModel serializer with a primary key related field to 'MyRelatedModel'.
"""
def get_my_limited_queryset(self):
root = self.root
if root.instance is None:
return MyRelatedModel.objects.none()
return root.instance.related_set.all()
my_related_model = DynamicQuersetPrimaryKeyRelatedField(queryset=get_my_limited_queryset)
class Meta:
model = MyModel
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment