Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using Django filters inside model function

The main purpose of a model is to contain business logic, so I want most of my code inside Django model in the form of methods. For example I want to write a method named get_tasks_by_user() inside task model. So that I can access it as

Tasks.get_tasks_by_user(user_id)

Following is my model code:

class Tasks(models.Model):
    slug=models.URLField()
    user=models.ForeignKey(User)
    title=models.CharField(max_length=100)
    objects=SearchManager()
    def __unicode__(self):
        return self.title
    days_passed = property(getDaysPassed)
    def get_tasks_by_user(self,userid):
        return self.filters(user_id=userid)

But this doesn't seems to work, I have used it in view as:

    tasks = Tasks.objects.get_tasks_by_user(user_id)

But it gives following error:

'SearchManager' object has no attribute 'get_tasks_by_user'

If I remove objects=SearchManager, then just name of manager in error will change so I think that is not issue. Seems like I am doing some very basic level mistake, how can I do what I am trying to do? I know I can do same thing via :Tasks.objects.filters(user_id=userid) but I want to keep all such logic in model. What is the correct way to do so?

like image 747
Hafiz Avatar asked Nov 23 '25 07:11

Hafiz


2 Answers

An easy way to do this is by using classmethod decorator to make it a class method. Inside class Tasks:

@classmethod
def get_tasks_by_user(cls, userid):
    return cls.objects.filters(user_id=userid)

This way you can simply call:

tasks = Tasks.get_tasks_by_user(user_id)

Alternatively, you can use managers per Tom's answer.

To decided on which one to choose in your specific case, you can refer James Bennett's (the release manager of Django) blog post on when to use managers/classmethod.

like image 80
K Z Avatar answered Nov 24 '25 21:11

K Z


Any methods on a model class will only be available to instances of that model, i.e. individual objects.

For your get_tasks_by_user function to be available as you want it (on the collection), it needs to be implemented on the model manager.

class TaskManager(models.Manager):
    def get_tasks_by_user(self, user_id):
        return super(TaskManager, self).get_query_set().filter(user=user_id)

class Task(models.Model):
    # ...
    objects = TaskManager()
like image 34
Tom Avatar answered Nov 24 '25 21:11

Tom



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!