diff --git django/views/generic/detail.py django/views/generic/detail.py
index 7e9047f..1802b33 100644
|
|
class SingleObjectMixin(object):
|
15 | 15 | queryset = None |
16 | 16 | slug_field = 'slug' |
17 | 17 | context_object_name = None |
| 18 | slug_url_kwarg = 'slug' |
| 19 | pk_url_kwarg = 'pk' |
18 | 20 | |
19 | 21 | def get_object(self, queryset=None): |
20 | 22 | """ |
… |
… |
class SingleObjectMixin(object):
|
29 | 31 | queryset = self.get_queryset() |
30 | 32 | |
31 | 33 | # Next, try looking up by primary key. |
32 | | pk = self.kwargs.get('pk', None) |
33 | | slug = self.kwargs.get('slug', None) |
| 34 | pk = self.kwargs.get(self.get_pk_url_kwarg(), None) |
| 35 | slug = self.kwargs.get(self.get_slug_url_kwarg(), None) |
34 | 36 | if pk is not None: |
35 | 37 | queryset = queryset.filter(pk=pk) |
36 | 38 | |
… |
… |
class SingleObjectMixin(object):
|
74 | 76 | """ |
75 | 77 | return self.slug_field |
76 | 78 | |
| 79 | def get_slug_url_kwarg(self): |
| 80 | """ |
| 81 | Get the name of the URL keyword to be used to look up by slug. |
| 82 | """ |
| 83 | return self.slug_url_kwarg |
| 84 | |
| 85 | def get_pk_url_kwarg(self): |
| 86 | """ |
| 87 | Get the name of the URL keyword to be used to look up by pk. |
| 88 | """ |
| 89 | return self.pk_url_kwarg |
| 90 | |
77 | 91 | def get_context_object_name(self, obj): |
78 | 92 | """ |
79 | 93 | Get the name to use for the object. |
diff --git docs/ref/class-based-views.txt docs/ref/class-based-views.txt
index e9f3152..8698161 100644
|
|
SingleObjectMixin
|
136 | 136 | The name of the field on the model that contains the slug. By default, |
137 | 137 | ``slug_field`` is ``'slug'``. |
138 | 138 | |
| 139 | .. attribute:: slug_url_kwarg |
| 140 | |
| 141 | The name of the URL keyword that contains the slug. By default, |
| 142 | ``slug_url_kwarg`` is ``'slug'``. |
| 143 | |
| 144 | .. attribute:: pk_url_kwarg |
| 145 | |
| 146 | The name of the URL keyword that contains the primary key. By default, |
| 147 | ``pk_url_kwarg`` is ``'pk'``. |
| 148 | |
139 | 149 | .. attribute:: context_object_name |
140 | 150 | |
141 | 151 | Designates the name of the variable to use in the context. |
… |
… |
SingleObjectMixin
|
146 | 156 | ``queryset`` is provided, that queryset will be used as the |
147 | 157 | source of objects; otherwise, |
148 | 158 | :meth:`~SingleObjectMixin.get_queryset` will be used. |
149 | | :meth:`~SingleObjectMixin.get_object` looks for a ``pk`` |
150 | | argument in the arguments to the view; if ``pk`` is found, |
151 | | this method performs a primary-key based lookup using that |
152 | | value. If no ``pk`` argument is found, it looks for a ``slug`` |
| 159 | :meth:`~SingleObjectMixin.get_object` looks for a |
| 160 | :attr:`SingleObjectMixin.pk_url_kwarg` argument in the arguments |
| 161 | to the view; if this argument is found, this method performs a |
| 162 | primary-key based lookup using that value. If this argument is not |
| 163 | found, it looks for a :attr:`SingleObjectMixin.slug_url_kwarg` |
153 | 164 | argument, and performs a slug lookup using the |
154 | 165 | :attr:`SingleObjectMixin.slug_field`. |
155 | 166 | |
diff --git tests/regressiontests/generic_views/detail.py tests/regressiontests/generic_views/detail.py
index e8f2050..cd55d26 100644
|
|
class DetailViewTest(TestCase):
|
21 | 21 | self.assertEqual(res.context['author'], Author.objects.get(pk=1)) |
22 | 22 | self.assertTemplateUsed(res, 'generic_views/author_detail.html') |
23 | 23 | |
| 24 | def test_detail_by_custom_pk(self): |
| 25 | res = self.client.get('/detail/author/bycustompk/1/') |
| 26 | self.assertEqual(res.status_code, 200) |
| 27 | self.assertEqual(res.context['object'], Author.objects.get(pk=1)) |
| 28 | self.assertEqual(res.context['author'], Author.objects.get(pk=1)) |
| 29 | self.assertTemplateUsed(res, 'generic_views/author_detail.html') |
| 30 | |
24 | 31 | def test_detail_by_slug(self): |
25 | 32 | res = self.client.get('/detail/author/byslug/scott-rosenberg/') |
26 | 33 | self.assertEqual(res.status_code, 200) |
27 | 34 | self.assertEqual(res.context['object'], Author.objects.get(slug='scott-rosenberg')) |
28 | 35 | self.assertEqual(res.context['author'], Author.objects.get(slug='scott-rosenberg')) |
29 | 36 | self.assertTemplateUsed(res, 'generic_views/author_detail.html') |
| 37 | |
| 38 | def test_detail_by_custom_slug(self): |
| 39 | res = self.client.get('/detail/author/bycustomslug/scott-rosenberg/') |
| 40 | self.assertEqual(res.status_code, 200) |
| 41 | self.assertEqual(res.context['object'], Author.objects.get(slug='scott-rosenberg')) |
| 42 | self.assertEqual(res.context['author'], Author.objects.get(slug='scott-rosenberg')) |
| 43 | self.assertTemplateUsed(res, 'generic_views/author_detail.html') |
30 | 44 | |
31 | 45 | def test_verbose_name(self): |
32 | 46 | res = self.client.get('/detail/artist/1/') |
diff --git tests/regressiontests/generic_views/urls.py tests/regressiontests/generic_views/urls.py
index 067c1f6..dc86e4d 100644
|
|
urlpatterns = patterns('',
|
30 | 30 | url(r'^detail/author/(?P<pk>\d+)/$', |
31 | 31 | views.AuthorDetail.as_view(), |
32 | 32 | name="author_detail"), |
| 33 | (r'^detail/author/bycustompk/(?P<foo>\d+)/$', |
| 34 | views.AuthorDetail.as_view(pk_url_kwarg='foo')), |
33 | 35 | (r'^detail/author/byslug/(?P<slug>[\w-]+)/$', |
34 | 36 | views.AuthorDetail.as_view()), |
| 37 | (r'^detail/author/bycustomslug/(?P<foo>[\w-]+)/$', |
| 38 | views.AuthorDetail.as_view(slug_url_kwarg='foo')), |
35 | 39 | (r'^detail/author/(?P<pk>\d+)/template_name_suffix/$', |
36 | 40 | views.AuthorDetail.as_view(template_name_suffix='_view')), |
37 | 41 | (r'^detail/author/(?P<pk>\d+)/template_name/$', |