Предотвращение необходимости использования одного и того же предложения select_related для нескольких представлений в DRF
Учитывая следующие модели...
class Player(models.Model):
user = models.ForeignKey(User)
class Activity(models.Model):
player = models.ForeignKey(Player)
и эти сериализаторы...
class PlayerSerializer(serializers.ModelSerializer):
class Meta:
model = Player
fields = ['user']
class ActivitySerializer(serializers.ModelSerializer):
player = PlayerSerializer()
class Meta:
model = Activity
fields = ['player']
если я хочу использовать django-rest-framework для составления списка всех действий, мне нужно сделать что-то вроде этого...
class ActivityViewSet(viewsets.ReadOnlyModelViewSet):
queryset = Activity.objects.select_related("player__user") <--- this is needed because the activity serializer is going to serialize the player which has a user
serializer_class = ActivitySerializer
Все это хорошо. Но тогда каждый раз, когда я буду писать новое представление, которое на каком-то уровне использует PlayerSerializer, мне придется не забывать делать правильный select_related clause, чтобы сохранить низкое количество обращений к БД.
В итоге я собираюсь написать множество представлений, которые имеют одинаковые select_related clauses (мои на самом деле намного сложнее, чем этот пример), и, если PlayerSerializer когда-нибудь изменится, мне нужно будет не забыть изменить все представления.
Мне это кажется не очень DRY, и я чувствую, что должен быть лучший способ сделать это. Может быть, я упустил что-то очевидное?
Можно иметь базовый родительский класс, например:
class BaseViewset(viewsets.ReadOnlyModelViewSet):
SELECT_RELATED_FIELD = None # for providing select related field in your queryset or maybe have a default value for this one (based on your use case)
def get_queryset(self):
if not self.SELECT_RELATED_FIELD or not isinstance(self.SELECT_RELATED_FIELD, str):
raise NotImplementedError("Ensure 'SELECT_RELATED_FIELD' is not empty/ Is instance of string")
return super().get_queryset().select_related(self.SELECT_RELATED_FIELD)
А затем используйте этот родительский класс во всех ваших представлениях вместо ReadOnlyModelViewSet:
class ActivityViewSet(BaseViewset):
SELECT_RELATED_FIELD = "player__user"
queryset = Activity.objects.all()
serializer_class = ActivitySerializer
было бы хорошим началом (во всех представлениях, которые у вас есть select_related часть).