views:

302

answers:

2

I'm attempting to use a similar Category implementation to this one in the Django Wiki. I'm wondering what the Django way of doing a search to pull all objects associated with a parent category. For example, if I have a category "TV" and it has subcategories "LED", "LCD", and "Plasma", how would I be able to easily query for all TV's without recursively going through all subcategories and subsubcategories (if there are any).

Code wise I was thinking something like:

class Item(models.Model):
   name = ...
   ...
   category = models.ForeignKey(Category, null=True, blank=True)

so with this type of implementation is there any easy way to do what I need, or is there any other better solution?

Thank you!

+3  A: 

Assuming you're using the Category model the same way it's being used on the page you referenced, it would seem that a category 'TV' would be a Category instance with a null parent, and 'Plasma' & 'LCD' would be Category instances with the 'TV' category as a parent.

>>> tv=Category(name="TV")
>>> tv.save()
>>> lcd=Category(name="LCD", parent=tv)
>>> lcd.save()
>>> plasma=Category(name="Plasma", parent=tv)
>>> plasma.save()

Create some items

>>> vizio=Item(name="Vizio", category=lcd)
>>> vizio.save()
>>> plasmatron=Item(name="PlasmaTron", category=plasma)
>>> plasmatron.save()

Get the Item queryset

>>> items=Item.objects.filter(category__parent=tv)

or

>>>> items=Item.objects.filter(category__parent__name='TV')

Does this look like it's in the ballpark of what you need?

czarchaic
Would this be able to do subsubcategories? For instance, if Vizio was actually another category and then there was an item like this: specific_model_number = Item(name="model43534", category=vizio)wouldn't "items=Item.objects.filter(category__parent=tv)"not return the specific_model_number object in the result set?
Jordan Messina
Can you edit your post, or add an answer with the type of code you'll be using and outline your concerns? I am trying to understand exactly what you need. For instance in the queryset above, when looping through it, each item would have a name and a `Category`. Is it possible in your application for a category to have `vizio` as a parent (i.e. sub sub categories)?
czarchaic
Yes a category could have vizio as a parent. My concern is that a queryset wont return every item within a subset of the category tree. If I had a queryset just for "category__parent=tv" would I get all the "vizio" items returned even though they are 2 nodes down the tree? I don't know how to edit the post to explain it better so I apologize because it's confusing and I really appreciate your help so far.
Jordan Messina
I'm leaving for work, so I'll update when I get home, but a quick question. Does the code in my response look like what your app expects. (i.e. are we on the right track?). Can you give me some ideas as to what type of `Category` might have `lcd` or `plasma` as a parent?
czarchaic
This is absolutely on track! I was just using TVs as an example, and maybe it's not the best example. Let's say a "TV" can be "HD" or "SD". For "HD" then there's "LCD" and "Plasma". And further, under "LCD" there is a "Vizio" category, how would a queryset that has arguments "category__parent=tv" return all the Items categorized as Vizio. The Vizio parent is "LCD", not "TV", so it wouldn't be returned, but I want all TVs that fall under the "TV" category, so it should be returned.
Jordan Messina
Hi Jordan, another quick question before I dive back into your code. How deep can the categories go? Would it be possible to have a category `40inch` with a parent `flatscreen` which itself has a parent `vizio` whose parent is `lcd` whose parent is `tv`? (hypothetically speaking)
czarchaic
+4  A: 

If you want to enforce strict categories and subcategories but also have the ability to perform fast searches with results like you describe, you may want to make a "tag" table where you don't actually allow users to tag items themselves, but rather as soon as you assign a category to an item you fill in the tag table for that item with all the parent categories up to the root node of the category tree.

For example, if you have the following: alt text

The tag table would look something like:

   id   |   tag_name   |   tv_id
   1    |     "tv"     |     1
   2    |     "sd"     |     1    
   3    |     "crt"    |     1  
   4    |     "tv"     |     2  
   5    |     "HD"     |     2  
   6    |     "LCD"    |     2  
   7    |     "tv"     |     3  
   8    |     "HD"     |     3  
   9    |   "plasma"   |     3

Now your queryset will look like items=Item.objects.filter(tag='TV')

gohnjanotis