1

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.

asked Feb 7, 2014 at 19:35

2 Answers 2

6

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"
answered Feb 7, 2014 at 20:12
Sign up to request clarification or add additional context in comments.

1 Comment

This looks better. However, would it be possible to have AbstractManager and no other classes? I.e. construct the Manager class in the model definition?
1

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.

answered Feb 10, 2014 at 9:36

Comments

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.