Suppose that we have following models
class Category(models.Model):
name = models.CharField(max_length=254)
class Item(models.Model):
category = models.ForeignKey(Category, on_delete=models.CASCADE, related_name="items")
name = models.CharField(max_length=254)
state = models.ForeignKey(State, on_delete=models.CASCADE)
Categories and their items are listed like so
def view(request):
categories = Category.objects.all()
pass
{% for category in categories %}
{{ category.name }}
{% for item in category.items.all %}
{{ item.name }}
{% endfor %}
{% endfor %}
In this structure, I want to write on-request filtering for listed ‘items’.
def view(request):
...
queryset = ???
state = request.GET.get('state')
if state:
queryset = queryset.filter(state__name=state)
The problem is defining ‘queryset’. Because, Items are listed as related objects of category.
Can it be done properly? or Do I need to change design?
You can take a look at my low fidelity design to be more clear.
You could use a Prefetch
object. Give that a look and let me know if you have questions.
1 Like
@CodenameTim, Thank you for the reply.
Firstly, I’m trying to get queryset using Prefetch.
In the document, the sample is,
Question.objects.prefetch_related(Prefetch('choice_set')).get().choice_set.all()
So when I use this for me,
items = Category.objects.prefetch_related(Prefetch('items')).get().items.all()
error : MultipleObjectsReturned → get() returned more than one Category – it returned 8!
Then, I try to use filter() instead of get()
items = Category.objects.prefetch_related(Prefetch('items')).filter().items.all()
error: QuerySet’ object has no attribute ‘items’
How can I fix this?
It sounds like there may be a misunderstanding with some other parts of the ORM. The first error, MultipleObjectsReturned, is because .get()
expects one and only one value to be returned, otherwise it errors. It’s defensive mechanism of the ORM. You may be interested in the .first()
function when you really only care about getting some value or None
back. Please check out the ORM’s queryset documentation for more extensive information.
The second error is due to attempting to access the property items
which is does not exist on a QuerySet
which is what’s being returned by .filter()
. If you’re looking to explore the orm, try .first()
to get an instance rather than get
, but be careful of the implications.
1 Like