Django, query filtering from model method

2019-01-21 21:27发布

问题:

I have these models:

def Foo(Models.model):
    size = models.IntegerField()
    # other fields

    def is_active(self):
         if check_condition:
              return True
         else:
              return False

def Bar(Models.model):
     foo = models.ForeignKey("Foo")
     # other fields

Now I want to query Bars that are having active Foo's as such:

Bar.objects.filter(foo.is_active())

I am getting error such as

SyntaxError at /
('non-keyword arg after keyword arg'

How can I achieve this?

回答1:

You cannot query against model methods or properties. Either use the criteria within it in the query, or filter in Python using a list comprehension or genex.



回答2:

You could also use a custom manager. Then you could run something like this:

Bar.objects.foo_active()

And all you have to do is:

class BarManager(models.Manager):
    def foo_active(self):
       # use your method to filter results
       return you_custom_queryset

Check out the docs.



回答3:

I had similar problem: I am using class-based view object_list and I had to filter by model's method. (storing the information in database wasn't an option because the property was based on time and I would have to create a cronjob and/or... no way)

My answer is ineffective and I don't know how it's gonna scale on larger data; but, it works:

q = Model.objects.filter(...)...
# here is the trick
q_ids = [o.id for o in q if o.method()]
q = q.filter(id__in=q_ids)


回答4:

You can't filter on methods, however if the is_active method on Foo checks an attribute on Foo, you can use the double-underscore syntax like Bar.objects.filter(foo__is_active_attribute=True)



回答5:

class Page(models.Model):
    category = models.ForeignKey(Category)
    title = models.CharField(max_length=128)
    url = models.URLField()
...

class Category(models.Model):
    ...
    open = models.BooleanField(default=True)

May be you can use simple filter, for this type of conditions.

Page.objects.filter(category__open=True)