“ ReverseManyToOneDescriptor”对象没有属性“ all”

时间:2018-08-21 13:59:06

标签: python django

我是Django的新手,我正在尝试通过Category模型访问属于类别的产品。我在Product中使用外键进行分类。 这些是我的模型:

class Category(models.Model):
    name = models.CharField(max_length=140)
    slug = models.SlugField(blank=True)

    def __str__(self):
        return self.name

    def get_absolute_url(self):
        return reverse("shop:category", kwargs= 
                {"category_slug": self.slug})

class Product(models.Model):
    category = models.ForeignKey(Category, 
                               on_delete=models.CASCADE)
    brand = models.ForeignKey(Brand, 
                               on_delete=models.CASCADE)
    title = models.CharField(max_length=200)
    slug = models.SlugField()
    description = models.TextField()
    image = models.ImageField(upload_to=image_name)
    price = models.PositiveIntegerField()
    avaliable = models.BooleanField(default=True)

    def get_absolute_url(self):
         return reverse("shop:product", kwargs={
                       "product_slug": self.slug,                                           
                       "product_ctgr_slug": 
                                   self.category.slug,})

我的观点:

class CategoryDetailView(DetailView):
    model = Category
    category_products = Category.product_set.all()
    slug_url_kwarg = "category_slug"

    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        context['categories'] = self.categories
        context['category_products'] = self.category_products
        return context

但是Django给了我AttributeError: 'ReverseManyToOneDescriptor' object has no attribute 'all'
我在做什么错了?

3 个答案:

答案 0 :(得分:2)

这可能有帮助:

def get_context_data(self, **kwargs):
    context = super().get_context_data(**kwargs)
    instance = self.get_object()
    context['categories'] = self.categories
    context['category_products'] = instance.product_set.all()
    return context

答案 1 :(得分:1)

您可以使用product_set作为Django默认创建的相关名称,也可以自己更好地创建相关名称。 产品属于类别,但是类别可以具有许多 product 。遵循这一原则,并使您的查询易于阅读。

为此,请在类category中为Product设置相关名称:

category = models.ForeignKey(
    Category,
    on_delete=models.CASCADE,
    related_name='products'
)

现在您必须在views.py中进行一些更改。

class CategoryDetailView(DetailView):
    model = Category
    # remove the line below
    category_products = Category.product_set.all()
    # don't prefix the fields like this, it's ugly and redundant
    # call it just slug, not category_slug, adjust in urls.py
    slug_url_kwarg = "category_slug"

    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        # where did you get self.categories?
        context['categories'] = self.categories
        # and this won't work anymore too
        context['category_products'] = self.category_products
        return context

CategoryDetailView中,您将只显示一个类别。它是详细视图-仅表示一个对象。因此,您不会使用类别之类的东西。该对象在方法中可用。这是我们重写它的方式:

def get_context_data(self, **kwargs):
    context = super().get_context_data(**kwargs)
    products = self.object.products.all()
    context['products'] = products
    return context

答案 2 :(得分:0)

真正的问题是原始发布者试图从而不是从实例调用RelatedManager.all()函数。

category_products = Category.product_set.all()

Category 是类名。既然是类,它不会也不可能知道单个实例的相关产品。

您必须从实例而不是类本身调用 RelatedManagers.all() 函数。