Django Одно представление для разных моделей
В моем проекте Django есть несколько моделей с одним похожим полем - "comment"
.
Я хочу создать UpdateView
для обновления только этого одного поля. Я могу сделать это, написав UpdateView
для каждой модели. Но мне интересно, могу ли я написать один класс UpdateView
для каждой из этих моделей, если функциональность класса одинакова, нужно изменить только имя модели.
Чтобы сохранить DRY-код, вы можете использовать такой подход:
# recommended option
from django.views.generic.edit import UpdateView
from myapp.models import Author, AnotherModel
class CommentUpdateView(UpdateView):
fields = ["comment"]
def get_queryset(self):
if not hasattr(self, 'model') or not self.model:
raise AttributeError("CommentUpdateView requires 'model' attribute.")
return self.model.objects.all()
# Then, for each model, you create a specific view:
class AuthorCommentUpdateView(CommentUpdateView):
model = Author
class AnotherModelCommentUpdateView(CommentUpdateView):
model = AnotherModel
Только ОДИН UpdateView для всех моделей, содержащих поле комментария, - плохая идея. Потому что модель должна быть передана в UpdateView в качестве параметра во время выполнения. Единственный способ передать что-то в представление - через url. Это дает пользователю полный доступ к проверке существующих моделей и раскрывает ваши данные. Поскольку вы просили именно об этом - вот, пожалуйста:
# NOT recommended option
# views.py
from django.views.generic.edit import UpdateView
from django.apps import apps
from django.http import Http404
class DynamicCommentUpdateView(UpdateView):
fields = ["comment"]
def get_queryset(self):
model_name = self.kwargs.get('model_name')
if model_name:
try:
model = apps.get_model('myapp', model_name)
if 'comment' not in [field.name for field in model._meta.fields]:
raise ValueError("Model does not have 'comment' field.")
return model.objects.all()
except (LookupError, ValueError):
raise Http404("No model found with the given name that has a 'comment' field.")
else:
raise AttributeError("DynamicCommentUpdateView requires 'model_name' in URL kwargs.")
# urls.py
from django.urls import path
from .views import DynamicCommentUpdateView
urlpatterns = [
path('<str:model_name>/<int:pk>/update/', DynamicCommentUpdateView.as_view(), name='dynamic-update'),
]
Вышеприведенный код определяет по строке в url, какая модель должна быть обновлена. Как уже было сказано, плохая идея.
Установите экземпляр models.Manager
на View
во время инстанцирования. Когда вы в конечном итоге инстанцируете View
в случае class
на основе View
, вы можете использовать метод as_view()
, чтобы переопределить атрибуты, установленные на class
для различных экземпляров class
.
Этот пример устанавливает атрибут queryset
для View
, UpdateView
. Затем он переопределяет этот атрибут в as_view()
:
class UpdateView(View):
queryset = None
def put(self, request):
self.queryset.all().update(comment="")
return HttpResponse("All comments have been cleared.")
urlpatterns = [
path("clear-all-model1-comments/", UpdateView.as_view(queryset=Model1.objects)),
path("clear-all-model2-comments/", UpdateView.as_view(queryset=Model2.objects)),
path("clear-all-model3-comments/", UpdateView.as_view(queryset=Model3.objects)),
]