2

我创建了一个基于类的视图,它继承CreateView了它根据 url 参数动态生成一个表单。我有其他视图也具有相同的功能,但它们确实重定向到ListView但这个 CBV 给出了 404 错误请求 url:http://127.0.0.1:8000/create/StudentPerformance/tblstandard/(StudentPerformance 是 app_label,tblstandard 是 model_label)这是 CreateView 下面的 url。我得到一个Attribute Error: Generic detail view ModelObjectCreateView must be called with either an object pk or a slug in the URLconf.

创建视图

仅显示创建视图,但工作的 ModelObjectUpadteView、ModelObjectDeleteView 具有相同的结构并且它们工作。

class ModelObjectCreateView(SuccessMessageMixin, PermissionRequiredMixin, LoginRequiredMixin, CreateView):
    context_object_name = 'object'
    app_label = ""
    model_label = ""
    fields_label = ""
    template_label = ""
    success_label = ""
    success_message = f"%(object)s successfully created!!!"

    def dispatch(self, request, *args, **kwargs):
        self.app_label = kwargs.get('app_label', None)
        self.model_label = kwargs.get('model_label', None)
        self.model = apps.get_model(self.app_label, self.model_label.capitalize())
        self.get_modelobject_fields_label()

        self.template_label = kwargs.get('template_label', None)
        self.template_name = self.get_template_name_label()

# ----------------------------------
# success_url is assigned
# ----------------------------------
        self.success_url = self.get_success_url_label()

        self.permission_required = self.get_permissions_required_label()
        try:
            ret = super(ModelObjectCreateView, self).dispatch(request, *args, **kwargs)
        except AttributeError as e:
            print(e)
            raise Http404
        return ret

    def form_valid(self, form):
        form.instance.created_by = self.request.user
        return super().form_valid(form)

    def get_template_name_label(self):
        if self.template_label == '0':
            template_name = f'{self.app_label}/{self.model_label}_create.html'
        elif self.template_label:
            path = self.template_label.split("-")
            file = ""
            for folder in path:
                file += folder + "/"
            template_name = f'{file[:-1]}.html'
        else:
            template_name = 'modelobject_create.html'
        return template_name

    def get_modelobject_fields_label(self, form1=None):
        if not form1 is None:
            self.form_class = form1
        else:
            model_label = list()
            field_label = list()
            for app in apps.get_app_configs():
                for model in app.get_models():
                    model_label.append(model._meta.verbose_name.replace(" ", ""))
            field_labels = self.model._meta.get_fields()
            for field in field_labels:
                if field.name == f'{self.model.objects.model._meta.db_table}_id':
                    pass
                elif field.name in model_label:
                    pass
                elif not field.editable:
                    pass
                else:
                    field_label.append(field.name)
            self.fields = field_label
        return 0

# -------------------------------------------------------------
# This creates the success url that is assigned to self.success_url in dispatch() method.
# -------------------------------------------------------------
    def get_success_url_label(self):
        if self.success_label == "0":
            success_url = 'modelobject_success_url.html'
        elif self.success_label == "1":
            success_url = f'{self.app_label}/{self.model_label}_success_url.html'
        elif self.success_label:
            success_url = self.success_label
        else:
            success_url = reverse('MySchoolHome:modelobject_list_view',
                                  kwargs={'app_label': self.app_label, 'model_label': self.model_label})
        return success_url

    def get_success_message(self, cleaned_data):
        return self.success_message % dict(
            cleaned_data,
            object=self.get_object(),
        )

    def get_permissions_required_label(self, permission=None, permission_type=None):
        if permission is not None:
            permission_required_label = permission
        else:
            if permission_type is None:
                permission_required_label = f'{self.app_label}.add_{self.model_label}'
            else:
                return HttpResponse(status=403)
        return permission_required_label

Urls.py(摘录)

app_name = 'MySchoolHome'

urlpatterns += [
    path('list/<str:app_label>/<str:model_label>/',
         views.MshModelListView.as_view(extra_context={'page_context': {'titleTag': '1'}}),
         name='modelobject_list_view'),
    path('list/<str:app_label>/<str:model_label>/<str:template_label>/',
         views.MshModelListView.as_view(extra_context={'page_context': {'titleTag': '1'}}),
         name='modelobject_list_view'),

    path('create/<str:app_label>/<str:model_label>/',
         generic.ModelObjectCreateView.as_view(extra_context={'page_context': {'titleTag': '1'}}),
         name='modelobject_create_view'),
    path('create/<str:app_label>/<str:model_label>/<int:pk>/',
         generic.ModelObjectCreateView.as_view(extra_context={'page_context': {'titleTag': '1'}}),
         name='modelobject_create_view'),
    path('create/<str:app_label>/<str:model_label>/<str:template_label>/',
         generic.ModelObjectCreateView.as_view(), name='modelobject_create_view'),

我已经看到其他关于该错误的 SO 帖子,但我也尝试过它们,但它们没有帮助。我也想给出一个固定的 url 来查看 success_url 是否有效,但它并不有效。

编辑:同时显示 generic.py(我的扩展通用视图)文件和 urls.py 以供进一步参考: generic.py

from django.contrib import messages
from django.contrib.auth.mixins import LoginRequiredMixin, PermissionRequiredMixin
from django.contrib.messages.views import SuccessMessageMixin
from django.http import Http404, HttpResponse
from django.apps import apps
from django.template.exceptions import TemplateDoesNotExist
from django.urls import reverse_lazy, reverse
from django.views.generic import ListView, CreateView, DetailView, UpdateView, DeleteView
from django.contrib.auth import views as auth_views


class ModelObjectListView(PermissionRequiredMixin, LoginRequiredMixin, ListView):
    context_object_name = 'object'
    app_label = ""
    model_label = ""
    template_label = ""
    paginate_by = 25

    def dispatch(self, request, *args, **kwargs):
        self.app_label = kwargs.get('app_label', None)
        self.model_label = kwargs.get('model_label', None)
        self.model = apps.get_model(self.app_label, self.model_label.capitalize())

        self.template_label = kwargs.get('template_label', None)
        self.template_name = self.get_template_name_label()
        self.permission_required = self.get_permissions_required_label()
        try:
            ret = super(ModelObjectListView, self).dispatch(request, *args, **kwargs)
        except AttributeError:
            raise Http404
        return ret

    def get_queryset(self):
        filters = {}
        for key, value in self.request.GET.items():
            if key != "page":
                if value != '':
                    filters[f'{key}__icontains'] = value
        filter_list = self.model.objects.filter(**filters)
        return filter_list

    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        context['fields'] = [
            field for field in self.get_modelobject_fields_label()
        ]
        context['display_fields'] = [
            field.replace('_', ' ').title() for field in self.get_modelobject_fields_label()
        ]
        return context

    def get_modelobject_fields_label(self, form1=None):
        model_label = list()
        field_label = list()
        display_field_label = list()
        for app in apps.get_app_configs():
            for model in app.get_models():
                model_label.append(model._meta.verbose_name.replace(" ", ""))
        field_labels = self.model._meta.get_fields()
        for field in field_labels:
            if field.name == f'{self.model.objects.model._meta.db_table}_id':
                pass
            elif field.name in model_label:
                pass
            # elif not field.editable:
            #     pass
            else:
                field_label.append(field.name)
        return field_label

    def get_template_name_label(self):
        if self.template_label == '0':
            template_name = f'{self.app_label}/{self.model_label}_create.html'
        elif self.template_label:
            path = self.template_label.split("-")
            file = ""
            for folder in path:
                file += folder + "/"
            template_name = f'{file[:-1]}.html'
        else:
            template_name = 'modelobject_list.html'
        return template_name

    def get_permissions_required_label(self, permission=None, permission_type=None):
        if permission is not None:
            permission_required_label = permission
        else:
            if permission_type is None:
                permission_required_label = f'{self.app_label}.view_{self.model_label.lower()}'
            else:
                return HttpResponse(status=403)
        return permission_required_label


class ModelObjectCreateView(SuccessMessageMixin, PermissionRequiredMixin, LoginRequiredMixin, CreateView):
    context_object_name = 'object'
    app_label = ""
    model_label = ""
    fields_label = ""
    template_label = ""
    success_label = ""
    success_message = f"%(object)s successfully created!!!"

    def dispatch(self, request, *args, **kwargs):
        self.app_label = kwargs.get('app_label', None)
        self.model_label = kwargs.get('model_label', None)
        self.model = apps.get_model(self.app_label, self.model_label.capitalize())
        self.get_modelobject_fields_label()

        self.template_label = kwargs.get('template_label', None)
        self.template_name = self.get_template_name_label()

        self.success_url = self.get_success_url_label()

        self.permission_required = self.get_permissions_required_label()
        try:
            ret = super(ModelObjectCreateView, self).dispatch(request, *args, **kwargs)
        except AttributeError as e:
            print(e)
            raise Http404
        return ret

    def form_valid(self, form):
        form.instance.created_by = self.request.user
        return super().form_valid(form)

    def get_template_name_label(self):
        if self.template_label == '0':
            template_name = f'{self.app_label}/{self.model_label}_create.html'
        elif self.template_label:
            path = self.template_label.split("-")
            file = ""
            for folder in path:
                file += folder + "/"
            template_name = f'{file[:-1]}.html'
        else:
            template_name = 'modelobject_create.html'
        return template_name

    def get_modelobject_fields_label(self, form1=None):
        if not form1 is None:
            self.form_class = form1
        else:
            model_label = list()
            field_label = list()
            for app in apps.get_app_configs():
                for model in app.get_models():
                    model_label.append(model._meta.verbose_name.replace(" ", ""))
            field_labels = self.model._meta.get_fields()
            for field in field_labels:
                if field.name == f'{self.model.objects.model._meta.db_table}_id':
                    pass
                elif field.name in model_label:
                    pass
                elif not field.editable:
                    pass
                else:
                    field_label.append(field.name)
            self.fields = field_label
        return 0

    def get_success_url_label(self):
        if self.success_label == "0":
            success_url_label = 'modelobject_success_url.html'
        elif self.success_label == "1":
            success_url_label = f'{self.app_label}/{self.model_label}_success_url.html'
        elif self.success_label:
            success_url_label = self.success_label
        else:
            success_url_label = reverse('MySchoolHome:modelobject_list_view',
                                  kwargs={'app_label': self.app_label, 'model_label': self.model_label})
        return success_url_label

    def get_success_message(self, cleaned_data):
        return self.success_message % dict(
            cleaned_data,
            object=self.get_object(),
        )

    def get_permissions_required_label(self, permission=None, permission_type=None):
        if permission is not None:
            permission_required_label = permission
        else:
            if permission_type is None:
                permission_required_label = f'{self.app_label}.add_{self.model_label}'
            else:
                return HttpResponse(status=403)
        return permission_required_label


class ModelObjectUpdateView(SuccessMessageMixin, PermissionRequiredMixin, LoginRequiredMixin, UpdateView):
    context_object_name = 'object'
    app_label = ""
    model_label = ""
    fields_label = ""
    template_label = ""
    success_label = ""
    success_message = f"%(object)s successfully updated!!!"

    def dispatch(self, request, *args, **kwargs):
        self.app_label = kwargs.get('app_label', None)
        self.model_label = kwargs.get('model_label', None)
        self.model = apps.get_model(self.app_label, self.model_label.capitalize())
        self.get_modelobject_fields_label()

        self.template_label = kwargs.get('template_label', None)
        self.template_name = self.get_template_name_label()

        self.success_url = self.get_success_url_label()

        self.permission_required = self.get_permissions_required_label()
        print(self.get_permissions_required_label())
        try:
            ret = super(ModelObjectUpdateView, self).dispatch(request, *args, **kwargs)
        except AttributeError:
            raise Http404
        return ret

    def form_valid(self, form):
        form.instance.created_by = self.request.user
        return super().form_valid(form)

    def get_template_name_label(self):
        if self.template_label == '0':
            template_name = f'{self.app_label}/{self.model_label}_create.html'
        elif self.template_label:
            path = self.template_label.split("-")
            file = ""
            for folder in path:
                file += folder + "/"
            template_name = f'{file[:-1]}.html'
        else:
            template_name = 'modelobject_create.html'
        return template_name

    def get_modelobject_fields_label(self, form1=None):
        if not form1 is None:
            self.form_class = form1
        else:
            model_label = list()
            field_label = list()
            for app in apps.get_app_configs():
                for model in app.get_models():
                    model_label.append(model._meta.verbose_name.replace(" ", ""))
            field_labels = self.model._meta.get_fields()
            for field in field_labels:
                if field.name == f'{self.model.objects.model._meta.db_table}_id':
                    pass
                elif field.name in model_label:
                    pass
                elif not field.editable:
                    pass
                else:
                    field_label.append(field.name)
            self.fields = field_label
        return 0

    def get_success_url_label(self):
        if self.success_label == "0":
            success_url = 'modelobject_success_url.html'
        elif self.success_label == "1":
            success_url = f'{self.app_label}/{self.model_label}_success_url.html'
        elif self.success_label:
            success_url = self.success_label
        else:
            success_url = reverse('MySchoolHome:modelobject_list_view',
                                  kwargs={'app_label': self.app_label, 'model_label': self.model_label})
        return success_url

    def get_success_message(self, cleaned_data):
        return self.success_message % dict(
            cleaned_data,
            object=self.get_object(),
        )

    def get_permissions_required_label(self, permission=None, permission_type=None):
        if permission is not None:
            permission_required_label = permission
        else:
            if permission_type is None:
                permission_required_label = f'{self.app_label}.change_{self.model_label.lower()}'
            else:
                return HttpResponse(status=403)
        return permission_required_label


class ModelObjectDeleteView(PermissionRequiredMixin, LoginRequiredMixin, DeleteView):
    context_object_name = f'object'
    app_label = ""
    model_label = ""
    template_label = ""
    success_label = ""

    def dispatch(self, request, *args, **kwargs):
        self.model_label = kwargs.get('model_label', None)
        self.app_label = kwargs.get('app_label', None)
        self.model = apps.get_model(self.app_label, self.model_label.capitalize())

        self.template_label = kwargs.get('template_label', None)
        self.template_name = self.get_template_name_label()

        self.success_label = kwargs.get('success_label', None)
        self.success_url = self.get_success_url_label()

        self.permission_required = self.get_permissions_required_label()
        try:
            ret = super(ModelObjectDeleteView, self).dispatch(request, *args, **kwargs)
        except AttributeError:
            raise Http404
        except TemplateDoesNotExist:
            return HttpResponse(status=501)
        return ret

    def get_template_name_label(self):
        if self.template_label == "0":
            template_name = f'{self.app_label}/{self.model_label}_delete.html'
        elif self.template_label:
            path = self.template_label.split("-")
            file = ""
            for folder in path:
                file += folder + "/"
            template_name = f'{file[:-1]}.html'
        else:
            template_name = 'modelobject_confirm_delete.html'
        return template_name

    def get_success_url_label(self):
        if self.success_label == "0":
            success_url = f'{self.app_label}/{self.model_label}_success_url.html'
        elif self.success_label:
            success_url = reverse('MySchoolHome:modelobject_list_view',
                                  kwargs={'app_label': self.app_label, 'model_label': self.model_label,
                                          'template_label': self.success_label})
        else:
            success_url = reverse('MySchoolHome:modelobject_list_view',
                                  kwargs={'app_label': self.app_label, 'model_label': self.model_label})
        return success_url

    def get_permissions_required_label(self, permission=None, permission_type=None):
        if permission is not None:
            permission_required_label = permission
        else:
            if permission_type is None:
                permission_required_label = f'{self.app_label}.delete_{self.model_label}'
            else:
                return HttpResponse(status=403)
        return permission_required_label

    def delete(self, request, *args, **kwargs):
        obj = self.get_object()
        messages.success(self.request, f"{obj} successfully deleted!!!")
        return super(ModelObjectDeleteView, self).delete(request, *args, **kwargs)

网址.py

from django.urls import path
from django.contrib.auth import views as auth_views
from django.http import request
from . import views
from aagam_packages.django.view_extensions import generic

app_name = 'MySchoolHome'

urlpatterns = [
    path('sitemap/', views.sitemap, name='sitemap'),
]

urlpatterns += [
    path('login/', auth_views.LoginView.as_view(extra_context={'page_context': page_context, 'titleTag': 'Login'}),
         name='login'),
    path('logout/', auth_views.LogoutView.as_view(extra_context={'page_context': page_context, 'titleTag': 'Logout'}),
         name='logout'),
    path('change-password/', auth_views.PasswordChangeView.as_view(), name="change_password"),
    path('settings/', auth_views.LogoutView.as_view(extra_context={'page_context': page_context, 'titleTag': 'Logout'}),
         name='settings'),
    path('documentation/',
         auth_views.LogoutView.as_view(extra_context={'page_context': page_context, 'titleTag': 'Logout'}),
         name='documentation'),
]

urlpatterns += [
    path('list/<str:app_label>/<str:model_label>/',
         generic.ModelObjectListView.as_view(extra_context={'page_context': {'titleTag': '1'}}),
         name='modelobject_list_view'),
    path('list/<str:app_label>/<str:model_label>/<str:template_label>/',
         generic.ModelObjectListView.as_view(extra_context={'page_context': {'titleTag': '1'}}),
         name='modelobject_list_view'),

    path('create/<str:app_label>/<str:model_label>/',
         generic.ModelObjectCreateView.as_view(extra_context={'page_context': {'titleTag': '1'}}),
         name='modelobject_create_view'),
    path('create/<str:app_label>/<str:model_label>/<str:template_label>/',
         generic.ModelObjectCreateView.as_view(), name='modelobject_create_view'),

    path('update/<str:app_label>/<str:model_label>/<int:pk>/',
         views.MshModelUpdateView.as_view(extra_context={'page_context': {'titleTag': '1'}}),
         name='modelobject_update_view'),
    path('update/<str:app_label>/<str:model_label>/<int:pk>/<str:template_label>/',
         views.MshModelUpdateView.as_view(extra_context={'page_context': {'titleTag': '1'}}),
         name='modelobject_update_view'),

    path('delete/<str:app_label>/<str:model_label>/<int:pk>/',
         generic.ModelObjectDeleteView.as_view(), name='modelobject_delete_view'),
    path('delete/<str:app_label>/<str:model_label>/<int:pk>/<str:template_label>/',
         generic.ModelObjectDeleteView.as_view(), name='modelobject_delete_view'),
    path('delete/<str:app_label>/<str:model_label>/<int:pk>/<str:template_label>/<str:success_label>/',
         generic.ModelObjectDeleteView.as_view(), name='modelobject_delete_view'),
]

urlpatterns += [
    path('', views.home, name='home'),
    path('student/', views.student_dashboard, name='student_dashboard'),
    path('educator/', views.educator_dashboard, name='educator_dashboard'),
    path('principal/', views.principal_dashboard, name='principal_dashboard'),
    path('staff/', views.staff_dashboard, name='staff_dashboard'),
]

4

1 回答 1

1

在您get_success_message调用的方法get_object中,尝试使用传递给视图的 kwargs 获取对象。相反,您应该使用创建对象后object设置的实例属性:form_valid

def get_success_message(self, cleaned_data):
    return self.success_message % dict(
        cleaned_data,
        object=self.object,
    )

注意:您的课程中似乎有很多代码重复,请考虑制作一个 mixin 来防止这种情况。

于 2021-04-18T07:41:44.773 回答