我一直在尝试优化我在Django中的查询以减少我的postgres数据库命中,所以这里是简化这个问题的关注模型
class SentEmail(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE)
sent_date = models.DateTimeField(default=timezone.now)
sender = models.EmailField()
class AppUser(models.Model):
user= models.OneToOneField(User, primary_key=True)
is_active= models.BooleanField(default= False)
expiration_date = models.DateTimeField(default=make_default_expiration_date) #note : 90 days after the creation
User
是标准的Django auth用户,其中包含用户名,密码和其他内容。我想要做的是检索活跃用户的AppUser
各种数据以及与他们相关的最后一个SentEmail
。现在,我有这个。
active_users = Language_new.objects.filter(expiration_date__gt=timezone.now(),
is_active=True)
如果我想要包含上次发送的电子邮件,我会做这样的事情
active_users = Language_new.objects.filter(expiration_date__gt=timezone.now(),
is_active=True).prefetch_related(
Prefetch(
"sentemail",
queryset=SentEmail.objects.filter().latest('sent_date'),
to_attr="last_sentemail"
))
Django是否足够聪明,可以在这里建立关系:queryset=SentEmail.objects.filter().latest('sent_date')
?如果没有,我如何在filter()
?
另外,因为可能没有"最新的"每个sentemail
AppUser
,如何在此类查询中处理DoesNotExist?
执行此代码会得到一个AttributeError
AttributeError: 'SentEmail' object has no attribute '_iterable_class'
指着这一行:to_attr="last_sentemail"
。我不知道为什么。
请注意,我的工作解决方案如下所示:
active_users = Language_new.objects.filter(expiration_date__gt=timezone.now(),
is_active=True)
active_users = list(active_users)
for user in active_users:
last_sent_mail = SentEmail.objects.filter(user=active_user.user)
if last_sent_mail.exists():
setattr(user, 'last_sent_mail_date', last_sent_mail.latest('sent_date').sent_date)
else:
setattr(user, 'last_sent_mail_date', 'None')
它正在工作,但我认为我们都同意它并不是最好的。
注意:我在这里直接检索了上一个sentemail
的日期,但是完整的sentemail
或其日期都适用于我。
感谢。
答案 0 :(得分:1)
尝试:
class SentEmail(models.Model):
user = models.ForeignKey(
User, on_delete=models.CASCADE, related_name='sent_mails'
)
sent_date = models.DateTimeField(default=timezone.now)
sender = models.EmailField()
和
class AppUser(models.Model):
user= models.OneToOneField(User, primary_key=True)
is_active= models.BooleanField(default= False)
expiration_date = models.DateTimeField(
default=make_default_expiration_date
) #note : 90 days after the creation
@property
def last_sent_mail(self): # or last_sent_mail_date
sent_mails = self.user.sent_mails.order_by('sent_date')
return sent_mails[0] if sent_mails.exists() else None
检索上次发送的电子邮件:
last_mail = user.last_sent_mail
if last_mail:
print last_mail.sent_date