Django - DetailView - `get_object` 函数混淆

Django - DetailView - `get_object` function confusion

我是 CBV 的新手。不确定为什么这不起作用...

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.

并且没有打印出上下文。


如果我在代码中添加 get_object,它工作正常:


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

但是,如果我将 get_object 函数更改为:

    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().

我很困惑...DetailView 应该可以工作而无需定义 get_object 不??


其他文件:

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>

你的第一个例子是正确的,你不需要明确定义 get_object() 但你应该在 url 路径中使用 pk 参数而不是 item_pk 使用详情 CBV:

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

因为默认 get_object() 方法使用 self.kwargs["pk"] 搜索对象。

如果您仍想使用 item_pk,则需要在视图中指定使用 pk_url_kwarg:

class ItemDetailView(DetailView):
    pk_url_kwarg = 'item_pk'

来自 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