Django 过滤和查询:在views.py、模板或过滤器中进行?

Posted

技术标签:

【中文标题】Django 过滤和查询:在views.py、模板或过滤器中进行?【英文标题】:Django filtering and querying: do it in views.py, template, or filters? 【发布时间】:2015-03-12 06:41:00 【问题描述】:

所以我正在开发一个小型 Django 项目,目前不需要优化。但是为了为未来做准备,我想多了解一下这三种方法。

例如,作为模型的一部分,我有 UserUserProfileTransaction

class User(models.Model):
    name = ...
    email = ...

class UserProfile(models.Model):
    user = models.ForeignKey(User, related_name='profile')
    photo = models.URLField(...)
    ...

class Transaction(models.Model):
    giver = models.ForeignKey(User, related_name="transactions_as_giver")
    receiver = models.ForeignKey(User, related_name='transactions_as_receiver')
    ...

我经常需要执行类似“返回transactionsrequest.usergiverreceiver”之类的操作,或者“返回用户的个人资料照片”。我有几种选择,例如获取待处理交易列表和双方的photos,我可以在views.py 级别进行:

1.

#views.py
transactions = Transaction.objects.filter(Q(giver=request.user)|Q(receiver=request.user))
for transaction in transactions:
    giver_photo = transactions.giver.profile.all()[0].photo
    # or first query UserProfile by
    # giver_profile = UserProfile.objects.get(user=transaction.giver),
    # then giver_photo = giver_profile.photo
    # 
    # Then same thing for receiver_photo
    transaction['giver_photo'] = giver_photo
    ...

    或者我可以在template 级别上做更多:

    # some template
    <!-- First receive transactions from views.py without photo data -->
    % for t in transactions %
    t.giver.profile.all.0.photo, ...
    % endfor %
    

    或者我可以将上述部分甚至全部内容移至filters.py

    # some template
     for t in request.user|pending_transactions 
     t.giver|photo    t.receiver|photo 
     endfor 
    

其中photopending_transactions 与原始views.py 中的代码大致相同,但已移至过滤器。

所以我想知道是否有关于如何选择哪种方法的最佳实践/指南?

从 Django 文档来看,低级别更快,因此 2. 3. 应该比 1 慢;但是比较 2. 和 3. 怎么样?

在获取用户照片时,应该推荐两者中的哪一个,transactions.giver.profile.all()[0].photo OR profile = UserProfile.objects.get(...) --&gt; photo = profile.photo

【问题讨论】:

查看:docs.djangoproject.com/en/1.7/misc/design-philosophies/… 【参考方案1】:

将此逻辑移动到模型和管理器中。视图和模板必须尽可能短。

class User(models.Model):
    ...
    def transactions(self):
        return Transaction.objects.filter(Q(giver=self)|Q(receiver=self))

    def photo(self):
        return self.profile.all().first().photo

所以模板将是:

% for t in request.user.transactions %
     t.giver.photo    t.receiver.photo 
% endfor %

我的经验表明,模型中的业务逻辑比视图/模板中的业务逻辑更容易测试、支持和重用。

【讨论】:

我明白了。所以应该推荐链接return self.profile.all()...而不是profile = UserProfile.objects.get(...);return profile.photo 在大多数情况下是的。顺便说一句,我建议将UserProfileUser 之间的关系从ForeignKey 更改为OneToOne。这将允许您像 user.profile 而不是 user.profile.all()[0] 一样简单地访问用户的个人资料

以上是关于Django 过滤和查询:在views.py、模板或过滤器中进行?的主要内容,如果未能解决你的问题,请参考以下文章

Django 自定义模板标签和过滤器

Django自定义模板标签和过滤器

django模板中的自定义过滤器

django Tips

django Tips

如何过滤django模板中的特殊字符