2009-07-30 68 views
56

是否可以按屬性篩選?按屬性篩選

我有一個方法,在我的模型:

@property 
def myproperty(self): 
    [..] 

,現在我想通過這個屬性就像過濾:

MyModel.objects.filter(myproperty=[..]) 

是這個莫名其妙可能嗎?

+0

它在SQLAlchemy中:http://docs.sqlalchemy.org/en/latest/orm/extensions/hybrid.html,您可以通過https://pypi.python.org/pypi/aldjemy將django與SQLAlchemy連接起來但我懷疑這兩者可以按照你希望的方式進行連接。 – rattray 2016-05-03 06:28:59

回答

47

沒有。 Django過濾器在數據庫級別運行,生成SQL。要根據Python屬性進行過濾,您必須將對象加載到Python中才能評估屬性 - 此時,您已經完成了加載它的所有工作。

+2

運氣不好,這個功能沒有實現,會是一個有趣的擴展,至少過濾出匹配對象_after_結果集已經建立。 – schneck 2009-07-30 09:24:17

+0

如何在管理員中處理它?有一些解決方法嗎? – andi 2014-02-13 14:52:48

30

我可能會誤解你的原始問題,但python中有一個filter內建函數。

filtered = filter(myproperty, MyModel.objects) 

但最好使用list comprehension

filtered = [x for x in MyModel.objects if x.myproperty()] 

,甚至更好,一個generator expression

filtered = (x for x in MyModel.objects if x.myproperty()) 
3

請有人糾正我,但我想我已經找到了解決方案,至少對我自己的情況。

我想處理所有這些元素的屬性完全等於......任何。

但我有幾個模型,這個例程應該適用於所有模型。它的作用:

def selectByProperties(modelType, specify): 
    clause = "SELECT * from %s" % modelType._meta.db_table 

    if len(specify) > 0: 
     clause += " WHERE " 
     for field, eqvalue in specify.items(): 
      clause += "%s = '%s' AND " % (field, eqvalue) 
     clause = clause [:-5] # remove last AND 

    print clause 
    return modelType.objects.raw(clause) 

這款通用子程序,我可以選擇所有那些正好等於我的「指定」(PROPERTYNAME,的PropertyValue)組合字典元素。

第一個參數需要(models.Model)

第二字典等: { 「property1」: 「77」, 「property2」: 「12」}

並創建SQL語句像

SELECT * from appname_modelname WHERE property1 = '77' AND property2 = '12' 

,並返回這些元素一個QuerySet。

這是一個測試功能:

from myApp.models import myModel 

def testSelectByProperties(): 

    specify = {"property1" : "77" , "property2" : "12"} 
    subset = selectByProperties(myModel, specify) 

    nameField = "property0" 
    ## checking if that is what I expected: 
    for i in subset: 
     print i.__dict__[nameField], 
     for j in specify.keys(): 
      print i.__dict__[j], 
     print 

還有呢?你怎麼看?

7

看起來像using F() with annotations將是我的解決方案。

它不會過濾@property,因爲F在將對象帶入python之前與數據庫進行通信。但仍然把它放在這裏作爲一個答案,因爲我希望按屬性過濾的原因是真的想通過在兩個不同的字段上進行簡單算術的結果過濾對象。

因此,沿着線的東西:

companies = Company.objects\ 
    .annotate(chairs_needed=F('num_employees') - F('num_chairs'))\ 
    .filter(chairs_needed__lt=4) 

,而不是定義的屬性爲:

@property 
def chairs_needed(self): 
    return self.num_employees - self.num_chairs 

然後做所有的對象列表理解。

3

Riffing關@ TheGrimmScientist建議的解決方法,你可以通過定義他們的經理或查詢集,和複用/鏈讓這些「SQL屬性」 /撰寫他們:

隨着經理:

class CompanyManager(models.Manager): 
    def with_chairs_needed(self): 
     return self.annotate(chairs_needed=F('num_employees') - F('num_chairs')) 

class Company(models.Model): 
    # ... 
    objects = CompanyManager() 

Company.objects.with_chairs_needed().filter(chairs_needed__lt=4) 

有了一個QuerySet:

class CompanyQuerySet(models.QuerySet): 
    def many_employees(self, n=50): 
     return self.filter(num_employees__gte=n) 

    def needs_fewer_chairs_than(self, n=5): 
     return self.with_chairs_needed().filter(chairs_needed__lt=n) 

    def with_chairs_needed(self): 
     return self.annotate(chairs_needed=F('num_employees') - F('num_chairs')) 

class Company(models.Model): 
    # ... 
    objects = CompanyQuerySet.as_manager() 

Company.objects.needs_fewer_chairs_than(4).many_employees() 

更多見https://docs.djangoproject.com/en/1.9/topics/db/managers/。 請注意,我正在關閉文檔,並沒有測試上述內容。