Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse code

Added sqlite3 database backend -- somewhat tested, but probably not 1…

…00% perfect.

git-svn-id: http://code.djangoproject.com/svn/django/trunk@288 bcc190cf-cafb-0310-a4f2-bffc1f526a37
  • Loading branch information...
commit e320a0936e4c846e7332bcacc533dda19dad6783 1 parent dbfb35b
Jacob Kaplan-Moss authored July 22, 2005
10  django/conf/project_template/settings/main.py
@@ -10,11 +10,11 @@
10 10
 
11 11
 LANGUAGE_CODE = 'en-us'
12 12
 
13  
-DATABASE_ENGINE = 'postgresql' # 'postgresql' or 'mysql'
14  
-DATABASE_NAME = ''
15  
-DATABASE_USER = ''
16  
-DATABASE_PASSWORD = ''
17  
-DATABASE_HOST = ''             # Set to empty string for localhost
  13
+DATABASE_ENGINE = 'postgresql' # 'postgresql', 'mysql', or 'sqlite'
  14
+DATABASE_NAME = ''             # or path to database file if using sqlite 
  15
+DATABASE_USER = ''             # not used with sqlite
  16
+DATABASE_PASSWORD = ''         # not used with sqlite
  17
+DATABASE_HOST = ''             # Set to empty string for localhost; not used with sqlite
18 18
 
19 19
 SITE_ID = 1
20 20
 
148  django/core/db/backends/sqlite3.py
... ...
@@ -0,0 +1,148 @@
  1
+"""
  2
+SQLite3 backend for django.  Requires pysqlite2 (http://pysqlite.org/).
  3
+"""
  4
+
  5
+from django.core.db import base, typecasts
  6
+from django.core.db.dicthelpers import *
  7
+from pysqlite2 import dbapi2 as Database
  8
+DatabaseError = Database.DatabaseError
  9
+
  10
+# Register adaptors ###########################################################
  11
+
  12
+Database.register_converter("bool", lambda s: str(s) == '1')
  13
+Database.register_converter("time", typecasts.typecast_time)
  14
+Database.register_converter("date", typecasts.typecast_date)
  15
+Database.register_converter("datetime", typecasts.typecast_timestamp)
  16
+
  17
+# Database wrapper ############################################################
  18
+
  19
+class DatabaseWrapper:
  20
+    def __init__(self):
  21
+        self.connection = None
  22
+        self.queries = []
  23
+
  24
+    def cursor(self):
  25
+        from django.conf.settings import DATABASE_NAME, DEBUG
  26
+        if self.connection is None:
  27
+            self.connection = Database.connect(DATABASE_NAME, detect_types=Database.PARSE_DECLTYPES)
  28
+            # register extract and date_trun functions
  29
+            self.connection.create_function("django_extract", 2, _sqlite_extract)
  30
+            self.connection.create_function("django_date_trunc", 2, _sqlite_date_trunc)
  31
+        if DEBUG:
  32
+            return base.CursorDebugWrapper(FormatStylePlaceholderCursor(self.connection), self)
  33
+        return FormatStylePlaceholderCursor(self.connection)
  34
+
  35
+    def commit(self):
  36
+        self.connection.commit()
  37
+
  38
+    def rollback(self):
  39
+        if self.connection:
  40
+            self.connection.rollback()
  41
+
  42
+    def close(self):
  43
+        if self.connection is not None:
  44
+            self.connection.close()
  45
+            self.connection = None
  46
+
  47
+class FormatStylePlaceholderCursor(Database.Cursor):
  48
+    """
  49
+    Django uses "format" style placeholders, but pysqlite2 uses "qmark" style.
  50
+    This fixes it -- but note that if you want to use a literal "%s" in a query,
  51
+    you'll need to use "%%s" (which I belive is true of other wrappers as well).
  52
+    """
  53
+    
  54
+    def execute(self, query, params=[]):
  55
+        query = self.convert_query(query, len(params))
  56
+        return Database.Cursor.execute(self, query, params)
  57
+        
  58
+    def executemany(self, query, params=[]):
  59
+        query = self.convert_query(query, len(params))
  60
+        return Database.Cursor.executemany(self, query, params)
  61
+        
  62
+    def convert_query(self, query, num_params):
  63
+        # XXX this seems too simple to be correct... is this right?
  64
+        return query % tuple("?" * num_params)
  65
+
  66
+# Helper functions ############################################################
  67
+
  68
+def get_last_insert_id(cursor, table_name, pk_name):
  69
+    return cursor.lastrowid
  70
+    
  71
+def get_date_extract_sql(lookup_type, table_name):
  72
+    # lookup_type is 'year', 'month', 'day'
  73
+    # sqlite doesn't support extract, so we fake it with the user-defined 
  74
+    # function _sqlite_extract that's registered in connect(), above.
  75
+    return 'django_extract("%s", %s)' % (lookup_type.lower(), table_name)
  76
+
  77
+def _sqlite_extract(lookup_type, dt):
  78
+    try:
  79
+        dt = typecasts.typecast_timestamp(dt)
  80
+    except (ValueError, TypeError):
  81
+        return None
  82
+    return str(getattr(dt, lookup_type))
  83
+
  84
+def get_date_trunc_sql(lookup_type, field_name):
  85
+    # lookup_type is 'year', 'month', 'day'
  86
+    # sqlite doesn't support DATE_TRUNC, so we fake it as above.
  87
+    return 'django_date_trunc("%s", %s)' % (lookup_type.lower(), field_name)
  88
+
  89
+def _sqlite_date_trunc(lookup_type, dt):
  90
+    try:
  91
+        dt = typecasts.typecast_timestamp(dt)
  92
+    except (ValueError, TypeError):
  93
+        return None
  94
+    if lookup_type == 'year':
  95
+        return "%i-01-01 00:00:00" % dt.year
  96
+    elif lookup_type == 'month':
  97
+        return "%i-%02i-01 00:00:00" % (dt.year, dt.month)
  98
+    elif lookup_type == 'day':
  99
+        return "%i-%02i-%02i 00:00:00" % (dt.year, dt.month, dt.day)
  100
+
  101
+# Operators and fields ########################################################
  102
+        
  103
+OPERATOR_MAPPING = {
  104
+    'exact':        '=',
  105
+    'iexact':       'LIKE',
  106
+    'contains':     'LIKE',
  107
+    'icontains':    'LIKE',
  108
+    'ne':           '!=',
  109
+    'gt':           '>',
  110
+    'gte':          '>=',
  111
+    'lt':           '<',
  112
+    'lte':          '<=',
  113
+    'startswith':   'LIKE',
  114
+    'endswith':     'LIKE',
  115
+    'istartswith':  'LIKE',
  116
+    'iendswith':    'LIKE',
  117
+}
  118
+
  119
+# SQLite doesn't actually support most of these types, but it "does the right 
  120
+# thing" given more verbose field definitions, so leave them as is so that
  121
+# schema inspection is more useful.
  122
+DATA_TYPES = {
  123
+    'AutoField':                    'integer',
  124
+    'BooleanField':                 'bool',
  125
+    'CharField':                    'varchar(%(maxlength)s)',
  126
+    'CommaSeparatedIntegerField':   'varchar(%(maxlength)s)',
  127
+    'DateField':                    'date',
  128
+    'DateTimeField':                'datetime',
  129
+    'EmailField':                   'varchar(75)',
  130
+    'FileField':                    'varchar(100)',
  131
+    'FloatField':                   'numeric(%(max_digits)s, %(decimal_places)s)',
  132
+    'ImageField':                   'varchar(100)',
  133
+    'IntegerField':                 'integer',
  134
+    'IPAddressField':               'char(15)',
  135
+    'ManyToManyField':              None,
  136
+    'NullBooleanField':             'bool',
  137
+    'OneToOneField':                'integer',
  138
+    'PhoneNumberField':             'varchar(20)',
  139
+    'PositiveIntegerField':         'integer unsigned',
  140
+    'PositiveSmallIntegerField':    'smallint unsigned',
  141
+    'SlugField':                    'varchar(50)',
  142
+    'SmallIntegerField':            'smallint',
  143
+    'TextField':                    'text',
  144
+    'TimeField':                    'time',
  145
+    'URLField':                     'varchar(200)',
  146
+    'USStateField':                 'varchar(2)',
  147
+    'XMLField':                     'text',
  148
+}
5  docs/faq.txt
@@ -144,8 +144,8 @@ own lightweight development server. For a production environment, we recommend
144 144
 `Apache 2`_ and mod_python_, although Django follows the WSGI_ spec, which
145 145
 means it can run on a variety of server platforms.
146 146
 
147  
-You'll also need a database engine. PostgreSQL_ is recommended, and MySQL_ is
148  
-supported.
  147
+You'll also need a database engine. PostgreSQL_ is recommended, and MySQL_
  148
+and `SQLite 3`_ are supported.
149 149
 
150 150
 .. _Python: http://www.python.org/
151 151
 .. _Apache 2: http://httpd.apache.org/
@@ -153,6 +153,7 @@ supported.
153 153
 .. _WSGI: http://www.python.org/peps/pep-0333.html
154 154
 .. _PostgreSQL: http://www.postgresql.org/
155 155
 .. _MySQL: http://www.mysql.com/
  156
+.. _`SQLite 3`: http://www.sqlite.org/
156 157
 
157 158
 Do I have to use mod_python?
158 159
 ----------------------------
86  docs/tutorial01.txt
@@ -49,23 +49,27 @@ settings. Let's look at what ``startproject`` created::
49 49
 First, edit ``myproject/settings/main.py``. It's a normal Python module with
50 50
 module-level variables representing Django settings. Edit the file and change
51 51
 these settings to match your database's connection parameters:
52  
-
53  
-* ``DATABASE_ENGINE`` -- Either 'postgresql' or 'mysql'. More coming soon.
54  
-* ``DATABASE_NAME`` -- The name of your database.
55  
-* ``DATABASE_USER`` -- Your database username.
56  
-* ``DATABASE_PASSWORD`` -- Your database password.
57  
-* ``DATABASE_HOST`` -- The host your database is on. Leave this as an
58  
-  empty string if your database server is on the same physical machine
59  
-  (localhost).
60  
-
61  
-(Make sure you've created a database within PostgreSQL or MySQL by this point.
62  
-Do that with "``CREATE DATABASE database_name;``" within your database's
63  
-interactive prompt.)
64  
-
65  
-Also, note that MySQL support is a recent development, and Django hasn't been
66  
-comprehensively tested with that database. If you find any bugs in Django's
67  
-MySQL bindings, please file them in `Django's ticket system`_ so we can fix them
68  
-immediately.
  52
+    
  53
+    * ``DATABASE_ENGINE`` -- Either 'postgresql', 'mysql' or 'sqlite3'. 
  54
+      More coming soon.
  55
+    * ``DATABASE_NAME`` -- The name of your database, or the full path to 
  56
+      the database file if using sqlite.
  57
+    * ``DATABASE_USER`` -- Your database username (not used for sqlite).
  58
+    * ``DATABASE_PASSWORD`` -- Your database password (not used for sqlite).
  59
+    * ``DATABASE_HOST`` -- The host your database is on. Leave this as an
  60
+      empty string if your database server is on the same physical machine
  61
+      (not used for sqlite).
  62
+
  63
+.. admonition:: Note
  64
+
  65
+    Make sure you've created a database within PostgreSQL or MySQL by this
  66
+    point. Do that with "``CREATE DATABASE database_name;``" within your
  67
+    database's interactive prompt.
  68
+
  69
+    Also, note that MySQL and sqlite support is a recent development, and Django
  70
+    hasn't been comprehensively tested with either database. If you find any
  71
+    bugs in those bindings, please file them in `Django's ticket system`_ so we
  72
+    can fix them immediately.
69 73
 
70 74
 Now, take a second to make sure ``myproject`` is on your Python path. You
71 75
 can do this by copying ``myproject`` to Python's ``site-packages`` directory,
@@ -90,8 +94,9 @@ On Windows, you'd use ``set`` instead::
90 94
 
91 95
 If you don't see any errors after running ``django-admin.py init``, you know it
92 96
 worked. That command initialized your database with Django's core database
93  
-tables. If you're interested, run the PostgreSQL or MySQL command-line client
94  
-and type "\\dt" (PostgreSQL) or "SHOW TABLES;" (MySQL) to display the tables.
  97
+tables. If you're interested, run the command-line client for your database and
  98
+type ``\\dt`` (PostgreSQL), ``SHOW TABLES;`` (MySQL), or ``.schema`` (SQLite) to
  99
+display the tables.
95 100
 
96 101
 Now you're set to start doing work. You won't have to take care of this boring
97 102
 administrative stuff again.
@@ -235,27 +240,34 @@ You should see the following (the CREATE TABLE SQL statements for the polls app)
235 240
 
236 241
 Note the following:
237 242
 
238  
-* Table names are automatically generated by combining the name of the app
239  
-  (polls) with a plural version of the object name (polls and choices). (You
240  
-  can override this behavior.)
241  
-* Primary keys (IDs) are added automatically. (You can override this, too.)
242  
-* The foreign key relationship is made explicit by a ``REFERENCES`` statement.
243  
-* It's tailored to the database you're using, so database-specific field types
244  
-  such as ``auto_increment`` (MySQL) vs. ``serial`` (PostgreSQL) are handled
245  
-  for you automatically. The author of this tutorial runs PostgreSQL, so the
246  
-  example output is in PostgreSQL syntax.
  243
+    * Table names are automatically generated by combining the name of the app
  244
+      (polls) with a plural version of the object name (polls and choices). (You
  245
+      can override this behavior.)
  246
+      
  247
+    * Primary keys (IDs) are added automatically. (You can override this, too.)
  248
+    
  249
+    * The foreign key relationship is made explicit by a ``REFERENCES`` statement.
  250
+    
  251
+    * It's tailored to the database you're using, so database-specific field types
  252
+      such as ``auto_increment`` (MySQL), ``serial`` (PostgreSQL), or ``integer
  253
+      primary key`` (SQLite) are handled for you automatically. The author of
  254
+      this tutorial runs PostgreSQL, so the example output is in PostgreSQL
  255
+      syntax.
247 256
 
248 257
 If you're interested, also run the following commands:
249 258
 
250  
-* ``django-admin.py sqlinitialdata polls`` -- Outputs the initial-data inserts
251  
-  required for Django's admin framework.
252  
-* ``django-admin.py sqlclear polls`` -- Outputs the necessary ``DROP TABLE``
253  
-  statements for this app, according to which tables already exist in your
254  
-  database (if any).
255  
-* ``django-admin.py sqlindexes polls`` -- Outputs the ``CREATE INDEX``
256  
-  statements for this app.
257  
-* ``django-admin.py sqlall polls`` -- A combination of 'sql' and
258  
-  'sqlinitialdata'.
  259
+    * ``django-admin.py sqlinitialdata polls`` -- Outputs the initial-data 
  260
+      inserts required for Django's admin framework.
  261
+    
  262
+    * ``django-admin.py sqlclear polls`` -- Outputs the necessary ``DROP 
  263
+      TABLE`` statements for this app, according to which tables already exist
  264
+      in your database (if any).
  265
+      
  266
+    * ``django-admin.py sqlindexes polls`` -- Outputs the ``CREATE INDEX``
  267
+      statements for this app.
  268
+    
  269
+    * ``django-admin.py sqlall polls`` -- A combination of 'sql' and
  270
+      'sqlinitialdata'.
259 271
 
260 272
 Looking at the output of those commands can help you understand what's actually
261 273
 happening under the hood.

0 notes on commit e320a09

Please sign in to comment.
Something went wrong with that request. Please try again.