编写MySQL Python类的最佳方法是什么?

时间:2018-01-20 20:50:42

标签: python mysql

我总是编写一个数据库类,其中包含我需要的每个查询的方法。

这样做我最终得到了50多种方法。

我想我应该编写一个包含SELECT,DELETE,UPDATE,INSERT等方法的小类。然后直接将我的查询写入我的方法。

哪种方式更好,为什么?我还有另一种方法吗?

2 个答案:

答案 0 :(得分:2)

为什么不使用查询构建器或ORM? https://github.com/kayak/pypika 使用查询构建器来获取对查询和ORM的重复控制的粒度控制。

答案 1 :(得分:2)

这真的适用于python和mysql之外的上下文:

您要问的是如何设计数据库适配器,即用于与数据库通信的代码。需要考虑很多重要问题:

  1. 对底层数据库进行更改有多容易?您是否需要进行大量代码更改?
  2. 添加新查询有多容易?
  3. 测试有多容易?
  4. 为每个MySQL动词设置方法似乎很有吸引力,因为那样您就不必为每种查询类型添加新方法,但这有关于权益结束的地方。您可能会开始将某些查询复制并粘贴到不同的位置。一旦发生这种情况,要更新该查询中的任何内容(表名,列名,联接,甚至其工作方式的具体信息 - 可能是不同的排序顺序或限制),您必须在复制的每个位置修改查询它来。这很快就失控了。它还意味着您的控制器(假设您使用MVC - 如果没有,将它们视为调用您已编写的此DB包装器的代码)成为tightly coupled到底层数据库实现。这种脆弱性使它们更难以测试。您只需要设置一个数据库来测试它们。

    您当前为每种类型的查询设置方法的方法当然可能感觉更像代码,但您所接近的是Repository pattern。这里的想法是我们将特定于数据库工作方式的所有行为(表名,列名,连接,外键,排序策略,缓存)抽象为几个特定的​​类。对于博客文章,这可能是BlogPostRepository。对于评论,这可能是CommentRepository。他们会这样:

    class BlogPostRepository(Repository):
        def create(self, blog_post):
            with self._conn.cursor() as c:
                c.execute('INSERT ...', blog_post.name) # etc.
    
        def list(self):
            return [BlogPost(r) for r in self._conn.query('SELECT * FROM blog_post')]
    

    现在胜利是你的控制器可以将存储库作为一个arg到init(许多框架可以使用dependency injection简化这一点):

    class HomeController(Controller):
        def __init__(self, blog_post_repository):
            self.blog_posts = blog_post_repository
    
        def show_home_page(self):
            posts = self.blog_posts.list()
            # Render the posts...
    

    您需要列出博客帖子的任何其他地方都可以使用相同的代码。然后,如果您需要更改列出博客文章的方式,则只需修改BlogPostRepository中的代码即可。此外,在测试控制器时,您可以传入模拟的存储库并断言调用正确的方法。这样,您的控制器测试不需要设置数据库(如果您更改了数据库,也需要更改这些测试)。

    如果编写SQL查询变得难以处理,或者您希望防范需要更改底层数据库的情况,则可以查看ORM。但是如果你选择使用一个,你仍然应该在存储库模式中使用ORM,这样你的控制器就不那么紧密地与数据库代码结合了。