2009-05-26 11 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のようなものがあります。

これまでのところ、私はこれらの2件のブログの記事を見てきました: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

+0

@hakuninどうやって使っていますか?これをモデルの親クラスにする必要があります。 –

+0

私が使っているモデルは次のとおりです:https://gist.github.com/2014164私は '__getattr__'を使いたいですが、何らかの理由で呼び出されません。 – hakunin

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__を使用すると、属性が見つからない場合にのみ呼び出されます。 –

+0

私はそれを変更しました – Unknown

1

Djangoがないようにあなたは、「find_by」メソッドとキーワードを使用することができます。

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)

ザ・インサートを以下のforループは、すべてのクラス属性のため@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

が印刷されます、私は物事の正しい方法はよく分かりません。しかし、すべての属性に対して統一された "find"を実装できる場合は、上記のスクリプトが機能します。

関連する問題