给定模式:
class Investor(models.Model):
name = models.CharField(max_length=30)
advisors = models.ManyToManyField("Advisor", related_name="investors", through="Connection")
class Advisor(models.Model):
name = models.CharField(max_length=30)
class Connection(models.Model):
investor = models.ForeignKey("Investor", related_name="connections", on_delete=models.CASCADE)
advisor = models.ForeignKey("Advisor", related_name="connections", on_delete=models.CASCADE)
blocked = models.BooleanField(default=False)
并给予顾问";a";,获取所有投资者的列表以及他们与"投资者"的连接的最佳方式是什么;a";它什么时候存在?
到目前为止,我发现最好的是:
from django.db.models import Prefetch
for investor in Investor.objects.prefetch_related(
Prefetch(
'connections',
queryset=Connection.objects.filter(advisor=a),
to_attr='connection',
)
):
name = investor.name
blocked = None
if investor.connection:
blocked = investor.connection[0].blocked
print(f"{name} (blocked={blocked})")
更新
我找到了一种让使用上述策略更愉快的方法:
class WithConnection:
def __init__(self, queryset):
self.queryset = queryset
def __iter__(self):
for model in self.queryset:
connection = model.my_connections[0] if model.my_connections else None
yield model, connection
class InvestorQuerySet(models.QuerySet):
def pov(self, advisor):
return WithConnection(
self.prefetch_related(models.Prefetch(
'connections',
queryset=Connection.objects.filter(advisor=advisor),
to_attr='my_connections',
))
)
像这样使用:
advisor = Advisor.objects.first()
for investor, connection in Investor.objects.pov(advisor):
# do stuff with investor
if connection:
# do stuff with connection
希望在这方面有所改进。Django的ORM非常强大,似乎应该有一种更简单的方法来实现这一点。
我认为你只是想要
a.investor_set.all()
经过大量的研究和迭代,我得到了这个解决方案:
class WithConnectionQuerySet(models.QuerySet):
def __iter__(self):
return map(
lambda m: (m, m.my_connections[0]) if m.my_connections else (m, None),
super().__iter__(),
)
class Investor(models.Model):
...
@classmethod
def viewed_by(cls, advisor):
manager = cls._default_manager.__class__.from_queryset(WithConnectionQuerySet)()
manager.model = cls
return manager.prefetch_related(models.Prefetch(
'connections',
queryset=Connection.objects.filter(advisor=advisor),
to_attr='my_connections',
))
像这样使用:
advisor = Advisor.objects.first()
for investor, connection in Investor.viewed_by(advisor).filter(age__gt=40):
# do stuff with investor
if connection:
# do stuff with connection
我仍然不是100%的兴奋,但我喜欢它现在开始使用它。如果有人有更好的答案,请插话。