Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

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
@jacobian jacobian authored
View
10 django/conf/project_template/settings/main.py
@@ -10,11 +10,11 @@
LANGUAGE_CODE = 'en-us'
-DATABASE_ENGINE = 'postgresql' # 'postgresql' or 'mysql'
-DATABASE_NAME = ''
-DATABASE_USER = ''
-DATABASE_PASSWORD = ''
-DATABASE_HOST = '' # Set to empty string for localhost
+DATABASE_ENGINE = 'postgresql' # 'postgresql', 'mysql', or 'sqlite'
+DATABASE_NAME = '' # or path to database file if using sqlite
+DATABASE_USER = '' # not used with sqlite
+DATABASE_PASSWORD = '' # not used with sqlite
+DATABASE_HOST = '' # Set to empty string for localhost; not used with sqlite
SITE_ID = 1
View
148 django/core/db/backends/sqlite3.py
@@ -0,0 +1,148 @@
+"""
+SQLite3 backend for django. Requires pysqlite2 (http://pysqlite.org/).
+"""
+
+from django.core.db import base, typecasts
+from django.core.db.dicthelpers import *
+from pysqlite2 import dbapi2 as Database
+DatabaseError = Database.DatabaseError
+
+# Register adaptors ###########################################################
+
+Database.register_converter("bool", lambda s: str(s) == '1')
+Database.register_converter("time", typecasts.typecast_time)
+Database.register_converter("date", typecasts.typecast_date)
+Database.register_converter("datetime", typecasts.typecast_timestamp)
+
+# Database wrapper ############################################################
+
+class DatabaseWrapper:
+ def __init__(self):
+ self.connection = None
+ self.queries = []
+
+ def cursor(self):
+ from django.conf.settings import DATABASE_NAME, DEBUG
+ if self.connection is None:
+ self.connection = Database.connect(DATABASE_NAME, detect_types=Database.PARSE_DECLTYPES)
+ # register extract and date_trun functions
+ self.connection.create_function("django_extract", 2, _sqlite_extract)
+ self.connection.create_function("django_date_trunc", 2, _sqlite_date_trunc)
+ if DEBUG:
+ return base.CursorDebugWrapper(FormatStylePlaceholderCursor(self.connection), self)
+ return FormatStylePlaceholderCursor(self.connection)
+
+ def commit(self):
+ self.connection.commit()
+
+ def rollback(self):
+ if self.connection:
+ self.connection.rollback()
+
+ def close(self):
+ if self.connection is not None:
+ self.connection.close()
+ self.connection = None
+
+class FormatStylePlaceholderCursor(Database.Cursor):
+ """
+ Django uses "format" style placeholders, but pysqlite2 uses "qmark" style.
+ This fixes it -- but note that if you want to use a literal "%s" in a query,
+ you'll need to use "%%s" (which I belive is true of other wrappers as well).
+ """
+
+ def execute(self, query, params=[]):
+ query = self.convert_query(query, len(params))
+ return Database.Cursor.execute(self, query, params)
+
+ def executemany(self, query, params=[]):
+ query = self.convert_query(query, len(params))
+ return Database.Cursor.executemany(self, query, params)
+
+ def convert_query(self, query, num_params):
+ # XXX this seems too simple to be correct... is this right?
+ return query % tuple("?" * num_params)
+
+# Helper functions ############################################################
+
+def get_last_insert_id(cursor, table_name, pk_name):
+ return cursor.lastrowid
+
+def get_date_extract_sql(lookup_type, table_name):
+ # lookup_type is 'year', 'month', 'day'
+ # sqlite doesn't support extract, so we fake it with the user-defined
+ # function _sqlite_extract that's registered in connect(), above.
+ return 'django_extract("%s", %s)' % (lookup_type.lower(), table_name)
+
+def _sqlite_extract(lookup_type, dt):
+ try:
+ dt = typecasts.typecast_timestamp(dt)
+ except (ValueError, TypeError):
+ return None
+ return str(getattr(dt, lookup_type))
+
+def get_date_trunc_sql(lookup_type, field_name):
+ # lookup_type is 'year', 'month', 'day'
+ # sqlite doesn't support DATE_TRUNC, so we fake it as above.
+ return 'django_date_trunc("%s", %s)' % (lookup_type.lower(), field_name)
+
+def _sqlite_date_trunc(lookup_type, dt):
+ try:
+ dt = typecasts.typecast_timestamp(dt)
+ except (ValueError, TypeError):
+ return None
+ if lookup_type == 'year':
+ return "%i-01-01 00:00:00" % dt.year
+ elif lookup_type == 'month':
+ return "%i-%02i-01 00:00:00" % (dt.year, dt.month)
+ elif lookup_type == 'day':
+ return "%i-%02i-%02i 00:00:00" % (dt.year, dt.month, dt.day)
+
+# Operators and fields ########################################################
+
+OPERATOR_MAPPING = {
+ 'exact': '=',
+ 'iexact': 'LIKE',
+ 'contains': 'LIKE',
+ 'icontains': 'LIKE',
+ 'ne': '!=',
+ 'gt': '>',
+ 'gte': '>=',
+ 'lt': '<',
+ 'lte': '<=',
+ 'startswith': 'LIKE',
+ 'endswith': 'LIKE',
+ 'istartswith': 'LIKE',
+ 'iendswith': 'LIKE',
+}
+
+# SQLite doesn't actually support most of these types, but it "does the right
+# thing" given more verbose field definitions, so leave them as is so that
+# schema inspection is more useful.
+DATA_TYPES = {
+ 'AutoField': 'integer',
+ 'BooleanField': 'bool',
+ 'CharField': 'varchar(%(maxlength)s)',
+ 'CommaSeparatedIntegerField': 'varchar(%(maxlength)s)',
+ 'DateField': 'date',
+ 'DateTimeField': 'datetime',
+ 'EmailField': 'varchar(75)',
+ 'FileField': 'varchar(100)',
+ 'FloatField': 'numeric(%(max_digits)s, %(decimal_places)s)',
+ 'ImageField': 'varchar(100)',
+ 'IntegerField': 'integer',
+ 'IPAddressField': 'char(15)',
+ 'ManyToManyField': None,
+ 'NullBooleanField': 'bool',
+ 'OneToOneField': 'integer',
+ 'PhoneNumberField': 'varchar(20)',
+ 'PositiveIntegerField': 'integer unsigned',
+ 'PositiveSmallIntegerField': 'smallint unsigned',
+ 'SlugField': 'varchar(50)',
+ 'SmallIntegerField': 'smallint',
+ 'TextField': 'text',
+ 'TimeField': 'time',
+ 'URLField': 'varchar(200)',
+ 'USStateField': 'varchar(2)',
+ 'XMLField': 'text',
+}
View
5 docs/faq.txt
@@ -144,8 +144,8 @@ own lightweight development server. For a production environment, we recommend
`Apache 2`_ and mod_python_, although Django follows the WSGI_ spec, which
means it can run on a variety of server platforms.
-You'll also need a database engine. PostgreSQL_ is recommended, and MySQL_ is
-supported.
+You'll also need a database engine. PostgreSQL_ is recommended, and MySQL_
+and `SQLite 3`_ are supported.
.. _Python: http://www.python.org/
.. _Apache 2: http://httpd.apache.org/
@@ -153,6 +153,7 @@ supported.
.. _WSGI: http://www.python.org/peps/pep-0333.html
.. _PostgreSQL: http://www.postgresql.org/
.. _MySQL: http://www.mysql.com/
+.. _`SQLite 3`: http://www.sqlite.org/
Do I have to use mod_python?
----------------------------
View
86 docs/tutorial01.txt
@@ -49,23 +49,27 @@ settings. Let's look at what ``startproject`` created::
First, edit ``myproject/settings/main.py``. It's a normal Python module with
module-level variables representing Django settings. Edit the file and change
these settings to match your database's connection parameters:
-
-* ``DATABASE_ENGINE`` -- Either 'postgresql' or 'mysql'. More coming soon.
-* ``DATABASE_NAME`` -- The name of your database.
-* ``DATABASE_USER`` -- Your database username.
-* ``DATABASE_PASSWORD`` -- Your database password.
-* ``DATABASE_HOST`` -- The host your database is on. Leave this as an
- empty string if your database server is on the same physical machine
- (localhost).
-
-(Make sure you've created a database within PostgreSQL or MySQL by this point.
-Do that with "``CREATE DATABASE database_name;``" within your database's
-interactive prompt.)
-
-Also, note that MySQL support is a recent development, and Django hasn't been
-comprehensively tested with that database. If you find any bugs in Django's
-MySQL bindings, please file them in `Django's ticket system`_ so we can fix them
-immediately.
+
+ * ``DATABASE_ENGINE`` -- Either 'postgresql', 'mysql' or 'sqlite3'.
+ More coming soon.
+ * ``DATABASE_NAME`` -- The name of your database, or the full path to
+ the database file if using sqlite.
+ * ``DATABASE_USER`` -- Your database username (not used for sqlite).
+ * ``DATABASE_PASSWORD`` -- Your database password (not used for sqlite).
+ * ``DATABASE_HOST`` -- The host your database is on. Leave this as an
+ empty string if your database server is on the same physical machine
+ (not used for sqlite).
+
+.. admonition:: Note
+
+ Make sure you've created a database within PostgreSQL or MySQL by this
+ point. Do that with "``CREATE DATABASE database_name;``" within your
+ database's interactive prompt.
+
+ Also, note that MySQL and sqlite support is a recent development, and Django
+ hasn't been comprehensively tested with either database. If you find any
+ bugs in those bindings, please file them in `Django's ticket system`_ so we
+ can fix them immediately.
Now, take a second to make sure ``myproject`` is on your Python path. You
can do this by copying ``myproject`` to Python's ``site-packages`` directory,
@@ -90,8 +94,9 @@ On Windows, you'd use ``set`` instead::
If you don't see any errors after running ``django-admin.py init``, you know it
worked. That command initialized your database with Django's core database
-tables. If you're interested, run the PostgreSQL or MySQL command-line client
-and type "\\dt" (PostgreSQL) or "SHOW TABLES;" (MySQL) to display the tables.
+tables. If you're interested, run the command-line client for your database and
+type ``\\dt`` (PostgreSQL), ``SHOW TABLES;`` (MySQL), or ``.schema`` (SQLite) to
+display the tables.
Now you're set to start doing work. You won't have to take care of this boring
administrative stuff again.
@@ -235,27 +240,34 @@ You should see the following (the CREATE TABLE SQL statements for the polls app)
Note the following:
-* Table names are automatically generated by combining the name of the app
- (polls) with a plural version of the object name (polls and choices). (You
- can override this behavior.)
-* Primary keys (IDs) are added automatically. (You can override this, too.)
-* The foreign key relationship is made explicit by a ``REFERENCES`` statement.
-* It's tailored to the database you're using, so database-specific field types
- such as ``auto_increment`` (MySQL) vs. ``serial`` (PostgreSQL) are handled
- for you automatically. The author of this tutorial runs PostgreSQL, so the
- example output is in PostgreSQL syntax.
+ * Table names are automatically generated by combining the name of the app
+ (polls) with a plural version of the object name (polls and choices). (You
+ can override this behavior.)
+
+ * Primary keys (IDs) are added automatically. (You can override this, too.)
+
+ * The foreign key relationship is made explicit by a ``REFERENCES`` statement.
+
+ * It's tailored to the database you're using, so database-specific field types
+ such as ``auto_increment`` (MySQL), ``serial`` (PostgreSQL), or ``integer
+ primary key`` (SQLite) are handled for you automatically. The author of
+ this tutorial runs PostgreSQL, so the example output is in PostgreSQL
+ syntax.
If you're interested, also run the following commands:
-* ``django-admin.py sqlinitialdata polls`` -- Outputs the initial-data inserts
- required for Django's admin framework.
-* ``django-admin.py sqlclear polls`` -- Outputs the necessary ``DROP TABLE``
- statements for this app, according to which tables already exist in your
- database (if any).
-* ``django-admin.py sqlindexes polls`` -- Outputs the ``CREATE INDEX``
- statements for this app.
-* ``django-admin.py sqlall polls`` -- A combination of 'sql' and
- 'sqlinitialdata'.
+ * ``django-admin.py sqlinitialdata polls`` -- Outputs the initial-data
+ inserts required for Django's admin framework.
+
+ * ``django-admin.py sqlclear polls`` -- Outputs the necessary ``DROP
+ TABLE`` statements for this app, according to which tables already exist
+ in your database (if any).
+
+ * ``django-admin.py sqlindexes polls`` -- Outputs the ``CREATE INDEX``
+ statements for this app.
+
+ * ``django-admin.py sqlall polls`` -- A combination of 'sql' and
+ 'sqlinitialdata'.
Looking at the output of those commands can help you understand what's actually
happening under the hood.
Please sign in to comment.
Something went wrong with that request. Please try again.