'django call related model queryset like rails activerecord merge scope

Say we have two models Account and Profile:

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

class Account < ApplicationRecord
    has_one :profile
end

Then we can have a query on Account model in Rails like this:

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

But with 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

My question is can we query from Account using filter age_upper of Profile instead of rewrite another one for Account like below

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)()


Solution 1:[1]

In Rails, you can't use a scope of one model to query another (at least with ActiveRecord). And even if you would find the way to do this that's probably not the best way to accomplish this.

If you don't want to write scopes or other shared logic again you can use concerns like that:

# app/models/concerns/shared_scopes.rb
module SharedScopes
  extend ActiveSupport::Concern

  included do
    scope :age_upper, ->(age) { where("age > ?", age) }
  end
end

And then include this concern in all model where you need this behavior:

# 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

Solution 2:[2]

you can write like below.

Account.objects.filter(profile_set__id__in=Profile.objects.age_upper(18).only('id'))

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Oleh Feilo
Solution 2 takashi