我总是编写一个数据库类,其中包含我需要的每个查询的方法。
这样做我最终得到了50多种方法。
我想我应该编写一个包含SELECT,DELETE,UPDATE,INSERT等方法的小类。然后直接将我的查询写入我的方法。
哪种方式更好,为什么?我还有另一种方法吗?
答案 0 :(得分:2)
为什么不使用查询构建器或ORM? https://github.com/kayak/pypika 使用查询构建器来获取对查询和ORM的重复控制的粒度控制。
答案 1 :(得分:2)
这真的适用于python和mysql之外的上下文:
您要问的是如何设计数据库适配器,即用于与数据库通信的代码。需要考虑很多重要问题:
为每个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,这样你的控制器就不那么紧密地与数据库代码结合了。