mirror of
				https://github.com/django/django.git
				synced 2025-10-31 09:41:08 +00:00 
			
		
		
		
	Added sqlite3 database backend -- somewhat tested, but probably not 100% perfect.
git-svn-id: http://code.djangoproject.com/svn/django/trunk@288 bcc190cf-cafb-0310-a4f2-bffc1f526a37
This commit is contained in:
		| @@ -10,11 +10,11 @@ MANAGERS = ADMINS | ||||
|  | ||||
| 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 | ||||
|  | ||||
|   | ||||
							
								
								
									
										148
									
								
								django/core/db/backends/sqlite3.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										148
									
								
								django/core/db/backends/sqlite3.py
									
									
									
									
									
										Normal file
									
								
							| @@ -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', | ||||
| } | ||||
| @@ -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? | ||||
| ---------------------------- | ||||
|   | ||||
| @@ -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', '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). | ||||
|  | ||||
| * ``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). | ||||
| .. 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.) | ||||
|     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. | ||||
|     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. | ||||
|   | ||||
		Reference in New Issue
	
	Block a user