Reputation: 691
I have created a a class based view that inherits CreateView
which dynamically generates a form based on the url parameters. I have other Views that also have the same functions but they do redirect to the ListView
but this CBV gives 404 error with request url : http://127.0.0.1:8000/create/StudentPerformance/tblstandard/
(StudentPerformance is app_label, tblstandard is model_label) which is the url for below CreateView. And I am getting an Attribute Error: Generic detail view ModelObjectCreateView must be called with either an object pk or a slug in the URLconf.
Only showing create view but ModelObjectUpadteView, ModelObjectDeleteView that work are of the same structure and they work.
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
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'),
I have seen other SO posts for the error but and I tried them too but they are not helping. I also though of giving a fixed url to see if success_url even works but it dosent.
Edit : Showing Both generic.py (my extened generic views) file and the urls.py for further reference : 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)
urls.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'),
]
Upvotes: 1
Views: 354
Reputation: 21812
In your get_success_message
method you call get_object
which tries to get the object using the kwargs passed to the view. Instead you should use the instance attribute object
that is set by form_valid
after creating the object:
def get_success_message(self, cleaned_data):
return self.success_message % dict(
cleaned_data,
object=self.object,
)
Note: You appear to have lot's of code repeating in your classes, consider making a mixin to prevent this.
Upvotes: 1