【问题标题】:django call related model queryset like rails activerecord merge scopedjango 调用相关模型查询集,如 rails activerecord 合并范围
【发布时间】:2026-02-17 14:40:02
【问题描述】:

假设我们有两个模型 Account 和 Profile:

class Profile < ApplicationRecord
    belongs_to :account
    scope :age_upper, ->(age) { where("age > ?", age) }
end

class Account < ApplicationRecord
    has_one :profile
end

然后我们可以像这样在 Rails 中查询 Account 模型:

>>> Account.joins(:profile).merge(Profile.age_upper(18))

但是对于 Django:

class ProfileQuerySet(models.QuertSet):
    def age_upper(age):
        return self.filter(age__gt=age)

class Profile(models.Model):
    account = models.ForiegnKey('Account', on_delete=models.CASCADE)

    objects = models.Manager.from_queryset(ProfileQuerySet)()


class Account(models.Model):
    pass

我的问题是我们可以使用 Profile 的过滤器 age_upper 从 Account 查询,而不是像下面那样为 Account 重写另一个

class AccountQuerySet(models.QuertSet):
    def age_upper(age):
        return self.filter(profile__age__gt=age)

class Account(models.Model):
    objects = models.Manager.from_queryset(AccountQuerySet)()

【问题讨论】:

    标签: python ruby-on-rails django orm


    【解决方案1】:

    在 Rails 中,您不能使用一个模型的范围来查询另一个模型(至少使用 ActiveRecord)。即使您能找到实现此目的的方法,也可能不是实现此目的的最佳方法。

    如果您不想再次编写范围或其他共享逻辑,您可以使用这样的关注点:

    # app/models/concerns/shared_scopes.rb
    module SharedScopes
      extend ActiveSupport::Concern
    
      included do
        scope :age_upper, ->(age) { where("age > ?", age) }
      end
    end
    

    然后将此问题包含在您需要此行为的所有模型中:

    # app/models/profile.rb
    class Profile < ApplicationRecord
      include SharedScopes
      belongs_to :account
    end
    
    # app/models/account.rb
    class Account < ApplicationRecord
      include SharedScopes
      has_one :profile
    end
    

    【讨论】:

    • 也许你误解了我的问题,我的意思是我想在 django 中执行类似 rails 的查询。顺便说一句,在你的回答中,如果我做Account.age_upper(18),它会触发错误,因为Account 没有age 属性
    • 确实,这是 ruby​​ 代码,他要的是 python 代码。此外,他是对的,是的,您可以在 ActiveRecord 中“使用一个模型的范围来查询另一个模型”,并且 OP 演示了如何。