2009-05-26 45 views
5

我想在Python中實現類似Rails動態查找器的東西(對於 webapp/GAE)。動態查找工作是這樣的:Python中缺少動態查找器和方法

  • 你的人有一些領域:姓名,年齡和電子郵件。
  • 假設您想查找名稱爲「Robot」的所有用戶。

Person類有一個稱爲「find_by_name」,其接收的名稱 並返回查詢的結果的方法:

@classmethod 
def find_by_name(cls, name): 
    return Person.gql("WHERE name = :1", name).get() 

而不必編寫這樣的一個方法爲每個屬性的,我我喜歡 有類似Ruby的method_missing,允許我這樣做。

到目前爲止,我已經看到了這兩個博客文章:http://blog.iffy.us/?p=43http://www.whatspop.com/blog/2008/08/method-missing-in-python.cfm但我 喜歡聽什麼做的「最appropiate」的方式。

回答

7

這裏真的沒有必要使用GQL--它只是使問題複雜化。這是一個簡單的實現:

class FindableModel(db.Model): 
    def __getattr__(self, name): 
    if not name.startswith("find_by_"): 
     raise AttributeError(name) 
    field = name[len("find_by_"):] 
    return lambda value: self.all().filter(field, value) 

請注意,它返回一個查詢對象,您可以調用.get(),.fetch()等;這是更通用的,但如果你想要,你當然可以讓它只返回一個實體。

+0

我試圖使用這段代碼,但我仍然得到:'AttributeError(「類型對象'FindableModel'沒有'find_by_name'','''''屬性。你能解釋一下如何使用它嗎? – hakunin 2012-03-10 13:11:47

+0

@hakunin你好嗎?你應該把它作爲你模型的父類。 – 2012-03-10 20:04:00

+0

這裏是我使用的模型:https://gist.github.com/2014164我很喜歡使用'__getattr__',但是由於某種原因它不會被調用。 – hakunin 2012-03-11 00:10:00

0
class Person(object): 
    def __getattr__(self, name): 
     if not name.startswith("find_by"): raise AttributeError(name) 
     field_name = name.split("find_by_",1)[1] 
     return lambda name: Person.gql("WHERE %s = :1" % field_name, name).get() 
+1

__getattribute__在這裏是一個壞主意,使用__getattr__,它只會被調用缺少的屬性。 – 2009-05-26 23:01:47

+0

好吧我改變了它 – Unknown 2009-05-26 23:25:14

1

你可以使用一個「find_by」的方法和關鍵字,像Django的作用:

class Person (object): 
    def find_by(self, *kw): 
     qspec = ' AND '.join('%s=%s' % kv for kv in kw.items()) 
     return self.gql('WHERE ' + qspec) 

person.find_by(name='Robot') 
person.find_by(name='Robot', age='2') 

沿着這條道路,你最終可能會設計自己的查詢語法。看看Django的功能......

0
class Person: 

    name = "" 
    age = 0 
    salary = 0 

    def __init__(self, name, age): 
     self.name = name 
     self.age = age 

高清找到(clsobj,*參數): 收益人(姓名= 「傑克」,年齡= 20)

的下面插入循環@classmethod所有的類屬性。這使得可以使用「find_by_name」,「find_by_age」和「sinf_by_salary」綁定方法。

for attr in Person.__dict__.keys(): 
    setattr(Person, 'find_by_'+attr, find) 
    setattr(Person, 'find_by_'+attr, classmethod(find)) 

打印Person.find_by_name(「傑克」)。年齡#將打印值20

我不知道,如果這做事的正確方法。但是如果你能夠爲所有屬性實現一個統一的「查找」,那麼上面的腳本就可以工作。