Django - DetailView - `get_object` function confusion

半腔热情 提交于 2020-03-04 05:27:49

问题


I'm new to CBV. Not sure why this isn't working...

views.py

class ItemDetailView(DetailView):
    '''display an individual item'''
    model = Item
    template_name = 'boutique/item.html'
    context_object_name = 'item'

    # With model specified, following code would be redundant, wouldn't it?? However...
    # def get_object(self):
        # return get_object_or_404(Item, pk=self.kwargs.get('item_pk'))

    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)

        # add categories for navbar link texts
        context['categories'] = Category.objects.all()

        print('\ncontext= ', context, '\n')
        return context

AttributeError at /item_8/ Generic detail view ItemDetailView must be called with either an object pk or a slug in the URLconf.

And the context isn't being printed out.


If I add get_object to the code, it's working fine:


class ItemDetailView(DetailView):
    '''display an individual item'''
    # model = Item
    template_name = 'boutique/item.html'
    # context_object_name = 'item'

    def get_object(self):
        return get_object_or_404(Item, pk=self.kwargs.get('item_pk'))

    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)

        # add categories for navbar link texts
        context['categories'] = Category.objects.all()

        print('\ncontext= ', context, '\n')
        return context

However, if I changed get_object function to:

    def get_object(self):
        obj = super().get_object()
        obj = get_object_or_404(Item, pk=self.kwargs.get('item_pk'))
        # obj = obj.filter(pk=self.kwargs.get('item_pk')) # doesn't work, same error
        # obj = obj.get(pk=self.kwargs.get('item_pk')) # doesn't work, same error

        return obj

ImproperlyConfigured at /item_8/ ItemDetailView is missing a QuerySet. Define ItemDetailView.model, ItemDetailView.queryset, or override ItemDetailView.get_queryset().

I'm confused... DetailView should work without having to define get_object at all no??


additional files:

url.py

app_name = 'boutique'
urlpatterns = [
    # show index page
    path('', views.IndexView.as_view(), name='index'),

    # show a specific item
    path('item_<int:item_pk>/', views.ItemDetailView.as_view(), name='item'),

    # show categories of products for men or women
    path('<slug:gender>/', views.CategoryListView.as_view(), name='show-all'),

    # show a specific category for men or women
    path('<slug:gender>/cat_<int:category_pk>/', views.CategoryListView.as_view(), name='category'),

    # show a specific subcategory under a specific category for men or women
    path('<slug:gender>/cat_<int:category_pk>/subcat_<int:subcategory_pk>/', views.CategoryListView.as_view(), name='subcategory'),

]

models.py

class Item(models.Model):
    '''Each item represents a product'''
    category = models.ForeignKey(Category, on_delete=models.CASCADE)
    subcategory = models.ForeignKey(
        SubCategory, on_delete=models.CASCADE, null=True, blank=True)
    name = models.CharField(max_length=100)
    description = models.TextField(blank=True)
    price = models.IntegerField(default='0')
    discount = models.IntegerField(null=True, blank=True)
    uploaded_date = models.DateTimeField(
        auto_now_add=True, null=True, blank=True)

    class Meta:
        ordering = ['-uploaded_date']

    def __str__(self):
        return self.name

    def discounted_price(self):
        '''to calculate the price after discount'''
        return int(self.price * (100 - self.discount) * 0.01)

    def get_item_url(self):
        return reverse('boutique:item', kwargs={'item_pk': self.pk})

item.html

<!-- display each item in its own box -->
<div class="col-6 col-md-4 col-lg-3 px-1 px-sm-2 d-flex flex-column">

    <!-- image anchor -->
    <a href="{{ item.get_item_url }}">
        <img class="rounded-sm" src="{{item.itemimage_set.first.image.url}}" width="100%"
    alt=""></a>
    <!-- /image anchor -->

    <!-- item price tag -->
    <div class="text-left p-1 mt-auto" style="font-size: 16px;">
        <div class="font-weight-light pt-2">
            <a href="{{ item.get_item_url }}" class="text-dark mb-1">{{item}}</a>
        </div>

        <div class="font-weight-lighter">
            {% if item.discount %}

            <p>
                <strike class="text-muted">&#8381;&nbsp;{{item.price}}</strike>
                <b class="text-danger">&#8381;&nbsp;{{item.discounted_price}}</b>
                <small class="text-danger">(-{{item.discount}}%)</small>
            </p>

            {% else %}
            <p>&#8381;&nbsp;{{item.price}}</p>

            {% endif %}
        </div>
    </div>
    <!-- /item price tag -->

</div>

回答1:


Your first example is correct, you don't need to define get_object() explicitly but you should use pk argument instead of item_pk in url path when using details CBV:

path('item_<int:pk>/', views.ItemDetailView.as_view(), name='item'),

Since by default get_object() method using self.kwargs["pk"] to search object.

If you still want to use item_pk you need to specify in in view using pk_url_kwarg:

class ItemDetailView(DetailView):
    pk_url_kwarg = 'item_pk'

From docs:

The URLconf here uses the named group pk - this name is the default name that DetailView uses to find the value of the primary key used to filter the queryset.

If you want to call the group something else, you can set pk_url_kwarg on the view. More details can be found in the reference for DetailView



来源:https://stackoverflow.com/questions/60113746/django-detailview-get-object-function-confusion

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!