Почему мы вызываем super().get_queryset() в методе get_queryset в Django?
У меня есть метод в моем проекте Django:
определение get_queryset(self): набор запросов = super(OrderListView, self).get_queryset() возвращает набор запросов.фильтр(инициатор=self.request.user) Я не понимаю, почему мы используем queryset = super(OrderListView, self).get_queryset() внутри get_queryset.
Какова цель этой строки? Что именно она делает? Почему мы вызываем super() здесь? Почему мы вызываем один и тот же метод (get_queryset) внутри него самого? Я пытался разобраться в этом, но объяснения пока не прояснили мне ситуацию. Я был бы признателен за простой и удовлетворяющий меня ответ.
Прежде чем вы сможете вернуть отфильтрованный набор запросов, у вас должен быть набор запросов, который можно фильтровать. Итак, первая строка извлекает набор запросов каким-либо образом, определенным в суперклассе. Затем вторая строка возвращает его отфильтрованную версию.
def get_queryset(self):
# 1. Get the original queryset
queryset = super(OrderListView, self).get_queryset()
# 2. Filter the queryset
return queryset.filter(initiator=self.request.user)
Для этого есть несколько причин.
Прежде всего, ListView
можно создать QuerySet
двумя способами: указав атрибут .model
или атрибут .queryset
. Таким образом, если бы вы использовали self.queryset
, это не сработало бы для ListView
, где вы используете .model
подход, подобный:
from django.views.generic import ListView
class MyListView(ListView):
model = MyModel
# 🖟 will ***not*** work
def get_queryset(self):
return self.queryset.filter(initiator=self.request.user)
Во-вторых, .get_queryset()
из MultipleObjectMixin
, который является комбинацией, которая дает ListView
метод .get_queryset()
, также упорядочивает набор запросов, если .ordering
определено, или .get_ordering()
возвращает что-то отличное от None
.
Вы также можете задать свои собственные миксины, например, с помощью:
class ActiveItemsMixin:
def get_queryset(self):
return super().get_queryset().filter(active=True)
и смешайте его в виде:
class MyListView(ActiveItemsMixin, ListView):
# …
Тогда super().get_queryset()
, таким образом, вернет элементы, у которых есть active=True
, и, таким образом, вы можете "связать" операции фильтрации и, таким образом, определить полезные миксины.
Примечание: С тех пор как PEP-3135 [pep], вам не нужно вызывать
super(…)
с параметрами, если первым параметром является класс, в котором вы определяете метод, а вторым - первый параметр (обычноself
) функции.
Я думаю, вам нужно понять основы объектно-ориентированного программирования и концепцию переопределения.
По сути, когда вы наследуете от родительского/базового класса, вы наследуете все свойства и методы этого класса, которые теперь доступны в вашем дочернем классе.
Могут быть случаи, когда вам нужно переопределить метод, но вы все равно хотите сохранить части реализаций метода из родительского класса.
Помните о DRY - Не повторяйтесь, в этом случае вам не нужно изобретать велосипед или реализовывать эти функции заново, вы можете просто вызвать super().method_name()
, чтобы сделать эти реализации доступными в методе вашего дочернего класса, и изменить его. в противном случае функции метода из родительского класса будут недоступны.
Я приведу вам пример ниже. Рассмотрим следующие классы фигур и квадратов.
Класс Square наследуется от Shape и переопределяет область, а также описывает методы, обеспечивающие более конкретную реализацию квадрата. Однако он по-прежнему вызывает super().area() и super().describe() для повторного использования логики родительского класса, а затем добавляет дополнительное поведение.
class Shape:
def __init__(self, length, width):
self.length = length
self.width = width
def area(self):
# Default implementation for a generic shape
return self.length * self.width
def describe(self):
return f"This is a shape with side length {self.length} and side width {self.width}."
class Square(Shape):
def __init__(self, side_length):
super().__init__(side_length, side_length) # Initialize the parent class
def area(self):
# Call the parent class's area() method
parent_area = super().area()
print(f"Parent class area: {parent_area}")
# Add specific logic for a square
square_area = self.side_length ** 2
print(f"Square area: {square_area}")
return square_area
def describe(self):
# Extend the parent class's describe() method
parent_description = super().describe()
return f"{parent_description} Specifically, this is a square."
*** ТЕСТИРОВАНИЕ ***
# Create a Square object
square = Square(5)
# Call the overridden area() method
print("Area of the square:", square.area())
# outputs => Parent class area: 25
# outputs => Area of the square: 25
# Call the overridden describe() method
print(square.describe())
# outputs => This is a shape with side length 5 and side width 5. Specifically, this is a square.
Как вы можете видеть в выходных данных области для квадратного объекта, мы переопределили площадь и описать методы, но мы вызываем super().area()
и super().describe()
, чтобы сделать доступными свойства родительских методов и внести в них изменения.
Теперь в вашем случае в Django, где вы должны вызвать queryset = super(OrderListView, self).get_queryset()
.
Он отвечает за вызов родительской функции get_queryset(), которая имеет несколько реализаций, одна из которых отвечает за выборку объектов из базы данных. Это, конечно, абстрагировано.
Очевидно, что вы выполняете фильтрацию результатов по извлеченным объектам, и в качестве альтернативы вы могли бы написать логику для извлечения объектов с нуля, но это излишне, и вы, по сути, будете повторять логику.
Конечно, есть особые случаи, когда вам не нужны реализации методов из базового/родительского класса, и совершенно нормально не использовать super().
Помните, что одна из важных особенностей наследования классов и методов заключается в том, что, по сути, вы можете писать поддерживаемые и повторно используемые коды, в то время как вы сосредотачиваете свое внимание на другой логике.