How do I properly use a UUID id as a url parameter in Django?
Question:
I’ve been trying to pass a UUID4 id into the url for a specific detail page.
After browsing Stackoverflow and other sites, here’s what I’ve tried so far:
- Passing the url path as
path('car/<uuid:id>/', views.CarDetailView.as_view(), name='car-detail'),
But this raises the error: Generic detail view CarDetailView must be called with either an object pk or a slug in the URLconf..
Since the uuid field is composed of both letters and numbers, I can’t use an int.
- So I used this:
path(r"^(?P<car_model>w+)/$", views.CarDetailView.as_view(), name='car-detail'),
which returns the messy and broken url: showroom/%5E(%3FP09c32f72-5863-49fa-a42a-1d0fed274c4e%5Cw+)/$
- Then I tried reverting to the original, but using a def_object method in the View class.
def get_object(self):
object = get_object_or_404(CarInstance,title=self.kwargs['car_model'])
return object
But this returns the error: “KeyError at /showroom/car/09c32f72-5863-49fa-a42a-1d0fed274c4e/
‘car_model'”
models.py
class CarInstance(models.Model):
manufacturer = models.ForeignKey('Manufacturer', on_delete=models.SET_NULL, null=True)
car_model = models.CharField('Model', max_length=50, null=True)
views.py
class CarDetailView(generic.DetailView):
model = CarInstance
template_name = 'car_detail'
def get_queryset(self):
return CarInstance.objects.all()
def get_object(self):
object = get_object_or_404(CarInstance,title=self.kwargs['car_model'])
return object
def get_absolute_url(self):
return reverse('showroom:car-detail', args=[str(self.pk)])
The urls should be be formatted as showroom/car/09c32f72-5863-49fa-a42a-1d0fed274c4e/, which brings up the detail view for the specific object.
Any ideas?
Update
According to the answer below, I changed the get_object override to
slug_field = 'title'
slug_url_kwarg = 'car_detail'
But I’m still getting the same urlconf must be called with slug or int error. Should I define the slugh in the models?
Update 2
I’ve changed the urlconf, but it’s raising the same error. Here’s the full traceback
Environment:
Request Method: GET
Request URL: http://localhost:8000/showroom/car/09c32f72-5863-49fa-a42a-1d0fed274c4e/
Django Version: 2.2.5
Python Version: 3.7.4
Installed Applications:
['django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'showroom']
Installed Middleware:
['django.middleware.security.SecurityMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.common.CommonMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware']
Traceback:
File "C:UsersUSEREnvstorquelibsite-packagesdjangocorehandlersexception.py" in inner
34. response = get_response(request)
File "C:UsersUSEREnvstorquelibsite-packagesdjangocorehandlersbase.py" in _get_response
115. response = self.process_exception_by_middleware(e, request)
File "C:UsersUSEREnvstorquelibsite-packagesdjangocorehandlersbase.py" in _get_response
113. response = wrapped_callback(request, *callback_args, **callback_kwargs)
File "C:UsersUSEREnvstorquelibsite-packagesdjangoviewsgenericbase.py" in view
71. return self.dispatch(request, *args, **kwargs)
File "C:UsersUSEREnvstorquelibsite-packagesdjangoviewsgenericbase.py" in dispatch
97. return handler(request, *args, **kwargs)
File "C:UsersUSEREnvstorquelibsite-packagesdjangoviewsgenericdetail.py" in get
106. self.object = self.get_object()
File "C:UsersUSEREnvstorquelibsite-packagesdjangoviewsgenericdetail.py" in get_object
47. "pk or a slug in the URLconf." % self.__class__.__name__
Exception Type: AttributeError at /showroom/car/09c32f72-5863-49fa-a42a-1d0fed274c4e/
Exception Value: Generic detail view CarDetailView must be called with either an object pk or a slug in the URLconf.
** Another update **
Thanks to help from @ruddra, I changed the path to match the slug_url_kwarg = ‘car_detail’ It looks like this now:
path('car/<slug:car_detail>/', views.CarDetailView.as_view(), name='car-detail')
However, now the page raises a 404 error.
Page not found (404)
Request Method: GET
Request URL: http://localhost:8000/showroom/car/09c32f72-5863-49fa-a42a-1d0fed274c4e/
Raised by: showroom.views.CarDetailView
No car instance found matching the query
Answers:
You don’t need to override get_object()
method. You can simply use slug_url_kwarg
and slug_field
. Like this:
class CarDetailView(generic.DetailView):
model = CarInstance
template_name = 'car_detail'
slug_field = 'title'
slug_url_kwarg = 'car_model'
More information can be found in get_object()
documentation.
- Create get_absolute_url() in models.py:
def get_absolute_url(self):
return reverse('car-detail', args=[str(self.<yourUUIDFieldName>)]) # self.car_model
- Set URL in urls.py:
urlpatterns = [
path('car/<uuid:yourUUIDFieldName>/', # 'car:<uuid:car_model'>
views.CarDetailView.as_view(), name='car-detail'),
]
- Try to change the views:
class CarDetailView(DetailView):
model = CarInstance
slug_field = '<uuid:yourUUIDFieldName>' # -> 'car_model'
slug_url_kwarg = '<uuid:yourUUIDFieldName>' # -> 'car_model'
template_name = 'car_detail.html'
- In addition try this if you like:
import uuid
car_model = models.UUIDField(default=uuid.uuid4, unique=True)
Replace yourUUIDFieldName
with car_model
check if this works,
in my way, i have no idea, i’m just a beginner like others, hope u get something out of it
Although this is too late.However, someone could find it helpful.You can modify your modules as below:
Your models.py:
import uuid as uuid_lib
class CarInstance(models.Model):
manufacturer = models.ForeignKey('Manufacturer', on_delete=models.SET_NULL, null=True)
car_model = models.CharField('Model', max_length=50, null=True)
uuid = models.UUIDField(
db_index=True,
default=uuid_lib.uuid4,
editable=False,
unique=True,)
urls.py:
path('car/<uuid:uuid>/', views.CarDetailView.as_view(), name='car-detail'),
Lastly your views.py:
class CarDetailView(generic.DetailView):
model = CarInstance
template_name = 'car_detail'
slug_field = 'uuid'
slug_url_kwarg = 'uuid'
I’ve been trying to pass a UUID4 id into the url for a specific detail page.
After browsing Stackoverflow and other sites, here’s what I’ve tried so far:
- Passing the url path as
path('car/<uuid:id>/', views.CarDetailView.as_view(), name='car-detail'),
But this raises the error: Generic detail view CarDetailView must be called with either an object pk or a slug in the URLconf..
Since the uuid field is composed of both letters and numbers, I can’t use an int.
- So I used this:
path(r"^(?P<car_model>w+)/$", views.CarDetailView.as_view(), name='car-detail'),
which returns the messy and broken url: showroom/%5E(%3FP09c32f72-5863-49fa-a42a-1d0fed274c4e%5Cw+)/$
- Then I tried reverting to the original, but using a def_object method in the View class.
def get_object(self):
object = get_object_or_404(CarInstance,title=self.kwargs['car_model'])
return object
But this returns the error: “KeyError at /showroom/car/09c32f72-5863-49fa-a42a-1d0fed274c4e/
‘car_model'”
models.py
class CarInstance(models.Model):
manufacturer = models.ForeignKey('Manufacturer', on_delete=models.SET_NULL, null=True)
car_model = models.CharField('Model', max_length=50, null=True)
views.py
class CarDetailView(generic.DetailView):
model = CarInstance
template_name = 'car_detail'
def get_queryset(self):
return CarInstance.objects.all()
def get_object(self):
object = get_object_or_404(CarInstance,title=self.kwargs['car_model'])
return object
def get_absolute_url(self):
return reverse('showroom:car-detail', args=[str(self.pk)])
The urls should be be formatted as showroom/car/09c32f72-5863-49fa-a42a-1d0fed274c4e/, which brings up the detail view for the specific object.
Any ideas?
Update
According to the answer below, I changed the get_object override to
slug_field = 'title'
slug_url_kwarg = 'car_detail'
But I’m still getting the same urlconf must be called with slug or int error. Should I define the slugh in the models?
Update 2
I’ve changed the urlconf, but it’s raising the same error. Here’s the full traceback
Environment:
Request Method: GET
Request URL: http://localhost:8000/showroom/car/09c32f72-5863-49fa-a42a-1d0fed274c4e/
Django Version: 2.2.5
Python Version: 3.7.4
Installed Applications:
['django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'showroom']
Installed Middleware:
['django.middleware.security.SecurityMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.common.CommonMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware']
Traceback:
File "C:UsersUSEREnvstorquelibsite-packagesdjangocorehandlersexception.py" in inner
34. response = get_response(request)
File "C:UsersUSEREnvstorquelibsite-packagesdjangocorehandlersbase.py" in _get_response
115. response = self.process_exception_by_middleware(e, request)
File "C:UsersUSEREnvstorquelibsite-packagesdjangocorehandlersbase.py" in _get_response
113. response = wrapped_callback(request, *callback_args, **callback_kwargs)
File "C:UsersUSEREnvstorquelibsite-packagesdjangoviewsgenericbase.py" in view
71. return self.dispatch(request, *args, **kwargs)
File "C:UsersUSEREnvstorquelibsite-packagesdjangoviewsgenericbase.py" in dispatch
97. return handler(request, *args, **kwargs)
File "C:UsersUSEREnvstorquelibsite-packagesdjangoviewsgenericdetail.py" in get
106. self.object = self.get_object()
File "C:UsersUSEREnvstorquelibsite-packagesdjangoviewsgenericdetail.py" in get_object
47. "pk or a slug in the URLconf." % self.__class__.__name__
Exception Type: AttributeError at /showroom/car/09c32f72-5863-49fa-a42a-1d0fed274c4e/
Exception Value: Generic detail view CarDetailView must be called with either an object pk or a slug in the URLconf.
** Another update **
Thanks to help from @ruddra, I changed the path to match the slug_url_kwarg = ‘car_detail’ It looks like this now:
path('car/<slug:car_detail>/', views.CarDetailView.as_view(), name='car-detail')
However, now the page raises a 404 error.
Page not found (404)
Request Method: GET
Request URL: http://localhost:8000/showroom/car/09c32f72-5863-49fa-a42a-1d0fed274c4e/
Raised by: showroom.views.CarDetailView
No car instance found matching the query
You don’t need to override get_object()
method. You can simply use slug_url_kwarg
and slug_field
. Like this:
class CarDetailView(generic.DetailView):
model = CarInstance
template_name = 'car_detail'
slug_field = 'title'
slug_url_kwarg = 'car_model'
More information can be found in get_object()
documentation.
- Create get_absolute_url() in models.py:
def get_absolute_url(self):
return reverse('car-detail', args=[str(self.<yourUUIDFieldName>)]) # self.car_model
- Set URL in urls.py:
urlpatterns = [
path('car/<uuid:yourUUIDFieldName>/', # 'car:<uuid:car_model'>
views.CarDetailView.as_view(), name='car-detail'),
]
- Try to change the views:
class CarDetailView(DetailView):
model = CarInstance
slug_field = '<uuid:yourUUIDFieldName>' # -> 'car_model'
slug_url_kwarg = '<uuid:yourUUIDFieldName>' # -> 'car_model'
template_name = 'car_detail.html'
- In addition try this if you like:
import uuid
car_model = models.UUIDField(default=uuid.uuid4, unique=True)
Replace yourUUIDFieldName
with car_model
check if this works,
in my way, i have no idea, i’m just a beginner like others, hope u get something out of it
Although this is too late.However, someone could find it helpful.You can modify your modules as below:
Your models.py:
import uuid as uuid_lib
class CarInstance(models.Model):
manufacturer = models.ForeignKey('Manufacturer', on_delete=models.SET_NULL, null=True)
car_model = models.CharField('Model', max_length=50, null=True)
uuid = models.UUIDField(
db_index=True,
default=uuid_lib.uuid4,
editable=False,
unique=True,)
urls.py:
path('car/<uuid:uuid>/', views.CarDetailView.as_view(), name='car-detail'),
Lastly your views.py:
class CarDetailView(generic.DetailView):
model = CarInstance
template_name = 'car_detail'
slug_field = 'uuid'
slug_url_kwarg = 'uuid'