Reputation: 2979
I lack Python metaprogramming knowledge here. Let's say I have the following:
class OwnCompanyManager(models.Manager):
"""Only companies of this user"""
def get_queryset(self, user):
if user.is_superuser:
return super(OwnCompanyManager, self).get_queryset()
return super(OwnCompanyManager, self).get_queryset().filter(
companyuser__user=user)
class OwnPublisherManager(models.Manager):
"""Only publishers of this user's company"""
def get_queryset(self, user):
if user.is_superuser:
return super(OwnPublisherManager, self).get_queryset()
return super(OwnPublisherManager, self).get_queryset().filter(
company__companyuser__user=user)
class Company(models.Model):
name = models.CharField(max_length=45)
objects = models.Manager()
own = OwnCompanyManager()
class Publisher(models.Model):
company = models.ForeignKey(Company)
allow_latest_dev = models.BooleanField(default=False)
domains_blocked = models.BooleanField(default=False)
objects = models.Manager()
own = OwnPublisherManager()
I have many more than that. I dislike the copy-paste boilerplate Own(Publisher|Company|Etcetra)Manager)
. The only change is, as you can see, in the filter.
How can I abstract Own(InsertModelNameHere)Manager
and use it from Company
, Publisher
and other models? I would like to specify the filter kwargs in manager definition.
Upvotes: 1
Views: 2914
Reputation: 2979
Inspired by Daniel's reply:
class OwnManager(models.Manager):
def __init__(self, key):
super(OwnManager, self).__init__()
self.k = key
def get_queryset(self, user):
if user.is_superuser:
return super(OwnManager, self).get_queryset()
return super(OwnManager, self).get_queryset().filter(**{self.k: user})
class Company(models.Model):
name = models.CharField(max_length=45)
objects = models.Manager()
own = OwnManager("companyuser__user")
class Publisher(models.Model):
company = models.ForeignKey(Company)
allow_latest_dev = models.BooleanField(default=False)
domains_blocked = models.BooleanField(default=False)
objects = models.Manager()
own = OwnManager("company__companyuser__user")
That way I don't want to create stupid class for every model.
Thanks Daniel.
Upvotes: 1
Reputation: 599630
There's no need for metaprogramming or anything particularly clever here. You just need to extract the bits that change. In this case, it's just the arguments to filter
: you can use the dictionary form of argument passing, and store the filter as a string in a class attribute.
class AbstractManager(models.Manager):
def get_queryset(self, user):
if user.is_superuser:
return super(AbstractManager, self).get_queryset()
return super(AbstractManager, self).get_queryset().filter(**{self.filter: user})
class OwnCompanyManager(AbstractManager):
filter = "companyuser__user"
class OwnPublisherManager(AbstractManager):
filter = "company__companyuser__user"
Upvotes: 6