views:

40

answers:

1

I've got two models. One represents a piece of equipment, the other represents a possible attribute the equipment has. Semantically, this might look like:

  • Equipment: tractor, Attributes: wheels, towing
  • Equipment: lawnmower, Attributes: wheels, blades
  • Equipment: hedgetrimmer, Attributes: blades

I want to make queries like,

wheels = Attributes.objects.get(name='wheels')
blades = Attributes.objects.get(name='blades')

Equipment.objects.filter(has_attribute=wheels) \
    .exclude(has_attribute=blades)

How can I create Django models to do this?

This seems simple, but I'm just too dense to see the right solution.

One solution that popped into my head is to encode the list of Attribute IDs in an integer list like |109|14|3 and test for attributes using Equipment.objects.filter(attributes_contains='|%d|' % id) -- but this seems really wrong.

+1  A: 

Your second example is pretty close, but you need to understand how the QuerySet API works across relationships (i.e. joins).

class Attribute(models.Model):
    name = models.CharField(max_length=20)

class Equipment(models.Model):
    name = models.CharField(max_length=20)
    attributes = models.ManyToManyField(Attribute)

equips = Equipment.objects.filter(
    attributes__name='wheels').exclude(attributes__name='blades')

You can use Q objects in your QuerySet to do more interesting queries.

And keep in mind you can always dump the SQL from a QuerySet like this:

print equips.query.as_sql()

Sometimes you'll want to see the exact SQL being generated to make sure you're using the API correctly.

Joe Holloway
This helps. Thanks!
a paid nerd