#python #django #inheritance #django-rest-framework
#python #django #наследование #django-rest-framework
Вопрос:
У меня есть веб-сайт, который по сути является вики-сайтом для кампании DnD, в которой я участвую. Таким образом, в нем есть статьи о существах, персонажах, местоположениях и многом другом. Я хотел использовать Viewsets для легкого доступа к ним и хотел использовать действие Viewset (вместе с пользовательским маршрутизатором), чтобы иметь возможность искать отдельные записи не через pk, а через различные параметры запроса.
У меня уже есть кое-что, что работает для этого, теперь я хотел бы применить к нему некоторое наследование, чтобы не повторяться. Я бы хотел сделать что-то вроде этого:
class WikiBaseViewset (viewsets.ModelViewSet):
detail_with_params_url_pattern_suffix: str
@action(detail=True, url_name="detail-params", url_path=detail_with_params_url_pattern_suffix)
def detail_through_params(self, request, **kwargs):
if self.detail_with_params_url_pattern_suffix == "":
raise InvalidViewsetURLException("URL of view 'detail_through_params' of WikiBaseViewset is not defined!")
model = self.serializer_class.Meta.model
instance = get_object_or_404(model, **kwargs)
serializer = self.get_serializer(instance)
return Response(serializer.data)
class CharacterSerializer (serializers.HyperlinkedModelSerializer):
class Meta:
model = wiki_models.Character
fields = '__all__'
class CharacterViewSet(WikiBaseViewset):
"""Called with URLs: character, character/<str: name>"""
serializer_class = CharacterSerializer
queryset = wiki_models.Character.objects.all()
detail_with_params_url_pattern_suffix = "(?P<name__iexact>. )"
Тем не менее, я борюсь с тем фактом, что декоратору абсолютно необходим параметр URL в базовом классе. В противном случае код просто не компилируется из-за жалобы NameError, которая detail_with_params_url_pattern_suffix
не определена. Если бы вы установили detail_with_params_url_pattern_suffix=""
в базовом классе, чтобы не получать ошибку при компиляции вашего кода, это все равно не имело бы значения, поскольку декоратор из моих экспериментов до сих пор все еще извлекает значение этой переменной из WikiBaseViewset
not CharacterViewSet
.
Как я могу переписать свой базовый класс, чтобы это работало? Есть ли вообще способ?
Ответ №1:
Я не нашел полностью удовлетворительного ответа на эту проблему, но в конце концов согласился с этим решением, поскольку это было лучше, чем копирование вставки.
Возможно, вы не сможете наследовать действия viewset, но вы наверняка можете наследовать отдельные методы, а затем просто перезаписать их в дочернем элементе и добавить декоратор сверху. Это приводит к такой структуре:
class WikiBaseViewset (viewsets.ModelViewSet):
detail_with_params_url_pattern_suffix: str
def detail_through_params(self, request, **kwargs):
model = self.serializer_class.Meta.model
instance = get_object_or_404(model, **kwargs)
serializer = self.get_serializer(instance)
return Response(serializer.data)
class CharacterSerializer (serializers.HyperlinkedModelSerializer):
class Meta:
model = wiki_models.Character
fields = '__all__'
class CharacterViewSet(WikiBaseViewset):
"""Called with URLs: character, character/<str: name>"""
serializer_class = CharacterSerializer
queryset = wiki_models.Character.objects.all()
@action(detail=True, url_name="detail-params", url_path="(?P<name__iexact>. )")
def detail_through_params(self, request, **kwargs):
return super().detail_through_params(request, **kwargs)