Django

Code

Ticket #87: mysql.py

File mysql.py, 5.2 kB (added by Jason Huggins, 3 years ago)
Line 
1 """
2 MySQL database backend for Django.
3
4 Requires MySQLdb: http://sourceforge.net/projects/mysql-python
5 """
6
7 from django.core.db import base, typecasts
8 from django.core.db.dicthelpers import *
9 import MySQLdb as Database
10 from MySQLdb.converters import conversions
11 from MySQLdb.constants import FIELD_TYPE
12 import types
13
14 DatabaseError = Database.DatabaseError
15
16 django_conversions = conversions.copy()
17 django_conversions.update({
18     types.BooleanType: typecasts.rev_typecast_boolean,
19     FIELD_TYPE.DATETIME: typecasts.typecast_timestamp,
20     FIELD_TYPE.DATE: typecasts.typecast_date,
21     FIELD_TYPE.TIME: typecasts.typecast_time,
22 })
23
24 class DatabaseWrapper:
25     def __init__(self):
26         self.connection = None
27         self.queries = []
28
29     def cursor(self):
30         from django.conf.settings import DATABASE_USER, DATABASE_NAME, DATABASE_HOST, DATABASE_PASSWORD, DEBUG
31         if self.connection is None:
32             self.connection = Database.connect(user=DATABASE_USER, db=DATABASE_NAME,
33                 passwd=DATABASE_PASSWORD, host=DATABASE_HOST, conv=django_conversions)
34         if DEBUG:
35             return base.CursorDebugWrapper(self.connection.cursor(), self)
36         return self.connection.cursor()
37
38     def commit(self):
39         self.connection.commit()
40
41     def rollback(self):
42         if self.connection:
43             try:
44                 self.connection.rollback()
45             except Database.NotSupportedError:
46                 pass
47
48     def close(self):
49         if self.connection is not None:
50             self.connection.close()
51             self.connection = None
52
53 def get_last_insert_id(cursor, table_name, pk_name):
54     cursor.execute("SELECT LAST_INSERT_ID()")
55     return cursor.fetchone()[0]
56
57 def get_date_extract_sql(lookup_type, table_name):
58     # lookup_type is 'year', 'month', 'day'
59     # http://dev.mysql.com/doc/mysql/en/date-and-time-functions.html
60     return "EXTRACT(%s FROM %s)" % (lookup_type.upper(), table_name)
61
62 def get_date_trunc_sql(lookup_type, field_name):
63     # lookup_type is 'year', 'month', 'day'
64     # http://dev.mysql.com/doc/mysql/en/date-and-time-functions.html
65     # MySQL doesn't support DATE_TRUNC, so we fake it by subtracting intervals.
66     # If you know of a better way to do this, please file a Django ticket.
67     subtractions = ["interval (DATE_FORMAT(%s, '%%%%s')) second - interval (DATE_FORMAT(%s, '%%%%i')) minute - interval (DATE_FORMAT(%s, '%%%%H')) hour" % (field_name, field_name, field_name)]
68     if lookup_type in ('year', 'month'):
69         subtractions.append(" - interval (DATE_FORMAT(%s, '%%%%e')-1) day" % field_name)
70     if lookup_type == 'year':
71         subtractions.append(" - interval (DATE_FORMAT(%s, '%%%%m')-1) month" % field_name)
72     return "(%s - %s)" % (field_name, ''.join(subtractions))
73
74 def get_table_list(cursor):
75     "Returns a list of table names in the current database."
76     cursor.execute("SHOW TABLES")
77     return [row[0] for row in cursor.fetchall()]
78
79 def get_relations(cursor, table_name):
80     raise NotImplementedError
81
82 OPERATOR_MAPPING = {
83     'exact': '=',
84     'iexact': 'LIKE',
85     'contains': 'LIKE',
86     'icontains': 'LIKE',
87     'ne': '!=',
88     'gt': '>',
89     'gte': '>=',
90     'lt': '<',
91     'lte': '<=',
92     'startswith': 'LIKE',
93     'endswith': 'LIKE',
94     'istartswith': 'LIKE',
95     'iendswith': 'LIKE',
96 }
97
98 # This dictionary maps Field objects to their associated MySQL column
99 # types, as strings. Column-type strings can contain format strings; they'll
100 # be interpolated against the values of Field.__dict__ before being output.
101 # If a column type is set to None, it won't be included in the output.
102 DATA_TYPES = {
103     'AutoField':         'mediumint(9) unsigned auto_increment',
104     'BooleanField':      'bool',
105     'CharField':         'varchar(%(maxlength)s)',
106     'CommaSeparatedIntegerField': 'varchar(%(maxlength)s)',
107     'DateField':         'date',
108     'DateTimeField':     'datetime',
109     'EmailField':        'varchar(75)',
110     'FileField':         'varchar(100)',
111     'FloatField':        'numeric(%(max_digits)s, %(decimal_places)s)',
112     'ImageField':        'varchar(100)',
113     'IntegerField':      'integer',
114     'IPAddressField':    'char(15)',
115     'ManyToManyField':   None,
116     'NullBooleanField':  'bool',
117     'OneToOneField':     'integer',
118     'PhoneNumberField':  'varchar(20)',
119     'PositiveIntegerField': 'integer UNSIGNED',
120     'PositiveSmallIntegerField': 'smallint UNSIGNED',
121     'SlugField':         'varchar(50)',
122     'SmallIntegerField': 'smallint',
123     'TextField':         'text',
124     'TimeField':         'time',
125     'URLField':          'varchar(200)',
126     'USStateField':      'varchar(2)',
127     'XMLField':          'text',
128 }
129
130 DATA_TYPES_REVERSE = {
131     FIELD_TYPE.BLOB: 'TextField',
132     FIELD_TYPE.CHAR: 'CharField',
133     FIELD_TYPE.DECIMAL: 'FloatField',
134     FIELD_TYPE.DATE: 'DateField',
135     FIELD_TYPE.DATETIME: 'DateTimeField',
136     FIELD_TYPE.DOUBLE: 'FloatField',
137     FIELD_TYPE.FLOAT: 'FloatField',
138     FIELD_TYPE.INT24: 'IntegerField',
139     FIELD_TYPE.LONG: 'IntegerField',
140     FIELD_TYPE.LONGLONG: 'IntegerField',
141     FIELD_TYPE.SHORT: 'IntegerField',
142     FIELD_TYPE.STRING: 'TextField',
143     FIELD_TYPE.TIMESTAMP: 'DateTimeField',
144     FIELD_TYPE.TINY_BLOB: 'TextField',
145     FIELD_TYPE.MEDIUM_BLOB: 'TextField',
146     FIELD_TYPE.LONG_BLOB: 'TextField',
147     FIELD_TYPE.VAR_STRING: 'CharField',
148 }
149
150 EMPTY_STR_EQUIV = ''