【问题标题】:Dynamic Finders and Method Missing in PythonPython 中缺少动态查找器和方法
【发布时间】:2010-10-29 02:53:30
【问题描述】:

我正在尝试在 Python 中实现类似 Rails 动态查找器(对于 网络应用程序/GAE)。动态查找器的工作方式如下:

  • 您的个人有一些字段:姓名、年龄和电子邮件。
  • 假设您要查找名称为“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 但我愿意 想听听“最合适”的做法是什么。

【问题讨论】:

    标签: python google-app-engine web-applications


    【解决方案1】:

    这里真的没有必要使用 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)
    

    请注意,它返回一个 Query 对象,您可以在该对象上调用 .get()、.fetch() 等;这更通用,但如果你愿意,当然可以让它只返回一个实体。

    【讨论】:

    • 我尝试使用此代码,但仍然得到:AttributeError("type object 'FindableModel' has no attribute 'find_by_name'",)。你能解释一下如何使用它吗?
    • @hakunin 你是如何使用它的?您应该将此作为模型的父类。
    • 这是我使用的模型:gist.github.com/2014164 我很想使用__getattr__,但由于某种原因它没有被调用。
    • @hakunin 您的模型正在扩展db.Model。它需要扩展FindableModel
    【解决方案2】:

    您可以像 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 做了什么……

    【讨论】:

      【解决方案3】:
      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()
      

      【讨论】:

      • getattribute 在这里是个坏主意,使用 getattr,它只会在缺少属性时被调用。
      【解决方案4】:
      class Person:
      
          name = ""
          age = 0
          salary = 0
      
          def __init__(self, name, age):
              self.name = name
              self.age = age
      

      def find(clsobj, *args): 返回人(姓名=“杰克”,年龄=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))
      

      print Person.find_by_name("jack").age # 将打印值 20。

      我不确定这是否是正确的做事方式。但是如果你能够为所有属性实现一个统一的“查找”,那么上面的脚本就可以了。

      【讨论】:

        猜你喜欢
        • 2011-09-08
        • 1970-01-01
        • 2013-01-01
        • 2017-07-24
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2022-12-28
        相关资源
        最近更新 更多