Django spanning relationships

2020-07-10 09:46发布

问题:

I've read the documentation but am still coming up with errors. I have Users placing Orders for Catalog objects. I'd like to create a query which returns all Users that have an Order containing a specific Catalog item.

Here are my models:

class Catalog(models.Model):
  name = models.CharField(max_length=100)
  price = models.IntegerField()

  def __unicode__(self):
      return self.name

class Annual(models.Model):
  catalog = models.OneToOneField(Catalog, blank=True, null=True, related_name='annual_products')
  year_id = models.IntegerField(max_length=4)
  start_date = models.CharField(max_length=10)
  end_date = models.CharField(max_length=10)
  date = models.DateTimeField(auto_now_add=True, blank=True)
  def __unicode__(self):
      return unicode(self.year_id)

class Order(models.Model):
  user = models.ForeignKey(User, related_name='who_ordered')
  select = models.ManyToManyField(Catalog, related_name='annuals_ordered', blank=True, null=True)

  def __unicode__(self):
      return unicode(self.user)

Here is the query I've been trying:

 Catalog.objects.filter(order__select__annual='2014')

回答1:

If you need users, you should start with users. Also, you need to filter on a specific field in Annual, ie year_id.

User.objects.filter(order__select__annual__year_id=2014)


回答2:

If I got your question correctly then, your query is wrong. There is no attribute name order inside your Catalog model, then how can you use it for filtering ? Or I'm missing anything here ?

Directly using the related name references on the related fields, you can get the users by using -

# id is auto generated field or you can pass one annual_product object.
User.objects.filter(who_ordered__select__annual_products__id=1)

# OR
annual = Annual.objects.all()[0]
User.objects.filter(who_ordered__select__annual_products=annual)

The step by step how you can achieve the same :-

# where 1 is the id of an one object in Catalog model.
# You can pass Catalog object also to filter the users
Order.objects.filter(select__id=1)

# Here is the full query 
catalog = Catalog.objects.all()[0]
orders = Order.objects.filter(select=catalog)
users = [o.user for o in orders]  # This loop isn't necessary.

Now you have all orders specific to one Catalog, from this you can get the user object by using the user attribute in each order.