`
san_yun
  • 浏览: 2662961 次
  • 来自: 杭州
文章分类
社区版块
存档分类
最新评论

django db backends探索

 
阅读更多

由于需要解决django db长连接的问题,最近看了看django db backend相关实现,以及ORM。

 

一、django db 结构

 

django.db是django ORM的封装,主要由两部分构成:

  1. django.db.models。
  2. django.db.backends。

代码具体位置在在/usr/local/lib/python2.7/dist-packages/django/db。一般使用django db的方式:

from django.db import connection
cursor = connection.cursor()
cursor.execute('select sleep(1);');

其中

connection

定义在 django/db/__init__.py中:

connections = ConnectionHandler(settings.DATABASES)
router = ConnectionRouter(settings.DATABASE_ROUTERS)
connection = connections[DEFAULT_DB_ALIAS]
backend = load_backend(connection.settings_dict['ENGINE'])
 

二、db backend结构

1.base backend

 

backend 属于django.db的子目录,在django.db.backends/__init__.py定义 all backend-specific,里面有一些比较重要的类:

BaseDatabaseWrapper               Represents a database connection,一些比较重要的数据库连接操作,如cursor(),close()在这个类中定义。

BaseDatabaseFeatures              一些特性开关,比如是否supports_unspecified_pk

BaseDatabaseOperations         This class encapsulates all backend-specific differences

BaseDatabaseIntrospection         This class encapsulates all backend-specific introspection utilities

BaseDatabaseClient                     This class encapsulates all backend-specific methods for opening a client

BaseDatabaseValidation              验证类,由具体的backend实现。

 

2.mysql backend

mysql backend只有如下6个文件,大部分类是继承于backends中定义的Base:
client.py               BaseDatabaseClient        继承于 BaseDatabaseClient,实现了runshell()
compiler.py          SQLCompiler                     继承于django.db.models.sql.compiler.SQLCompiler
creation.py           DatabaseCreation           This dictionary maps Field objects to their associated MySQL column
introspection.py  DatabaseIntrospection
validation.py        DatabaseValidation         There are some field length restrictions for MySQL

base.py  很重要的pakcage,定义了mysql的一些重要的类:

DatabaseWrapper           mysql database connection,继承于BaseDatabaseWrapper

CursorWrapper                A thin wrapper around MySQLdb's normal cursor class

DatabaseFeatures          继承于BaseDatabaseFeatures

DatabaseOperations     继承于 BaseDatabaseOperations

 

三、mongo db util

 

util.py 定义了db一些公共方法和类,被db.__init__.py调用

load_backend()

ConnectionHandler

ConnectionRouter

 

 

 

四、一些疑问和答案

1.Connection是如何被创建和销毁的?

 

答案:Connection通过BaseDatabaseWrapper 包装,每次调用_cursor()会新创建一个连接,mysql的实现如下:

def _cursor(self):
        if not self._valid_connection():
            kwargs = {
                'conv': django_conversions,
                'charset': 'utf8',
                'use_unicode': True,
            }
            settings_dict = self.settings_dict
            if settings_dict['USER']:
                kwargs['user'] = settings_dict['USER']
            if settings_dict['NAME']:
                kwargs['db'] = settings_dict['NAME']
            if settings_dict['PASSWORD']:
                kwargs['passwd'] = settings_dict['PASSWORD']
            if settings_dict['HOST'].startswith('/'):
                kwargs['unix_socket'] = settings_dict['HOST']
            elif settings_dict['HOST']:
                kwargs['host'] = settings_dict['HOST']
            if settings_dict['PORT']:
                kwargs['port'] = int(settings_dict['PORT'])
            # We need the number of potentially affected rows after an
            # "UPDATE", not the number of changed rows.
            kwargs['client_flag'] = CLIENT.FOUND_ROWS
            kwargs.update(settings_dict['OPTIONS'])
            self.connection = Database.connect(**kwargs)
            self.connection.encoders[SafeUnicode] = self.connection.encoders[unicode]
            self.connection.encoders[SafeString] = self.connection.encoders[str]
            connection_created.send(sender=self.__class__, connection=self)
        cursor = CursorWrapper(self.connection.cursor())
        return cursor

其中

 self.connection = Database.connect(**kwargs)

 

就是在初始化Connection,然后返回一个CursorWrapper。close定义在BaseDatabaseWrapper()中,被db.__init__.py中的close()方法调用,代码如下

def close(self):
        if self.connection is not None:
            self.connection.close()
            self.connection = None


2.一条sql语句如何执行?

 

答案:通过CursorWrapper,调用其exucute()。

 

3.如何让django 数据库保持长连接?

答案:db.__init__.py定义了connection,在每次请求结束之后close():

# Register an event that closes the database connection
# when a Django request is finished.
def close_connection(**kwargs):
    for conn in connections.all():
        conn.close()
signals.request_finished.connect(close_connection)

 

如果不希望Django在每次请求结束以后都关闭所有的连接,可以将上述最后一行代码注释。

 

经过测试,这样是可以达到保持连接的要求 了。但是这种修改Django内部代码的方式过于霸道了,所以继续研究和最后一行代码相关的Signal对象,发现其中还有一个disconnect方 法,对应实现取消信号关联,所以可以采用在django项目中的settings.py文件加入如下代码来实现保持数据库长连接的非非霸道操作。

    from django.core import signals  
    from django.db import close_connection  
      
    # 取消信号关联,实现数据库长连接  
    signals.request_finished.disconnect(close_connection)  
 

 

分享到:
评论

相关推荐

    django-db-connection-pool:Django 的持久数据库连接后端

    快速开始使用pip安装所有引擎: $ pip install django-db-connection-pool[all] 或选择特定引擎: $ pip install django-db-connection-pool[mysql,oracle,postgresql] 配置MySQL 将django.db.backends.mysql更改为...

    django 连接数据库出现1045错误的解决方式

    'ENGINE': 'django.db.backends.mysql', # 引擎,这里是MySQL 'NAME': 'test', # 数据库名 'USER': 'test', # 用户名 'PASSWORD': 'test123', # 密码 'HOST': 'localhost', # 主机,通常是本地主机 'PORT': '...

    django 链接多个数据库 并使用原生sql实现

    'ENGINE': 'django.db.backends.sqlite3', 'NAME': os.path.join(BASE_DIR, 'db.sqlite3'), }, 'db1': { # 配置第二个数据库节点名称 'ENGINE': 'django.db.backends.oracle', 'NAME': 'devdb', 'USER': '...

    Django 浅谈根据配置生成SQL语句的问题

    # 'ENGINE': 'django.db.backends.sqlite3', # 'NAME': os.path.join(BASE_DIR, 'db.sqlite3'), 'ENGINE': 'django.db.backends.mysql', 'NAME': '你的数据库的名字', 'USER': '用户名', '

    django-timescaledb:用于Timescaledb的Django数据库后端和工具

    快速开始通过点子安装pip install django-timescaledb 在settings.py中用作数据库引擎: 标准PostgreSQL DATABASES = { 'default' : { 'ENGINE' : 'timescale.db.backends.postgresql' , ... },} 邮政地理信息系统...

    Win 下 Django 配置

    'ENGINE': 'django.db.backends.mysql', 'NAME': 'your_database_name', # 替换为你的数据库名 'USER': 'your_username', # 替换为你的数据库用户名 'PASSWORD': 'your_password', # 替换为你的数据库密码 '...

    django python3 实例下载

    'ENGINE': 'django.db.backends.mysql', 'NAME': 'your_database_name', 'USER': 'your_username', 'PASSWORD': 'your_password', 'HOST': 'localhost', # 或者你的数据库服务器地址 'PORT': '', # 如果不是...

    基于Django框架的个人博客网站

    一主要功能 支持访客留言功能 ...文章可按日期、分类、标签等多种形式展示 网站后台使用xadmin,弥补了原生后台难看的缺点 ... 'ENGINE': 'django.db.backends.mysql', 'NAME': '数据库名', 'USER':'数据库账户名',

    django 3.0.x源码文件

    `django.db.backends`模块则包含了不同数据库的实现,如SQLite、MySQL、PostgreSQL等。 **3. 视图(View)** 视图是Django处理HTTP请求的主要部分。在`django.views`中,有多种预定义的视图函数和类,如函数式视图...

    django配置

    为了解决这个问题,可以修改Django的SQLite后端代码,具体来说是`/usr/local/python3/lib/python3.6/site-packages/django/db/backends/sqlite3/base.py`文件中的第159行及其前两行。原始代码可能如下所示: ```...

    django-postgresql 数据库驱动

    要在Django项目中使用PostgreSQL,首先需要在`settings.py`文件中的`DATABASES`配置中指定数据库引擎为`'django.db.backends.postgresql'`或`'django.db.backends.postgresql_psycopg2'`(尽管`postgresql_psycopg2`...

    期末大作业基于django后端+vue前端的电商比价系统源码.zip

    'ENGINE': 'django.db.backends.mysql', 'NAME': 'pricecompare', #数据库名称 'HOST':'127.0.0.1', #数据服务器IP 'PORT':3306, #端口号 ,不需要加引号 'USER':'root', #用户名 'PASSWORD':'142857' #密码 ...

    在Django中使用PostgreSQL数据库2

    'ENGINE': 'django.db.backends.postgresql', 'NAME': 'pydata', # 数据库名 'USER': 'your_username', # 数据库用户 'PASSWORD': 'your_password', # 用户密码 'HOST': 'localhost', # 数据库主机,通常为...

    Django跨db迁移

    'ENGINE': 'django.db.backends.sqlite3', 'NAME': os.path.join(BASE_DIR, 'db.sqlite3'), }, 'slave': { 'ENGINE': 'django.db.backends.mysql', 'NAME': '数据库名', 'USER': '用户名', 'PASSWORD': '...

    Django架构操作笔记

    - PostgreSQL: `'django.db.backends.postgresql'` - MySQL: `'django.db.backends.mysql'` - SQLite: `'django.db.backends.sqlite3'` - Oracle: `'django.db.backends.oracle'` **知识点10:** 修改 Django ...

    django学习常见错误

    'ENGINE': 'django.db.backends.oracle', 'NAME': 'TEST', 'USER': 'django', 'PASSWORD': 'oracle1', 'HOST': 'localhost', 'PORT': '1521', } } ``` 而如果我们想使用SQLite3数据库,可以使用以下代码: ``...

    Django+celery+rabbitmq配置文档

    'ENGINE': 'django.db.backends.mysql', 'NAME': 'your_db_name', 'USER': 'your_username', 'PASSWORD': 'your_password', 'HOST': 'localhost', # 或者是你的数据库服务器地址 'PORT': '3306', } } ``` ...

    Django读取Mysql数据并显示在前端的实例

    'ENGINE': 'django.db.backends.mysql', 'NAME': 'your_database_name', 'USER': 'your_database_user', 'PASSWORD': 'your_database_password', 'HOST': 'localhost', # 或你的数据库服务器地址 'PORT': '...

    Ubuntu12.04 nginx python uwsgi Django安装步骤

    'ENGINE': 'django.db.backends.sqlite3', 'NAME': '/home/wwwdjango/mysite/mysite.db', } } STATIC_ROOT = '/home/wwwdjango/mysite/mysite/static/' ``` 最后,我们需要修改 urls.py 文件,取消注释相关行以...

    PythonDjango支持像PostgresCitus这样的分布式多租户数据库

    'ENGINE': 'django.db.backends.postgresql', 'NAME': 'mydatabase', 'USER': 'myuser', 'PASSWORD': 'mypassword', 'HOST': 'localhost', 'PORT': '5432', 'OPTIONS': { 'options': '-c search_path=citus'...

Global site tag (gtag.js) - Google Analytics