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">₽ {{item.price}}</strike>
<b class="text-danger">₽ {{item.discounted_price}}</b>
<small class="text-danger">(-{{item.discount}}%)</small>
</p>
{% else %}
<p>₽ {{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
我是 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">₽ {{item.price}}</strike>
<b class="text-danger">₽ {{item.discounted_price}}</b>
<small class="text-danger">(-{{item.discount}}%)</small>
</p>
{% else %}
<p>₽ {{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