Django generic DetailView: как лучше всего опционально включить объект, связанный с реверсом?
Фон
Модели
Допустим, у меня есть django generic DetailView, который я использую для отображения одного экземпляра модели под названием Car
. Затем допустим, что у меня есть другая модель под названием Race
. Среди многих полей эта модель Race имеет поле ForeignKey, которое связано с Car
(т. е. Car
, которое Driver
(пользователь) использовал для Race
).
Пример models.py
from django.conf import settings
class Car(models.Model):
""" a bunch of fields, including many fk fields """
class Race(models.Model):
car = models.ForeignKey(Car, on_delete=models.CASCADE, related_name="races")
driver = models.models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
""" a bunch of other fields, including fk fields """
View
Допустим, у меня есть общий DetailView
, который пользователи моего сайта уже давно используют для просмотра одного автомобильного объекта.
Пример views.py
Это очень упрощенный queryset
(мой реальный набор запросов имеет такую же структуру, но больше полей, связанных с обратными связями, с соответствующими связанными полями).
from django.views import generic
class CarDetailView(generic.DetailView):
model = Car
queryset = Car.objects.select_related(
""" a bunch of related fields """
).prefetch_related(
""" some reverse related fields """,
Prefetch(""" a reverse related field """, SomeReverseRelatedField.objects.select_related(""" some of its related fields """)),
)
Новая функция :)
Однако недавно я реализовал способ, с помощью которого мои пользователи могут "управлять" автомобилем в гонке прямо из этого DetailView. У меня есть API django ninja, включенный в мое приложение Django, и я использую vanilla js, чтобы мои пользователи могли создавать объект Race
, а затем выполнять последующие действия, создающие дополнительные, вложенные объекты, которые являются другими полями с внешними ключами для Race
, которые они только что создали. Это своего рода мини-приложение внутри моего общего веб-приложения django.
До появления этой новой функции мой шаблон для этого вида был чрезвычайно плотным и сложным. С этой новой функцией он стал еще более плотным и сложным.
Проблема
У меня все отлично работает, но мне нужен способ, чтобы пользователи могли получить доступ к Race
и связанному с ним Car
объекту позже способом, который почти идентичен текущему Car
DetailView.
Итак, все сводится к необязательному Race
объекту, который я хотел бы прикрепить к моему Car
DetailView.
Я не хочу создавать копию своего шаблона, которая просто начинается на одном уровне с Car (т.е. делать DetailView для Race
и рефакторить мой существующий шаблон для Car
, чтобы получить доступ к объекту Car
(и всем его многочисленным связанным объектам) через его обратную связь Race
). Я хотел бы сохранить мой текущий шаблон и просто использовать условные теги шаблона Django и условные блоки javascript для добавления деталей Race
в случае наличия переменной сессии, указывающей на Race
.
Потенциальное решение
Рабочий процесс будет выглядеть следующим образом:
- Пользователь нажимает на ссылку, связанную с объектом
Race
- Простой вид перенаправления будет
- создаст переменную сессии с
Race
объектом pk - перенаправить пользователя на
Car
DetailView
- создаст переменную сессии с
Car
DetailView, если есть "гоночная" переменная сессии, создаст контекстную переменную дляRace
объекта (я бы обработал это вget_context_data()
методе представления)- Шаблон будет включать данные из объекта
Race
по мере необходимости (вместе со скрытым элементом ввода или чем-то, что запускает условный блок javascript).
Вопрос
- Не будет ли вышеописанное слишком запутанным способом решения этой проблемы? Есть ли более простой способ, который позволит избежать дублирования моего шаблона (что приведет к головной боли при обслуживании дублирования в будущем)?
- Как я буду работать с кверисетом с необязательным объектом, связанным с реверсом?
- (мне не нужны все связанные с реверсом
Race
объекты; мне нужен только один). Я бы поместил такую строку в ветвь методаget_context_data()
, которая будет запущена при наличии сессионной переменной "race_id":context['race'] = Race.objects.filter(pk=self.request.session['race_pk'])
но как мне эффективно запросить ее?
- (мне не нужны все связанные с реверсом