[Django]-'ReverseManyToOneDescriptor' object has no attribute 'all'

1๐Ÿ‘

โœ…

You can use product_set as related name created by default in Django, or you can better create a related name yourself. A product belongs to a category, but a category can have many products. Follow this principle and make your queries human readable.

For this purpose set the related name for category in the class Product:

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

Now in your views.py you have to make some changes.

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

In the CategoryDetailView youโ€™re going to display just one Category. It is detailed view โ€“ it implies just a single object. Therefore youโ€™re not using something like categories. The object is available in the method. This is how we rewrite it:

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

5๐Ÿ‘

The real problem is that the original poster tried to call the RelatedManager.all() function from the class instead of from an instance.

category_products = Category.product_set.all()

Category is the class name. Since it is the class, it does does not and cannot know about the related products of a single instance.

You have to call the RelatedManagers.all() function from an instance, not the class itself.

๐Ÿ‘คTorsten

2๐Ÿ‘

This may help:

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
๐Ÿ‘คChristo

Leave a comment