Django 通过中间表从多个对象获取多个对象
有没有一种简单的方法可以从返回多个对象的查询中获取多个对象?我现在做这件事的方式并不像我希望的那样性感。在我看来,我现在是这样做的:Django 通过中间表从多个对象获取多个对象,django,django-models,django-templates,Django,Django Models,Django Templates,有没有一种简单的方法可以从返回多个对象的查询中获取多个对象?我现在做这件事的方式并不像我希望的那样性感。在我看来,我现在是这样做的: contacts = Contact.objects.all() # Use Custom Manager Method to Fetch Each Contacts Phone Numbers contacts = PhoneNumber.objects.inject(contacts) 我的模型: class PhoneNumber(models.Model
contacts = Contact.objects.all()
# Use Custom Manager Method to Fetch Each Contacts Phone Numbers
contacts = PhoneNumber.objects.inject(contacts)
我的模型:
class PhoneNumber(models.Model):
number = models.CharField()
type = models.CharField()
# My Custom Manager
objects = PhoneNumberManager()
class Contact(models.Model):
name = models.CharField()
numbers = models.ManyToManyField(PhoneNumber, through='ContactPhoneNumbers')
class ContactPhoneNumbers(models.Model):
number = models.ForeignKey(PhoneNumber)
contact = models.ForeignKey(Contact)
ext = models.CharField()
我的客户经理:
class PhoneNumberManager(models.Manager):
def inject(self, contacts):
contact_ids = ','.join([str(item.id) for item in contacts])
cursor = connection.cursor()
cursor.execute("""
SELECT l.contact_id, l.ext, p.number, p.type
FROM svcontact_contactphonenumbers l, svcontact_phonenumber p
WHERE p.id = l.number_id AND l.contact_id IN(%s)
""" % contact_ids)
result = {}
for row in cursor.fetchall():
id = str(row[0])
if not id in result:
result[id] = []
result[id].append({
'ext': row[1],
'number': row[2],
'type': row[3]
})
for contact in contacts:
id = str(contact.id)
if id in result:
contact.phonenumbers = result[id]
return contacts
这里有几件事可以让你找到性感:-) Django没有任何OOTB方法将through表的属性注入到Contact实例中。带有额外数据的M2M表是一个SQL概念,因此Django不会试图处理这些关系,也不会猜测在名称空间冲突等情况下会发生什么。事实上,我甚至想说,您可能不想将任意模型属性注入到您的联系人对象中。。。如果您发现自己需要这样做,那么这可能是您应该修改模型定义的标志 相反,Django提供了在查询和数据检索中无缝访问关系的方便方法,同时保留了实体的完整性。在这种情况下,您会发现您的
Contact
对象提供了一个contactphonenumbers\u set
属性,您可以使用该属性访问直通数据:
>>> c = Contact.objects.get(id=1)
>>> c.contactphonenumbers_set.all()
# Would produce a list of ContactPhoneNumbers objects for that contact
这意味着,在您的情况下,要迭代所有联系电话号码(例如),您将:
for contact in Contact.objects.all():
for phone in contact.contactphonenumbers_set.all():
print phone.number.number, phone.number.type, phone.ext
如果你真的,真的,真的出于某种原因想进行注入,你会发现你可以使用上面的3行代码示例来完成:只需将print语句更改为赋值语句
另一方面,仅供将来参考,您可以在不使用SQL语句的情况下编写注入函数。在Django中,through表本身就是一个模型,因此您可以直接查询它:
def inject(self, contacts):
contact_phone_numbers = ContactPhoneNumbers.objects.\
filter(contact__in=contacts)
# And then do the result construction...
# - use contact_phone_number.number.phone to get the phone and ext
# - use contact_phone_number.contact to get the contact instance
嗯,我可能做错了。运行:cons=Contact.objects.all()!联系人电话号码=联系人电话号码。objects.select\u related().filter(contact\uu in=contacts)非常性感。我想知道它是否足够聪明,不会再拉联系人了。。过一会儿我就要检查这个查询了。酷!我忘了提到select_related(),很高兴您尝试了它。Django可以缓存查询集,但不能缓存对象拉()。换句话说,如果定义queryset并将其分配给变量,它将只执行一次。但是,我不会跨两个完全不同的查询集缓存对象检索。