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)),
]
Вернуться на верх