В моем проекте Django есть несколько моделей с одним похожим полем — "comment"
.
Я хочу создать UpdateView
для обновления только этого поля. Я могу сделать это, написав UpdateView
для каждой модели. Но мне интересно, могу ли я написать один UpdateView
класс для каждой из этих моделей, если функциональность класса одинакова, нужно изменить только имя модели.
Чтобы ваш код оставался СУХИМ, вы можете использовать такой подход:
# 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)),
]
Вы также можете установить атрибут
model
илиqueryset
вместо добавления пользовательского атрибутаmanager
. Они должны присутствовать «из коробки» в соответствующих представлениях на основе классов.