How to use mysql-connector-python 2.1.5 on Django 1.10?

MySQL Connector/Python currently not available from PyPI

When you want use mysql-connector-python as db backend in Django, the first thing you noticed is that the latest version of mysql-connector-python on PyPI is 2.0.4, but official version is 2.1.5.

The official developer explained this.(But why not host mysql-connector-python on PyPI?!).

so, you can bypass this problem. Add follow line into requirements.txt:

https://dev.mysql.com/get/Downloads/Connector-Python/mysql-connector-python-2.1.5.tar.gz#egg=mysql-connector-python

when you configured Connector/Python Django Backend, and run python manage.py migrate , you will meet error:

DatabaseError: Data truncated for column ‘applied’ at row 1

This is because mysql.connector.django cannot handle datetime with timezone.

You need patch 93c7b38.

when you fix this, you must drop all table, and re-run python manage.py migrate, you will meet another error:

  File "/path/to/venv/lib/python3.5/site-packages/mysql/connector/django/operations.py", line 223, in bulk_insert_sql
    return "VALUES " + ", ".join([items_sql] * num_values)
TypeError: can't multiply sequence by non-int of type 'tuple'

can’t multiply sequence by non-int of type ‘tuple’

This is because bulk_insert_sql ‘s third argument changed from int to list of placeholder rows, since Django 1.9.

You need another patch, patch 8dab00b. (Of cause, we doesn’t drop support of Django 1.6)


Now you can use mysql-connector-python 2.1.5 on Django 1.10, if you meet another problem, post the comment here!

Django的MySQL Driver配置

之前写过一篇文章《Django@Python3添加MySQL/MariaDB支持》,现在Django对MySQL的支持已经很好了,现在就说一说最佳实践吧。

PEP 249规定了Python的数据库API。MySQL主要有三种API实现:

  • MySQLdb 是Andy Dustman开发的、使用原生代码/C语言绑定的驱动,它已经开发了数十年。
  • mysqlclient 是MySQLdb的一个支持Python3的fork,并且可以无缝替换调MySQLdb。mysqlclient目前是MySQL在Django下的推荐选择。
  • MySQL Connector/Python 是Oracle写的,纯Python实现的客户端库。

以上所有的驱动都是线程安全的,且提供了连接池。MySQLdb 是唯一一个不支持Python3的。

如果你使用mysqlclient

settings.py中的配置如下:

# Database
# https://docs.djangoproject.com/en/1.10/ref/settings/#databases

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.mysql', #数据库引擎
        'NAME': 'test',                       #数据库名
        'USER': 'root',                       #用户名
        'PASSWORD': 'root',                   #密码
        'HOST': '',                           #数据库主机,默认为localhost
        'PORT': '',                           #数据库端口,MySQL默认为3306
        'OPTIONS': {
            'autocommit': True,
            'init_command': "SET sql_mode='STRICT_TRANS_TABLES'",
        },
    }
}

第14行主要是为了防止警告:

(mysql.W002) MySQL Strict Mode is not set for database connection 'default'

当然,要在requirements.txt中添加对mysqlclient的依赖:

mysqlclient==1.3.10

然后运行python manage.py migrate :

$ python manage.py migrate
Operations to perform:
  Apply all migrations: admin, auth, contenttypes, sessions
Running migrations:
  Applying contenttypes.0001_initial... OK
  。。。。。。

如果你使用MySQL Connector/Python

这么长时间了,Oracle官方的connector还是不太好用。

首先,一些补丁需要打:patch 93c7b38, patch 8dab00b要打上。

其次,这个包无法从PyPI安装了,只能从下载链接安装。

如果你要使用MySQL Connector/Python,首先,在requirements.txt中声明依赖:

https://dev.mysql.com/get/Downloads/Connector-Python/mysql-connector-python-2.1.5.tar.gz#egg=mysql-connector-python

其次,在settings.py里面关于数据库的配置如下:

# Database
# https://docs.djangoproject.com/en/1.10/ref/settings/#databases

DATABASES = {
    'default': {
        'ENGINE': 'mysql.connector.django',   #数据库引擎
        'NAME': 'test',                       #数据库名
        'USER': 'root',                       #用户名
        'PASSWORD': 'root',                   #密码
        'HOST': 'localhost',
        'OPTIONS': {
            'autocommit': True,
        },
    }
}

然后运行python manage.py migrate

Python3.4+uWSGI for Django Website in VirtualEnv (CentOS)

Install Python 3.x

In CentOS, There is no Python3 rpm package in EPEL, RPMFusion, we must install Python 3.x by source.

Download Python 3.4.0, and extract it.

wget https://www.python.org/ftp/python/3.4.0/Python-3.4.0.tar.xz
tar -xvf Python-3.4.0.tar.xz
cd Python-3.4.0

switch to Python-3.4.0, compile&install Python 3.4.0 (You are expected have installed gcc, make and sqlite-devel)

./configure
make
make install

As the result, you can see the path of Python 3.4.0 by command which python3.4

Thanks to Python 3.4.0, we needn’t install PIP.

Install virtualenvwrapper&Django

You can install virtualenvwrapper by PIP.(Require root privileges)

pip install virtualenvwrapper

Don’t forget add two lines to file .bashrc:

VIRTUALENVWRAPPER_PYTHON=/usr/local/bin/python3.4
source /usr/local/bin/virtualenvwrapper.sh
Let it take effect:
source ~/.bashrc

Then, create a New VirtualEnv, and install Django:

mkvirtualenv django_test
pip install django

Let’s create a new Website for test (in virtualenv django_test):

django-admin.py startproject proj
cd proj
python manage.py runserver

Visit port 8000, you can see the welcome page.

Install uWSGI

Download it and extract it:

wget http://projects.unbit.it/downloads/uwsgi-2.0.3.tar.gz
tar -xvf uwsgi-2.0.3.tar.gz
cd uwsgi-2.0.3

Compile it ( before compile, make sure you are in virtualenv django_test with Python 3.4.0 ):

python uwsgiconfig.py --build

Test it (with Django Website proj):

/path/to/uwsgi/uwsgi --http :8000 --chdir /path/to/proj --wsgi-file proj/wsgi.py -H $HOME/.virtualenvs/django_test

Then visit the port 8000, the uWSGI is also worked!

Let’s prepare uWSGI for nginx!

move uwsgi to system path (I cannot find a better way to install uWSGI):

mv /path/to/uwsgi/ /usr/local
#that is, you have folder /usr/local/uwsgi-2.0.3

and create the Directory /usr/etc/uwsgi and the file /usr/etc/uwsgi/django.ini:

mkdir -p /usr/local/etc/uwsgi
cat > /usr/local/etc/uwsgi/django.ini << EOF
[uwsgi]
socket = /tmp/django.sock
pidfile = /tmp/django.pid
chmod-socket = 666
limit-as = 256
processes = 6
max-request = 2000
memory-report = true
enable-threads = true

wsgi-file=proj/wsgi.py

virtualenv=/root/.virtualenvs/django_test
chdir = /path/to/proj

daemonize=/var/log/uwsgi/proj.log
EOF

execute uWSGI:

/usr/local/uwsgi-2.0.3/uwsgi /usr/local/etc/uwsgi/django.ini

Install Nginx

You can install nginx by yum (Require EPEL):

yum install nginx -y

Then, edit /etc/nginx/conf.d/virtual.conf :

server {
    listen       80;
    server_name  _;

    location / {
        include     uwsgi_params;
        uwsgi_pass  unix:///tmp/django.sock;
    }
}

And start nginx:

service nginx start

Then, visit the port 80, you can see the welcome page of Django.

let MySQL Connector 1.1.6 work with Django and South

MySQL Connector Python 1.1.6 was released on 2014-2-19, I use it with Django and South, but South looks like cannot work with the Connector 1.1.6.

Description

First, add pair ‘mysql.connector.django’: ‘mysql’, to variable engine_modules in file south/db/__init__.py .

But, with settings.DEBUG enabled, connector will process all warming as error. So, if we use south command schemamigration app –initial , We will receive the error “PendingDeprecationWarning: Options.module_name has been deprecated in favor of model_name”.

Hotfix1

Suppose we can’t modify the third party package, you can only adjust your code.

Add fellow code to settings.py :

SOUTH_DATABASE_ADAPTERS = {
    'default': 'south.db.mysql'
}

and, add fellow code to project’s __init__.py :

#Below is hotfix for MySQL connector 1.1.6

import warnings

origin_filterwarnings = warnings.filterwarnings

default_param = origin_filterwarnings.__defaults__

default_param = list(default_param[:-1])
default_param.append(True)

origin_filterwarnings.__defaults__ = tuple(default_param)

Hotfix2

If you can modify the third party package, you can use this way.

Add pair ‘mysql.connector.django’: ‘mysql’, to variable engine_modules in file south/db/__init__.py .

in file ‘mysql/connector/django/base.py’ line 61, the call of warnings.filterwarnings , add the parameter append=True

Continue reading let MySQL Connector 1.1.6 work with Django and South

PEP 3107 — 函数注解[译]

本文是PIP 3137的翻译。

背景

Python 2.x系列缺乏一个标准的方式来说明一个函数的参数和返回值,各种工具和库的出现填补了这一空白。一些工具使用了“PEP 318”中的装饰器,而其他的工具则去解析函数的文档注释,寻找注解。

在这一点上,众多已存在的机制和语法造成了很大的混乱。本PEP的目的是提供一个单一的,标准的方式指定这些信息,减少这些混乱。

函数注解的基础知识

在仔细讨论Python 3.0的函数注解的细节之前,首先让我们大致讨论下注解是什么、不是什么:

  1. 函数注解,无论是对参数的还是对返回值的函数注解,完全是可选的。
  2. 函数注解无非是一种方法,用来在编译时将任意Python表达式和函数的不同部分关联起来。就这点而言,Python并没有给注解赋予特殊的意义和重要性。Python仅仅让这些表达式可以被访问而已,以一种像本文的“访问函数注解”中描述的方法。注解对含义产生作用的唯一方式是当它们被第三方库解释的时候。这些注解的使用者可以用这些函数注解做他们想做的任何事情。例如,一个库可以利用字符串类型的注解来提供改进过的帮助信息:
    def compile(source: "something compilable",
                filename: "where the compilable thing comes from",
                mode: "is this a single statement or a suite?"):
        ...

    另一个库可以用来提供Python函数和方法的类型检查。这个库可以使用注解来说明函数的预期输入和返回值的类型:

    def haul(item: Haulable, *vargs: PackAnimal) -> Distance:
        ...

    然而,不论是第一个例子中的字符串还是第二个例子中的类型信息,它们自己没有任何含义;含义来自第三方库。

  3. 根据第二点,该PEP不会试图引入一种标准的语义,即使是为那些内置类型。这个工作留给第三方库。

语法

参数

对参数的注解跟随着参数名,采用了一种可选表达式的形式:

def foo(a: expression, b: expression = 5):
    ...

在伪语法中,参数现在看起来像identifier [: expression] [= expression] 。即,注解在参数的默认值之前,而且两者都是可选的。就像等号是用来标记一个默认值的,冒号用来标记注解。像默认值一样,所有的注解表达式都会在函数定义的时候被求值。

“多余”的参数(例如:*args**kwargs )的注解以同样的方式标记:

def foo((x1, y1: expression),
        (x2: expression, y2: expression)=(None, None)):
    ...

返回值

到目前为止,例子都忽略了如何注解一个函数的返回值类型。方法如下:

def sum() -> expression:
    ...

即,参数列表后可以跟着字符-> 和一个Python表达式。像对参数的注解一样,这个表达式会在函数定义的时候被求值。

现在函数定义的语法是:

decorator: '@' dotted_name [ '(' [arglist] ')' ] NEWLINE
decorators: decorator+
funcdef: [decorators] 'def' NAME parameters ['->' test] ':' suite
parameters: '(' [typedargslist] ')'
typedargslist: ((tfpdef ['=' test] ',')*
                ('*' [tname] (',' tname ['=' test])* [',' '**' tname]
                 | '**' tname)
                | tfpdef ['=' test] (',' tfpdef ['=' test])* [','])
tname: NAME [':' test]
tfpdef: tname | '(' tfplist ')'
tfplist: tfpdef (',' tfpdef)* [',']

Lambda表达式

lambda 的语法不支持注解。本可以通过修改lambda 的语法来支持注解,即要求用圆括号围住参数列表。但是,已经决定不进行此项更改,因为:

  1. 这将是一个不兼容的更改。
  2. 不论如何,Lambda会被阉割。
  3. 一个Lambda总是可以被改为一个函数。

访问函数注解

一旦被编译,函数注解是可以通过函数的func_annotations 属性来访问的。该属性是一个可变字典类型,参数名称映射到一个对象,这个对象代表求值后的注解。

returnfunc_annotations 中是一个特殊的键。只有在为函数的返回值提供了注解的情况下,return 键才会出现。

例如,如下注解:

def foo(a: 'x', b: 5 + 6, c: list) -> max(2, 9):
    ...

将会产生一个这样的func_annotation 映射:

{'a': 'x',
 'b': 11,
 'c': list,
 'return': 9}

选择return 键,是因为它不会和参数名称冲突。任何用return 作为函数参数名的尝试都会导致语法错误(SyntaxError )

如果函数没有注解,或者函数创建自一个lamba 表达式,则func_annotations 是一个空的、可变的字典。

使用案例

在讨论注解的过程中,一些使用案例已经出现。有些在这里列出,以它们要传达的信息来分组。还包括在现有的产品和包中使用注解的例子。

  • 提供类型信息
    • 类型检查(link 1, link 2
    • 让IDE显示函数期望的类型和返回的类型(link)
    • 函数重载/泛型函数(link)
    • 其他语言的桥[Foreign-language bridges](link 1, link 2)
    • 配接[Adaptation](link 1, link 2)
    • 逻辑谓词功能[Predicate logic functions]
    • 数据库查询映射
    • RPC参数封装(link)
  • 其他信息
    • 为参数和返回值的文档说明(link)

Django@Python3添加MySQL/MariaDB支持

Django 1.10对MySQL的支持发生了变化,请移步到新的文章

现状

首先,Django@Python2.x 中默认的引擎为 django.db.backends.mysql 。但是在Python3中如果这样写的话,会发现 django.db.backends.mysql 依赖 MySQLdb[5] ,而 MySQLdb 又不兼容 Python3 于是要找一种新的方式来继续使用MySQL。

MySQL官方的方案

首先据MySQL文档[3]说,自从MySQL Connector/Python 1.1.1 开始,引入了 mysql.connector.django ,可直接作为 Django 的数据库引擎使用,但是我试了1.1.2和1.1.3后发现,根本不是那么回事[4]。

PyMySQL(It works)

后来,发现了 PyMySQL[1] ,支持Python3 ,google后知道如何与 Django 结合使用[2],答案如下:

首先,安装PyMySQL

for Windows

pip install PyMySQL

for Fedora

pip-python3 install PyMySQL

然后,在 Django 站点的 __init__.py 文件中添加如下两行:

import pymysql

pymysql.install_as_MySQLdb()

最后是数据库的配置(在settings.py)

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.mysql', #数据库引擎
        'NAME': 'test',                       #数据库名
        'USER': 'root',                       #用户名
        'PASSWORD': 'root',                   #密码
        'HOST': '',                           #数据库主机,默认为localhost
        'PORT': '',                           #数据库端口,MySQL默认为3306
        'OPTIONS': {
            'autocommit': True,
        },
    }
}

然后同步数据库:

for Windows

python manage.py syncdb

for Fedora

python3 manage.py syncdb

OK, It works!

:本人在 Windows 7 + MariaDB 5.5 + Django 1.6.0 + Python 3.3 的环境下试验成功。

更新:在Fedora + MariaDB 5.5 + Django 1.6.0 + Python 3.3 下也测试成功。
Continue reading Django@Python3添加MySQL/MariaDB支持