Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Writing a manager to filter query set results

I have the following code:

class GroupDepartmentManager(models.Manager):
  def get_query_set(self):
    return super(GroupDepartmentManager, self).get_query_set().filter(group='1')

class Department(models.Model):
 name = models.CharField(max_length=128)
 group = models.ForeignKey(Group)
 def __str__(self):
    return self.name
 objects = GroupDepartmentManager()

... and it works fine. Only thing is that I need to replace group='1' with group=(the group specified by group = models.ForeignKey(Group)). I am having quite a time trying to determine whether that foreign key needs to be passed into the class, or into the get_query_set function, or what. I know that you can accomplish this with group.department_set.filter(group=desired group), but I am writing this model for the admin site, so I need to use a variable and not a constant after the = sign.

like image 614
John Avatar asked Dec 23 '09 18:12

John


People also ask

Can you filter a QuerySet?

Working with Filter Easily the most important method when working with Django models and the underlying QuerySets is the filter() method, which allows you to generate a QuerySet of objects that match a particular set of filtered parameters.

What is a QuerySet?

A QuerySet represents a collection of objects from your database. It can have zero, one or many filters. Filters narrow down the query results based on the given parameters. In SQL terms, a QuerySet equates to a SELECT statement, and a filter is a limiting clause such as WHERE or LIMIT .

Why might you want to write a custom model manager?

Custom managers. You can use a custom Manager in a particular model by extending the base Manager class and instantiating your custom Manager in your model. There are two reasons you might want to customize a Manager : to add extra Manager methods, and/or to modify the initial QuerySet the Manager returns.


2 Answers

I have a hunch that replacing the default Manager on objects in this manner might not be good idea, especially if you're planning on using the admin site... Even if it helps you with your Employees, it won't help you at all when handling Departments. How about a second property providing a restricted view on Departments alongside the usual objects? Or move the standard Manager from objects to _objects and rename from_same_group to objects if you really prefer your original approach for your app.

class Department(models.Model):
    name = models.CharField(max_length=128)
    group = models.ForeignKey(Group)
    def __str__(self):
        return self.name
    objects = models.Manager()

    @property
    def from_same_group(self):
        return Department.objects.filter(group__exact=self.group)

Also, I understand you know how to set up the admin site to take advantage of the funny Manager; if not (or if I misunderstood your question somehow), leave a comment, I'll try to follow up sometime soon.


EDIT: OK, to make this more clear: if you do absolutely insist on replacing objects, you'd probably want to do this:

class Department(models.Model):
    name = models.CharField(max_length=128)
    group = models.ForeignKey(Group)
    def __str__(self):
        return self.name

    _objects = models.Manager()

    @property
    def objects(self):
        # note the _objects in the next line
        return Department._objects.filter(group__exact=self.group)
like image 72
Michał Marczyk Avatar answered Sep 21 '22 03:09

Michał Marczyk


You might want to reconsider the relationship between the groups and departments if you find that trying to create a custom manager is too complex. Managers excel at simplifying common queries, but flop at displaying complex relationships between models and instances of models.

However, I think this article about filtering model objects with a custom manager will point you in the right direction. The author proposes a technique to perform a function call that returns a customized manager class that has the filter parameters you specify saved in the class so they don't get passed to the instance. Do it!

like image 35
jathanism Avatar answered Sep 19 '22 03:09

jathanism