Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

newforms-admin: Merged to [5983]

git-svn-id: http://code.djangoproject.com/svn/django/branches/newforms-admin@5984 bcc190cf-cafb-0310-a4f2-bffc1f526a37
  • Loading branch information...
commit c49f2d21ea055ae3c9b66cfd62a9f527a2f6d3b5 1 parent 0ae4e10
@adrianholovaty adrianholovaty authored
Showing with 2,338 additions and 1,862 deletions.
  1. +2 −0  AUTHORS
  2. +2 −1  django/conf/global_settings.py
  3. BIN  django/conf/locale/es/LC_MESSAGES/django.mo
  4. +7 −2 django/conf/locale/es/LC_MESSAGES/django.po
  5. +2 −2 django/conf/project_template/settings.py
  6. +1 −1  django/contrib/admin/templates/admin/index.html
  7. +9 −8 django/contrib/auth/models.py
  8. +6 −4 django/contrib/contenttypes/generic.py
  9. +21 −2 django/contrib/databrowse/datastructures.py
  10. +5 −5 django/contrib/databrowse/plugins/calendars.py
  11. +4 −1 django/contrib/databrowse/templates/databrowse/base.html
  12. +1 −0  django/contrib/databrowse/templates/databrowse/base_site.html
  13. +2 −2 django/contrib/databrowse/templates/databrowse/calendar_day.html
  14. +1 −1  django/contrib/databrowse/templates/databrowse/calendar_homepage.html
  15. +1 −1  django/contrib/databrowse/templates/databrowse/calendar_main.html
  16. +2 −2 django/contrib/databrowse/templates/databrowse/calendar_month.html
  17. +1 −1  django/contrib/databrowse/templates/databrowse/calendar_year.html
  18. +1 −1  django/contrib/databrowse/templates/databrowse/choice_detail.html
  19. +1 −1  django/contrib/databrowse/templates/databrowse/choice_list.html
  20. +2 −2 django/contrib/databrowse/templates/databrowse/fieldchoice_detail.html
  21. +1 −1  django/contrib/databrowse/templates/databrowse/fieldchoice_homepage.html
  22. +1 −1  django/contrib/databrowse/templates/databrowse/fieldchoice_list.html
  23. +1 −1  django/contrib/databrowse/templates/databrowse/homepage.html
  24. +2 −2 django/contrib/databrowse/templates/databrowse/model_detail.html
  25. +1 −1  django/contrib/databrowse/templates/databrowse/object_detail.html
  26. 0  django/contrib/localflavor/pl/__init__.py
  27. +84 −0 django/contrib/localflavor/pl/forms.py
  28. +385 −0 django/contrib/localflavor/pl/pl_administrativeunits.py
  29. +24 −0 django/contrib/localflavor/pl/pl_voivodeships.py
  30. +3 −3 django/core/management/base.py
  31. +6 −5 django/core/management/commands/createcachetable.py
  32. +2 −2 django/core/management/commands/loaddata.py
  33. +2 −2 django/core/management/commands/sqlsequencereset.py
  34. +4 −4 django/core/management/commands/syncdb.py
  35. +71 −63 django/core/management/sql.py
  36. +218 −0 django/db/backends/__init__.py
  37. +56 −139 django/db/backends/ado_mssql/base.py
  38. +9 −26 django/db/backends/dummy/base.py
  39. +94 −158 django/db/backends/mysql/base.py
  40. +2 −1  django/db/backends/mysql/introspection.py
  41. +96 −156 django/db/backends/mysql_old/base.py
  42. +2 −1  django/db/backends/mysql_old/introspection.py
  43. +381 −427 django/db/backends/oracle/base.py
  44. +2 −17 django/db/backends/oracle/creation.py
  45. +2 −2 django/db/backends/oracle/introspection.py
  46. +31 −215 django/db/backends/postgresql/base.py
  47. +3 −1 django/db/backends/postgresql/introspection.py
  48. +109 −0 django/db/backends/postgresql/operations.py
  49. +30 −202 django/db/backends/postgresql_psycopg2/base.py
  50. +3 −1 django/db/backends/postgresql_psycopg2/introspection.py
  51. +68 −142 django/db/backends/sqlite3/base.py
  52. +3 −1 django/db/backends/sqlite3/introspection.py
  53. +0 −27 django/db/backends/util.py
  54. +1 −1  django/db/models/__init__.py
  55. +33 −26 django/db/models/base.py
  56. +3 −6 django/db/models/fields/related.py
  57. +181 −106 django/db/models/loading.py
  58. +5 −5 django/db/models/options.py
  59. +59 −51 django/db/models/query.py
  60. +6 −6 django/template/defaulttags.py
  61. +1 −1  django/template/loader_tags.py
  62. +9 −7 django/test/utils.py
  63. +1 −1  docs/contributing.txt
  64. +2 −2 docs/install.txt
  65. +40 −0 docs/man/compile-messages.1
  66. +34 −0 docs/man/daily_cleanup.1
  67. +26 −0 docs/man/gather_profile_stats.1
  68. +62 −0 docs/man/make-messages.1
  69. +2 −2 docs/newforms.txt
  70. +11 −0 docs/templates.txt
  71. +1 −1  docs/templates_python.txt
  72. +8 −5 docs/tutorial04.txt
  73. +13 −3 docs/url_dispatch.txt
  74. +1 −0  tests/modeltests/test_client/models.py
  75. +56 −1 tests/regressiontests/forms/localflavor.py
  76. +16 −0 tests/regressiontests/string_lookup/models.py
View
2  AUTHORS
@@ -103,6 +103,7 @@ answer newbie questions, and generally made Django that much better:
dusk@woofle.net
Andy Dustman <farcepest@gmail.com>
Clint Ecker
+ Nick Efford <nick@efford.org>
eibaan@gmail.com
enlight
Enrico <rico.bl@gmail.com>
@@ -197,6 +198,7 @@ answer newbie questions, and generally made Django that much better:
mccutchen@gmail.com
michael.mcewan@gmail.com
mikko@sorl.net
+ Slawek Mikula <slawek dot mikula at gmail dot com>
mitakummaa@gmail.com
mmarshall
Andreas Mock <andreas.mock@web.de>
View
3  django/conf/global_settings.py
@@ -25,7 +25,8 @@
INTERNAL_IPS = ()
# Local time zone for this installation. All choices can be found here:
-# http://www.postgresql.org/docs/8.1/static/datetime-keywords.html#DATETIME-TIMEZONE-SET-TABLE
+# http://en.wikipedia.org/wiki/List_of_tz_zones_by_name (although not all
+# systems may support all possibilities).
TIME_ZONE = 'America/Chicago'
# Language code for this installation. All choices can be found here:
View
BIN  django/conf/locale/es/LC_MESSAGES/django.mo
Binary file not shown
View
9 django/conf/locale/es/LC_MESSAGES/django.po
@@ -6,7 +6,7 @@ msgid ""
msgstr ""
"Project-Id-Version: django\n"
"Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2007-08-13 11:29-0400\n"
+"POT-Creation-Date: 2007-08-17 15:35-0400\n"
"PO-Revision-Date: 2007-07-14 13:00-0500\n"
"Last-Translator: Mario Gonzalez <gonzalemario @t gmail.com>\n"
"Language-Team: Castellano <Django-I18N@googlegroups.com>\n"
@@ -22,6 +22,7 @@ msgstr "%(object)s de este %(type)s ya existen en este %(field)s."
#: db/models/manipulators.py:310 contrib/admin/views/main.py:342
#: contrib/admin/views/main.py:344 contrib/admin/views/main.py:346
+#: core/validators.py:275
msgid "and"
msgstr "y"
@@ -510,6 +511,10 @@ msgstr "%(number)d %(type)s"
msgid ", %(number)d %(type)s"
msgstr ", %(number)d %(type)s"
+#: utils/text.py:127
+msgid "or"
+msgstr "o"
+
#: utils/dateformat.py:41
msgid "p.m."
msgstr "p.m"
@@ -765,7 +770,7 @@ msgstr "ocho"
msgid "nine"
msgstr "nueve"
-#: contrib/auth/views.py:41
+#: contrib/auth/views.py:47
msgid "Logged out"
msgstr "Sesión terminada"
View
4 django/conf/project_template/settings.py
@@ -17,8 +17,8 @@
DATABASE_PORT = '' # Set to empty string for default. Not used with sqlite3.
# Local time zone for this installation. Choices can be found here:
-# http://www.postgresql.org/docs/8.1/static/datetime-keywords.html#DATETIME-TIMEZONE-SET-TABLE
-# although not all variations may be possible on all operating systems.
+# http://en.wikipedia.org/wiki/List_of_tz_zones_by_name
+# although not all choices may be avilable on all operating systems.
# If running in a Windows environment this must be set to the same as your
# system time zone.
TIME_ZONE = 'America/Chicago'
View
2  django/contrib/admin/templates/admin/index.html
@@ -59,7 +59,7 @@
{% else %}
<ul class="actionlist">
{% for entry in admin_log %}
- <li class="{% if entry.is_addition %}addlink{% endif %}{% if entry.is_change %}changelink{% endif %}{% if entry.is_deletion %}deletelink{% endif %}">{% if not entry.is_deletion %}<a href="{{ entry.get_admin_url }}">{% endif %}{{ entry.object_repr|escape }}{% if not entry.is_deletion %}</a>{% endif %}<br /><span class="mini quiet">{{ entry.content_type.name|capfirst|escape }}</span></li>
+ <li class="{% if entry.is_addition %}addlink{% endif %}{% if entry.is_change %}changelink{% endif %}{% if entry.is_deletion %}deletelink{% endif %}">{% if not entry.is_deletion %}<a href="{{ entry.get_admin_url }}">{% endif %}{{ entry.object_repr|escape }}{% if not entry.is_deletion %}</a>{% endif %}<br /><span class="mini quiet">{% filter capfirst|escape %}{% trans entry.content_type.name %}{% endfilter %}</span></li>
{% endfor %}
</ul>
{% endif %}
View
17 django/contrib/auth/models.py
@@ -1,6 +1,6 @@
from django.core import validators
from django.core.exceptions import ImproperlyConfigured
-from django.db import backend, connection, models
+from django.db import connection, models
from django.contrib.contenttypes.models import ContentType
from django.utils.encoding import smart_str
from django.utils.translation import ugettext_lazy as _
@@ -188,6 +188,7 @@ def get_group_permissions(self):
# AND gp."group_id" = ug."group_id"
# AND ct."id" = p."content_type_id"
# AND ug."user_id" = %s, [self.id])
+ qn = connection.ops.quote_name
sql = """
SELECT ct.%s, p.%s
FROM %s p, %s gp, %s ug, %s ct
@@ -195,13 +196,13 @@ def get_group_permissions(self):
AND gp.%s = ug.%s
AND ct.%s = p.%s
AND ug.%s = %%s""" % (
- backend.quote_name('app_label'), backend.quote_name('codename'),
- backend.quote_name('auth_permission'), backend.quote_name('auth_group_permissions'),
- backend.quote_name('auth_user_groups'), backend.quote_name('django_content_type'),
- backend.quote_name('id'), backend.quote_name('permission_id'),
- backend.quote_name('group_id'), backend.quote_name('group_id'),
- backend.quote_name('id'), backend.quote_name('content_type_id'),
- backend.quote_name('user_id'),)
+ qn('app_label'), qn('codename'),
+ qn('auth_permission'), qn('auth_group_permissions'),
+ qn('auth_user_groups'), qn('django_content_type'),
+ qn('id'), qn('permission_id'),
+ qn('group_id'), qn('group_id'),
+ qn('id'), qn('content_type_id'),
+ qn('user_id'),)
cursor.execute(sql, [self.id])
self._group_perm_cache = set(["%s.%s" % (row[0], row[1]) for row in cursor.fetchall()])
return self._group_perm_cache
View
10 django/contrib/contenttypes/generic.py
@@ -4,7 +4,7 @@
from django import oldforms
from django.core.exceptions import ObjectDoesNotExist
-from django.db import backend
+from django.db import connection
from django.db.models import signals
from django.db.models.fields.related import RelatedField, Field, ManyToManyRel
from django.db.models.loading import get_model
@@ -163,13 +163,15 @@ def __get__(self, instance, instance_type=None):
superclass = rel_model._default_manager.__class__
RelatedManager = create_generic_related_manager(superclass)
+ qn = connection.ops.quote_name
+
manager = RelatedManager(
model = rel_model,
instance = instance,
symmetrical = (self.field.rel.symmetrical and instance.__class__ == rel_model),
- join_table = backend.quote_name(self.field.m2m_db_table()),
- source_col_name = backend.quote_name(self.field.m2m_column_name()),
- target_col_name = backend.quote_name(self.field.m2m_reverse_name()),
+ join_table = qn(self.field.m2m_db_table()),
+ source_col_name = qn(self.field.m2m_column_name()),
+ target_col_name = qn(self.field.m2m_reverse_name()),
content_type = ContentType.objects.get_for_model(self.field.model),
content_type_field_name = self.field.content_type_field_name,
object_id_field_name = self.field.object_id_field_name
View
23 django/contrib/databrowse/datastructures.py
@@ -8,6 +8,7 @@
from django.utils.text import capfirst
from django.utils.translation import get_date_formats
from django.utils.encoding import smart_unicode, smart_str, iri_to_uri
+from django.db.models.query import QuerySet
EMPTY_VALUE = '(None)'
@@ -30,8 +31,12 @@ def url(self):
return '%s%s/%s/' % (self.site.root_url, self.model._meta.app_label, self.model._meta.module_name)
def objects(self, **kwargs):
- for obj in self.model._default_manager.filter(**kwargs):
- yield EasyInstance(self, obj)
+ return self.get_query_set().filter(**kwargs)
+
+ def get_query_set(self):
+ easy_qs = self.model._default_manager.get_query_set()._clone(klass=EasyQuerySet)
+ easy_qs._easymodel = self
+ return easy_qs
def object_by_pk(self, pk):
return EasyInstance(self, self.model._default_manager.get(pk=pk))
@@ -194,3 +199,17 @@ def urls(self):
else:
lst = [(self.values()[0], None)]
return lst
+
+class EasyQuerySet(QuerySet):
+ """
+ When creating (or cloning to) an `EasyQuerySet`, make sure to set the
+ `_easymodel` variable to the related `EasyModel`.
+ """
+ def iterator(self, *args, **kwargs):
+ for obj in super(EasyQuerySet, self).iterator(*args, **kwargs):
+ yield EasyInstance(self._easymodel, obj)
+
+ def _clone(self, *args, **kwargs):
+ c = super(EasyQuerySet, self)._clone(*args, **kwargs)
+ c._easymodel = self._easymodel
+ return c
View
10 django/contrib/databrowse/plugins/calendars.py
@@ -64,22 +64,22 @@ def homepage_view(self, request):
def calendar_view(self, request, field, year=None, month=None, day=None):
easy_model = EasyModel(self.site, self.model)
+ queryset = easy_model.get_query_set()
extra_context = {'root_url': self.site.root_url, 'model': easy_model, 'field': field}
if day is not None:
- # TODO: The objects in this template should be EasyInstances
- return date_based.archive_day(request, year, month, day, self.model.objects.all(), field.name,
+ return date_based.archive_day(request, year, month, day, queryset, field.name,
template_name='databrowse/calendar_day.html', allow_empty=False, allow_future=True,
extra_context=extra_context)
elif month is not None:
- return date_based.archive_month(request, year, month, self.model.objects.all(), field.name,
+ return date_based.archive_month(request, year, month, queryset, field.name,
template_name='databrowse/calendar_month.html', allow_empty=False, allow_future=True,
extra_context=extra_context)
elif year is not None:
- return date_based.archive_year(request, year, self.model.objects.all(), field.name,
+ return date_based.archive_year(request, year, queryset, field.name,
template_name='databrowse/calendar_year.html', allow_empty=False, allow_future=True,
extra_context=extra_context)
else:
- return date_based.archive_index(request, self.model.objects.all(), field.name,
+ return date_based.archive_index(request, queryset, field.name,
template_name='databrowse/calendar_main.html', allow_empty=True, allow_future=True,
extra_context=extra_context)
assert False, ('%s, %s, %s, %s' % (field, year, month, day))
View
5 django/contrib/databrowse/templates/databrowse/base.html
@@ -2,6 +2,7 @@
<html xmlns="http://www.w3.org/1999/xhtml" lang="{{ LANGUAGE_CODE }}" xml:lang="{{ LANGUAGE_CODE }}" {% if LANGUAGE_BIDI %}dir="rtl"{% endif %}>
<head>
<title>{% block title %}{% endblock %}</title>
+{% block style %}
<style type="text/css">
* { margin:0; padding:0; }
body { background:#eee; color:#333; font:76%/1.6 "Lucida Grande","Bitstream Vera Sans",Verdana,sans-serif; }
@@ -48,9 +49,11 @@
/* CONTENT */
#content { background:#fff; border-bottom:1px solid #ddd; padding:0 20px; }
</style>
+{% endblock %}
+{% block extrahead %}{% endblock %}
</head>
<body id="{% block bodyid %}page{% endblock %}">
-<div id="header"><a href="{{ root_url }}">Databrowse</a></div>
+<div id="header"><a href="{{ root_url }}">{% block databrowse_title %}Databrowse{% endblock %}</a></div>
<div id="content">
{% block content %}{% endblock %}
</div>
View
1  django/contrib/databrowse/templates/databrowse/base_site.html
@@ -0,0 +1 @@
+{% extends "databrowse/base.html" %}
View
4 django/contrib/databrowse/templates/databrowse/calendar_day.html
@@ -1,4 +1,4 @@
-{% extends "databrowse/base.html" %}
+{% extends "databrowse/base_site.html" %}
{% block title %}{{ model.verbose_name_plural|capfirst }} with {{ field.verbose_name }} {{ day|date:"F j, Y" }}{% endblock %}
@@ -6,7 +6,7 @@
<div id="breadcrumbs"><a href="{{ root_url }}">Home</a> / <a href="{{ model.url }}">{{ model.verbose_name_plural|capfirst }}</a> / <a href="../../../../">Calendars</a> / <a href="../../../">By {{ field.verbose_name }}</a> / <a href="../../">{{ day.year }}</a> / <a href="../">{{ day|date:"F" }}</a> / {{ day.day }}</div>
-<h1>{{ model.verbose_name_plural|capfirst }} with {{ field.verbose_name }} on {{ day|date:"F j, Y" }}</h1>
+<h1>{{ object_list.count }} {% if object_list.count|pluralize %}{{ model.verbose_name_plural|escape }}{% else %}{{ model.verbose_name|escape }}{% endif %} with {{ field.verbose_name }} on {{ day|date:"F j, Y" }}</h1>
<ul class="objectlist">
{% for object in object_list %}
View
2  django/contrib/databrowse/templates/databrowse/calendar_homepage.html
@@ -1,4 +1,4 @@
-{% extends "databrowse/base.html" %}
+{% extends "databrowse/base_site.html" %}
{% block title %}Calendars{% endblock %}
View
2  django/contrib/databrowse/templates/databrowse/calendar_main.html
@@ -1,4 +1,4 @@
-{% extends "databrowse/base.html" %}
+{% extends "databrowse/base_site.html" %}
{% block title %}{{ field.verbose_name|capfirst }} calendar{% endblock %}
View
4 django/contrib/databrowse/templates/databrowse/calendar_month.html
@@ -1,4 +1,4 @@
-{% extends "databrowse/base.html" %}
+{% extends "databrowse/base_site.html" %}
{% block title %}{{ model.verbose_name_plural|capfirst }} with {{ field.verbose_name }} in {{ month|date:"F Y" }}{% endblock %}
@@ -6,7 +6,7 @@
<div id="breadcrumbs"><a href="{{ root_url }}">Home</a> / <a href="{{ model.url }}">{{ model.verbose_name_plural|capfirst }}</a> / <a href="../../../">Calendars</a> / <a href="../../">By {{ field.verbose_name }}</a> / <a href="../">{{ month.year }}</a> / {{ month|date:"F" }}</div>
-<h1>{{ model.verbose_name_plural|capfirst }} with {{ field.verbose_name }} in {{ month|date:"F Y" }}</h1>
+<h1>{{ object_list.count }} {% if object_list.count|pluralize %}{{ model.verbose_name_plural|escape }}{% else %}{{ model.verbose_name|escape }}{% endif %} with {{ field.verbose_name }} on {{ day|date:"F Y" }}</h1>
<ul class="objectlist">
{% for object in object_list %}
View
2  django/contrib/databrowse/templates/databrowse/calendar_year.html
@@ -1,4 +1,4 @@
-{% extends "databrowse/base.html" %}
+{% extends "databrowse/base_site.html" %}
{% block title %}{{ model.verbose_name_plural|capfirst }} with {{ field.verbose_name }} in {{ year }}{% endblock %}
View
2  django/contrib/databrowse/templates/databrowse/choice_detail.html
@@ -1,4 +1,4 @@
-{% extends "databrowse/base.html" %}
+{% extends "databrowse/base_site.html" %}
{% block title %}{{ model.verbose_name_plural|capfirst }} by {{ field.field.verbose_name }}: {{ value|escape }}{% endblock %}
View
2  django/contrib/databrowse/templates/databrowse/choice_list.html
@@ -1,4 +1,4 @@
-{% extends "databrowse/base.html" %}
+{% extends "databrowse/base_site.html" %}
{% block title %}{{ model.verbose_name_plural|capfirst }} by {{ field.field.verbose_name }}{% endblock %}
View
4 django/contrib/databrowse/templates/databrowse/fieldchoice_detail.html
@@ -1,4 +1,4 @@
-{% extends "databrowse/base.html" %}
+{% extends "databrowse/base_site.html" %}
{% block title %}{{ model.verbose_name_plural|capfirst|escape }} with {{ field.field.verbose_name|escape }} {{ value|escape }}{% endblock %}
@@ -6,7 +6,7 @@
<div id="breadcrumbs"><a href="{{ root_url }}">Home</a> / <a href="{{ model.url }}">{{ model.verbose_name_plural|capfirst }}</a> / <a href="../../">Fields</a> / <a href="../">By {{ field.field.verbose_name|escape }}</a> / {{ value|escape }}</div>
-<h1>{{ model.verbose_name_plural|capfirst|escape }} with {{ field.field.verbose_name|escape }} {{ value|escape }}</h1>
+<h1>{{ object_list.count }} {% if object_list.count|pluralize %}{{ model.verbose_name_plural|escape }}{% else %}{{ model.verbose_name|escape }}{% endif %} with {{ field.field.verbose_name|escape }} {{ value|escape }}</h1>
<ul class="objectlist">
{% for object in object_list %}
View
2  django/contrib/databrowse/templates/databrowse/fieldchoice_homepage.html
@@ -1,4 +1,4 @@
-{% extends "databrowse/base.html" %}
+{% extends "databrowse/base_site.html" %}
{% block title %}Browsable fields in {{ model.verbose_name_plural|escape }}{% endblock %}
View
2  django/contrib/databrowse/templates/databrowse/fieldchoice_list.html
@@ -1,4 +1,4 @@
-{% extends "databrowse/base.html" %}
+{% extends "databrowse/base_site.html" %}
{% block title %}{{ model.verbose_name_plural|capfirst|escape }} by {{ field.field.verbose_name|escape }}{% endblock %}
View
2  django/contrib/databrowse/templates/databrowse/homepage.html
@@ -1,4 +1,4 @@
-{% extends "databrowse/base.html" %}
+{% extends "databrowse/base_site.html" %}
{% block title %}Databrowse{% endblock %}
View
4 django/contrib/databrowse/templates/databrowse/model_detail.html
@@ -1,4 +1,4 @@
-{% extends "databrowse/base.html" %}
+{% extends "databrowse/base_site.html" %}
{% block title %}{{ model.verbose_name_plural|capfirst }}{% endblock %}
@@ -6,7 +6,7 @@
<div id="breadcrumbs"><a href="{{ root_url }}">Home</a> / {{ model.verbose_name_plural|capfirst }}</div>
-<h1>{{ model.verbose_name_plural|capfirst }}</h1>
+<h1>{{ model.objects.count }} {% if model.objects.count|pluralize %}{{ model.verbose_name_plural }}{% else %}{{ model.verbose_name }}{% endif %}</h1>
{{ plugin_html }}
View
2  django/contrib/databrowse/templates/databrowse/object_detail.html
@@ -1,4 +1,4 @@
-{% extends "databrowse/base.html" %}
+{% extends "databrowse/base_site.html" %}
{% block title %}{{ object.model.verbose_name|capfirst }}: {{ object }}{% endblock %}
View
0  django/contrib/localflavor/pl/__init__.py
No changes.
View
84 django/contrib/localflavor/pl/forms.py
@@ -0,0 +1,84 @@
+"""
+Polish-specific form helpers
+"""
+
+from django.newforms import ValidationError
+from django.newforms.fields import Select, RegexField
+from django.utils.translation import ugettext as _
+
+class PLVoivodeshipSelect(Select):
+ """
+ A select widget with list of Polish voivodeships (administrative provinces)
+ as choices.
+ """
+ def __init__(self, attrs=None):
+ from pl_voivodeships import VOIVODESHIP_CHOICES
+ super(PLVoivodeshipSelect, self).__init__(attrs, choices=VOIVODESHIP_CHOICES)
+
+class PLAdministrativeUnitSelect(Select):
+ """
+ A select widget with list of Polish administrative units as choices.
+ """
+ def __init__(self, attrs=None):
+ from pl_administrativeunits import ADMINISTRATIVE_UNIT_CHOICES
+ super(PLAdministrativeUnitSelect, self).__init__(attrs, choices=ADMINISTRATIVE_UNIT_CHOICES)
+
+class PLNationalIdentificationNumberField(RegexField):
+ """
+ A form field that validates as Polish Identification Number (PESEL).
+
+ Checks the following rules:
+ * the length consist of 11 digits
+ * has a valid checksum
+
+ The algorithm is documented at http://en.wikipedia.org/wiki/PESEL.
+ """
+
+ def has_valid_checksum(self, number):
+ """
+ Calculates a checksum with the provided algorithm.
+ """
+ multiple_table = (1, 3, 7, 9, 1, 3, 7, 9, 1, 3, 1)
+ result = 0
+ for i in range(len(number)):
+ result += int(number[i])*multiple_table[i]
+
+ if result % 10 == 0:
+ return True
+ else:
+ return False
+
+ def __init__(self, *args, **kwargs):
+ super(PLNationalIdentificationNumberField, self).__init__(r'^\d{11}$',
+ max_length=None, min_length=None, error_message=_(u'National Identification Number consists of 11 digits.'),
+ *args, **kwargs)
+
+ def clean(self,value):
+ super(PLNationalIdentificationNumberField, self).clean(value)
+ if not self.has_valid_checksum(value):
+ raise ValidationError(_(u'Wrong checksum for the National Identification Number.'))
+ return u'%s' % value
+
+
+class PLTaxNumberField(RegexField):
+ """
+ A form field that validates as Polish Tax Number (NIP).
+ Valid forms are: XXX-XXX-YY-YY or XX-XX-YYY-YYY.
+ """
+ def __init__(self, *args, **kwargs):
+ super(PLTaxNumberField, self).__init__(r'^\d{3}-\d{3}-\d{2}-\d{2}$|^\d{2}-\d{2}-\d{3}-\d{3}$',
+ max_length=None, min_length=None,
+ error_message=_(u'Enter a tax number field (NIP) in the format XXX-XXX-XX-XX or XX-XX-XXX-XXX.'), *args, **kwargs)
+
+
+class PLPostalCodeField(RegexField):
+ """
+ A form field that validates as Polish postal code.
+ Valid code is XX-XXX where X is digit.
+ """
+ def __init__(self, *args, **kwargs):
+ super(PLPostalCodeField, self).__init__(r'^\d{2}-\d{3}$',
+ max_length=None, min_length=None,
+ error_message=_(u'Enter a postal code in the format XX-XXX.'),
+ *args, **kwargs)
+
View
385 django/contrib/localflavor/pl/pl_administrativeunits.py
@@ -0,0 +1,385 @@
+# -*- coding: utf-8 -*-
+"""
+Polish administrative units as in http://pl.wikipedia.org/wiki/Podzia%C5%82_administracyjny_Polski
+"""
+
+
+ADMINISTRATIVE_UNIT_CHOICES = (
+ ('wroclaw', u'Wrocław'),
+ ('jeleniagora', u'Jelenia Góra'),
+ ('legnica', u'Legnica'),
+ ('boleslawiecki', u'bolesławiecki'),
+ ('dzierzoniowski', u'dzierżoniowski'),
+ ('glogowski', u'głogowski'),
+ ('gorowski', u'górowski'),
+ ('jaworski', u'jaworski'),
+ ('jeleniogorski', u'jeleniogórski'),
+ ('kamiennogorski', u'kamiennogórski'),
+ ('klodzki', u'kłodzki'),
+ ('legnicki', u'legnicki'),
+ ('lubanski', u'lubański'),
+ ('lubinski', u'lubiński'),
+ ('lwowecki', u'lwówecki'),
+ ('milicki', u'milicki'),
+ ('olesnicki', u'oleśnicki'),
+ ('olawski', u'oławski'),
+ ('polkowicki', u'polkowicki'),
+ ('strzelinski', u'strzeliński'),
+ ('sredzki', u'średzki'),
+ ('swidnicki', u'świdnicki'),
+ ('trzebnicki', u'trzebnicki'),
+ ('walbrzyski', u'wałbrzyski'),
+ ('wolowski', u'wołowski'),
+ ('wroclawski', u'wrocławski'),
+ ('zabkowicki', u'ząbkowicki'),
+ ('zgorzelecki', u'zgorzelecki'),
+ ('zlotoryjski', u'złotoryjski'),
+ ('bydgoszcz', u'Bydgoszcz'),
+ ('torun', u'Toruń'),
+ ('wloclawek', u'Włocławek'),
+ ('grudziadz', u'Grudziądz'),
+ ('aleksandrowski', u'aleksandrowski'),
+ ('brodnicki', u'brodnicki'),
+ ('bydgoski', u'bydgoski'),
+ ('chelminski', u'chełmiński'),
+ ('golubsko-dobrzynski', u'golubsko-dobrzyński'),
+ ('grudziadzki', u'grudziądzki'),
+ ('inowroclawski', u'inowrocławski'),
+ ('lipnowski', u'lipnowski'),
+ ('mogilenski', u'mogileński'),
+ ('nakielski', u'nakielski'),
+ ('radziejowski', u'radziejowski'),
+ ('rypinski', u'rypiński'),
+ ('sepolenski', u'sępoleński'),
+ ('swiecki', u'świecki'),
+ ('torunski', u'toruński'),
+ ('tucholski', u'tucholski'),
+ ('wabrzeski', u'wąbrzeski'),
+ ('wloclawski', u'wrocławski'),
+ ('zninski', u'źniński'),
+ ('lublin', u'Lublin'),
+ ('biala-podlaska', u'Biała Podlaska'),
+ ('chelm', u'Chełm'),
+ ('zamosc', u'Zamość'),
+ ('bialski', u'bialski'),
+ ('bilgorajski', u'biłgorajski'),
+ ('chelmski', u'chełmski'),
+ ('hrubieszowski', u'hrubieszowski'),
+ ('janowski', u'janowski'),
+ ('krasnostawski', u'krasnostawski'),
+ ('krasnicki', u'kraśnicki'),
+ ('lubartowski', u'lubartowski'),
+ ('lubelski', u'lubelski'),
+ ('leczynski', u'łęczyński'),
+ ('lukowski', u'łukowski'),
+ ('opolski', u'opolski'),
+ ('parczewski', u'parczewski'),
+ ('pulawski', u'puławski'),
+ ('radzynski', u'radzyński'),
+ ('rycki', u'rycki'),
+ ('swidnicki', u'świdnicki'),
+ ('tomaszowski', u'tomaszowski'),
+ ('wlodawski', u'włodawski'),
+ ('zamojski', u'zamojski'),
+ ('gorzow-wielkopolski', u'Gorzów Wielkopolski'),
+ ('zielona-gora', u'Zielona Góra'),
+ ('gorzowski', u'gorzowski'),
+ ('krosnienski', u'krośnieński'),
+ ('miedzyrzecki', u'międzyrzecki'),
+ ('nowosolski', u'nowosolski'),
+ ('slubicki', u'słubicki'),
+ ('strzelecko-drezdenecki', u'strzelecko-drezdenecki'),
+ ('sulecinski', u'suleńciński'),
+ ('swiebodzinski', u'świebodziński'),
+ ('wschowski', u'wschowski'),
+ ('zielonogorski', u'zielonogórski'),
+ ('zaganski', u'żagański'),
+ ('zarski', u'żarski'),
+ ('lodz', u'Łódź'),
+ ('piotrkow-trybunalski', u'Piotrków Trybunalski'),
+ ('skierniewice', u'Skierniewice'),
+ ('belchatowski', u'bełchatowski'),
+ ('brzezinski', u'brzeziński'),
+ ('kutnowski', u'kutnowski'),
+ ('laski', u'łaski'),
+ ('leczycki', u'łęczycki'),
+ ('lowicki', u'łowicki'),
+ ('lodzki wschodni', u'łódzki wschodni'),
+ ('opoczynski', u'opoczyński'),
+ ('pabianicki', u'pabianicki'),
+ ('pajeczanski', u'pajęczański'),
+ ('piotrkowski', u'piotrkowski'),
+ ('poddebicki', u'poddębicki'),
+ ('radomszczanski', u'radomszczański'),
+ ('rawski', u'rawski'),
+ ('sieradzki', u'sieradzki'),
+ ('skierniewicki', u'skierniewicki'),
+ ('tomaszowski', u'tomaszowski'),
+ ('wielunski', u'wieluński'),
+ ('wieruszowski', u'wieruszowski'),
+ ('zdunskowolski', u'zduńskowolski'),
+ ('zgierski', u'zgierski'),
+ ('krakow', u'Kraków'),
+ ('tarnow', u'Tarnów'),
+ ('nowy-sacz', u'Nowy Sącz'),
+ ('bochenski', u'bocheński'),
+ ('brzeski', u'brzeski'),
+ ('chrzanowski', u'chrzanowski'),
+ ('dabrowski', u'dąbrowski'),
+ ('gorlicki', u'gorlicki'),
+ ('krakowski', u'krakowski'),
+ ('limanowski', u'limanowski'),
+ ('miechowski', u'miechowski'),
+ ('myslenicki', u'myślenicki'),
+ ('nowosadecki', u'nowosądecki'),
+ ('nowotarski', u'nowotarski'),
+ ('olkuski', u'olkuski'),
+ ('oswiecimski', u'oświęcimski'),
+ ('proszowicki', u'proszowicki'),
+ ('suski', u'suski'),
+ ('tarnowski', u'tarnowski'),
+ ('tatrzanski', u'tatrzański'),
+ ('wadowicki', u'wadowicki'),
+ ('wielicki', u'wielicki'),
+ ('warszawa', u'Warszawa'),
+ ('ostroleka', u'Ostrołęka'),
+ ('plock', u'Płock'),
+ ('radom', u'Radom'),
+ ('siedlce', u'Siedlce'),
+ ('bialobrzeski', u'białobrzeski'),
+ ('ciechanowski', u'ciechanowski'),
+ ('garwolinski', u'garwoliński'),
+ ('gostyninski', u'gostyniński'),
+ ('grodziski', u'grodziski'),
+ ('grojecki', u'grójecki'),
+ ('kozienicki', u'kozenicki'),
+ ('legionowski', u'legionowski'),
+ ('lipski', u'lipski'),
+ ('losicki', u'łosicki'),
+ ('makowski', u'makowski'),
+ ('minski', u'miński'),
+ ('mlawski', u'mławski'),
+ ('nowodworski', u'nowodworski'),
+ ('ostrolecki', u'ostrołęcki'),
+ ('ostrowski', u'ostrowski'),
+ ('otwocki', u'otwocki'),
+ ('piaseczynski', u'piaseczyński'),
+ ('plocki', u'płocki'),
+ ('plonski', u'płoński'),
+ ('pruszkowski', u'pruszkowski'),
+ ('przasnyski', u'przasnyski'),
+ ('przysuski', u'przysuski'),
+ ('pultuski', u'pułtuski'),
+ ('radomski', u'radomski'),
+ ('siedlecki', u'siedlecki'),
+ ('sierpecki', u'sierpecki'),
+ ('sochaczewski', u'sochaczewski'),
+ ('sokolowski', u'sokołowski'),
+ ('szydlowiecki', u'szydłowiecki'),
+ ('warszawski-zachodni', u'warszawski zachodni'),
+ ('wegrowski', u'węgrowski'),
+ ('wolominski', u'wołomiński'),
+ ('wyszkowski', u'wyszkowski'),
+ ('zwolenski', u'zwoleński'),
+ ('zurominski', u'żuromiński'),
+ ('zyrardowski', u'żyrardowski'),
+ ('opole', u'Opole'),
+ ('brzeski', u'brzeski'),
+ ('glubczycki', u'głubczyski'),
+ ('kedzierzynsko-kozielski', u'kędzierzyński-kozielski'),
+ ('kluczborski', u'kluczborski'),
+ ('krapkowicki', u'krapkowicki'),
+ ('namyslowski', u'namysłowski'),
+ ('nyski', u'nyski'),
+ ('oleski', u'oleski'),
+ ('opolski', u'opolski'),
+ ('prudnicki', u'prudnicki'),
+ ('strzelecki', u'strzelecki'),
+ ('rzeszow', u'Rzeszów'),
+ ('krosno', u'Krosno'),
+ ('przemysl', u'Przemyśl'),
+ ('tarnobrzeg', u'Tarnobrzeg'),
+ ('bieszczadzki', u'bieszczadzki'),
+ ('brzozowski', u'brzozowski'),
+ ('debicki', u'dębicki'),
+ ('jaroslawski', u'jarosławski'),
+ ('jasielski', u'jasielski'),
+ ('kolbuszowski', u'kolbuszowski'),
+ ('krosnienski', u'krośnieński'),
+ ('leski', u'leski'),
+ ('lezajski', u'leżajski'),
+ ('lubaczowski', u'lubaczowski'),
+ ('lancucki', u'łańcucki'),
+ ('mielecki', u'mielecki'),
+ ('nizanski', u'niżański'),
+ ('przemyski', u'przemyski'),
+ ('przeworski', u'przeworski'),
+ ('ropczycko-sedziszowski', u'ropczycko-sędziszowski'),
+ ('rzeszowski', u'rzeszowski'),
+ ('sanocki', u'sanocki'),
+ ('stalowowolski', u'stalowowolski'),
+ ('strzyzowski', u'strzyżowski'),
+ ('tarnobrzeski', u'tarnobrzeski'),
+ ('bialystok', u'Białystok'),
+ ('lomza', u'Łomża'),
+ ('suwalki', u'Suwałki'),
+ ('augustowski', u'augustowski'),
+ ('bialostocki', u'białostocki'),
+ ('bielski', u'bielski'),
+ ('grajewski', u'grajewski'),
+ ('hajnowski', u'hajnowski'),
+ ('kolnenski', u'kolneński'),
+ ('łomzynski', u'łomżyński'),
+ ('moniecki', u'moniecki'),
+ ('sejnenski', u'sejneński'),
+ ('siemiatycki', u'siematycki'),
+ ('sokolski', u'sokólski'),
+ ('suwalski', u'suwalski'),
+ ('wysokomazowiecki', u'wysokomazowiecki'),
+ ('zambrowski', u'zambrowski'),
+ ('gdansk', u'Gdańsk'),
+ ('gdynia', u'Gdynia'),
+ ('slupsk', u'Słupsk'),
+ ('sopot', u'Sopot'),
+ ('bytowski', u'bytowski'),
+ ('chojnicki', u'chojnicki'),
+ ('czluchowski', u'człuchowski'),
+ ('kartuski', u'kartuski'),
+ ('koscierski', u'kościerski'),
+ ('kwidzynski', u'kwidzyński'),
+ ('leborski', u'lęborski'),
+ ('malborski', u'malborski'),
+ ('nowodworski', u'nowodworski'),
+ ('gdanski', u'gdański'),
+ ('pucki', u'pucki'),
+ ('slupski', u'słupski'),
+ ('starogardzki', u'starogardzki'),
+ ('sztumski', u'sztumski'),
+ ('tczewski', u'tczewski'),
+ ('wejherowski', u'wejcherowski'),
+ ('katowice', u'Katowice'),
+ ('bielsko-biala', u'Bielsko-Biała'),
+ ('bytom', u'Bytom'),
+ ('chorzow', u'Chorzów'),
+ ('czestochowa', u'Częstochowa'),
+ ('dabrowa-gornicza', u'Dąbrowa Górnicza'),
+ ('gliwice', u'Gliwice'),
+ ('jastrzebie-zdroj', u'Jastrzębie Zdrój'),
+ ('jaworzno', u'Jaworzno'),
+ ('myslowice', u'Mysłowice'),
+ ('piekary-slaskie', u'Piekary Śląskie'),
+ ('ruda-slaska', u'Ruda Śląska'),
+ ('rybnik', u'Rybnik'),
+ ('siemianowice-slaskie', u'Siemianowice Śląskie'),
+ ('sosnowiec', u'Sosnowiec'),
+ ('swietochlowice', u'Świętochłowice'),
+ ('tychy', u'Tychy'),
+ ('zabrze', u'Zabrze'),
+ ('zory', u'Żory'),
+ ('bedzinski', u'będziński'),
+ ('bielski', u'bielski'),
+ ('bierunsko-ledzinski', u'bieruńsko-lędziński'),
+ ('cieszynski', u'cieszyński'),
+ ('czestochowski', u'częstochowski'),
+ ('gliwicki', u'gliwicki'),
+ ('klobucki', u'kłobucki'),
+ ('lubliniecki', u'lubliniecki'),
+ ('mikolowski', u'mikołowski'),
+ ('myszkowski', u'myszkowski'),
+ ('pszczynski', u'pszczyński'),
+ ('raciborski', u'raciborski'),
+ ('rybnicki', u'rybnicki'),
+ ('tarnogorski', u'tarnogórski'),
+ ('wodzislawski', u'wodzisławski'),
+ ('zawiercianski', u'zawierciański'),
+ ('zywiecki', u'żywiecki'),
+ ('kielce', u'Kielce'),
+ ('buski', u'buski'),
+ ('jedrzejowski', u'jędrzejowski'),
+ ('kazimierski', u'kazimierski'),
+ ('kielecki', u'kielecki'),
+ ('konecki', u'konecki'),
+ ('opatowski', u'opatowski'),
+ ('ostrowiecki', u'ostrowiecki'),
+ ('pinczowski', u'pińczowski'),
+ ('sandomierski', u'sandomierski'),
+ ('skarzyski', u'skarżyski'),
+ ('starachowicki', u'starachowicki'),
+ ('staszowski', u'staszowski'),
+ ('wloszczowski', u'włoszczowski'),
+ ('olsztyn', u'Olsztyn'),
+ ('elblag', u'Elbląg'),
+ ('bartoszycki', u'bartoszycki'),
+ ('braniewski', u'braniewski'),
+ ('dzialdowski', u'działdowski'),
+ ('elblaski', u'elbląski'),
+ ('elcki', u'ełcki'),
+ ('gizycki', u'giżycki'),
+ ('goldapski', u'gołdapski'),
+ ('ilawski', u'iławski'),
+ ('ketrzynski', u'kętrzyński'),
+ ('lidzbarski', u'lidzbarski'),
+ ('mragowski', u'mrągowski'),
+ ('nidzicki', u'nidzicki'),
+ ('nowomiejski', u'nowomiejski'),
+ ('olecki', u'olecki'),
+ ('olsztynski', u'olsztyński'),
+ ('ostrodzki', u'ostródzki'),
+ ('piski', u'piski'),
+ ('szczycienski', u'szczycieński'),
+ ('wegorzewski', u'węgorzewski'),
+ ('poznan', u'Poznań'),
+ ('kalisz', u'Kalisz'),
+ ('konin', u'Konin'),
+ ('leszno', u'Leszno'),
+ ('chodzieski', u'chodziejski'),
+ ('czarnkowsko-trzcianecki', u'czarnkowsko-trzcianecki'),
+ ('gnieznienski', u'gnieźnieński'),
+ ('gostynski', u'gostyński'),
+ ('grodziski', u'grodziski'),
+ ('jarocinski', u'jarociński'),
+ ('kaliski', u'kaliski'),
+ ('kepinski', u'kępiński'),
+ ('kolski', u'kolski'),
+ ('koninski', u'koniński'),
+ ('koscianski', u'kościański'),
+ ('krotoszynski', u'krotoszyński'),
+ ('leszczynski', u'leszczyński'),
+ ('miedzychodzki', u'międzychodzki'),
+ ('nowotomyski', u'nowotomyski'),
+ ('obornicki', u'obornicki'),
+ ('ostrowski', u'ostrowski'),
+ ('ostrzeszowski', u'ostrzeszowski'),
+ ('pilski', u'pilski'),
+ ('pleszewski', u'pleszewski'),
+ ('poznanski', u'poznański'),
+ ('rawicki', u'rawicki'),
+ ('slupecki', u'słupecki'),
+ ('szamotulski', u'szamotulski'),
+ ('sredzki', u'średzki'),
+ ('sremski', u'śremski'),
+ ('turecki', u'turecki'),
+ ('wagrowiecki', u'wągrowiecki'),
+ ('wolsztynski', u'wolsztyński'),
+ ('wrzesinski', u'wrzesiński'),
+ ('zlotowski', u'złotowski'),
+ ('bialogardzki', u'białogardzki'),
+ ('choszczenski', u'choszczeński'),
+ ('drawski', u'drawski'),
+ ('goleniowski', u'goleniowski'),
+ ('gryficki', u'gryficki'),
+ ('gryfinski', u'gryfiński'),
+ ('kamienski', u'kamieński'),
+ ('kolobrzeski', u'kołobrzeski'),
+ ('koszalinski', u'koszaliński'),
+ ('lobeski', u'łobeski'),
+ ('mysliborski', u'myśliborski'),
+ ('policki', u'policki'),
+ ('pyrzycki', u'pyrzycki'),
+ ('slawienski', u'sławieński'),
+ ('stargardzki', u'stargardzki'),
+ ('szczecinecki', u'szczecinecki'),
+ ('swidwinski', u'świdwiński'),
+ ('walecki', u'wałecki'),
+)
+
View
24 django/contrib/localflavor/pl/pl_voivodeships.py
@@ -0,0 +1,24 @@
+"""
+Polish voivodeship as in http://en.wikipedia.org/wiki/Poland#Administrative_division
+"""
+
+from django.utils.translation import ugettext_lazy as _
+
+VOIVODESHIP_CHOICES = (
+ ('lower_silesia', _('Lower Silesia')),
+ ('kuyavia-pomerania', _('Kuyavia-Pomerania')),
+ ('lublin', _('Lublin')),
+ ('lubusz', _('Lubusz')),
+ ('lodz', _('Lodz')),
+ ('lesser_poland', _('Lesser Poland')),
+ ('masovia', _('Masovia')),
+ ('opole', _('Opole')),
+ ('subcarpatia', _('Subcarpatia')),
+ ('podlasie', _('Podlasie')),
+ ('pomerania', _('Pomerania')),
+ ('silesia', _('Silesia')),
+ ('swietokrzyskie', _('Swietokrzyskie')),
+ ('warmia-masuria', _('Warmia-Masuria')),
+ ('greater_poland', _('Greater Poland')),
+ ('west_pomerania', _('West Pomerania')),
+)
View
6 django/core/management/base.py
@@ -34,9 +34,9 @@ def execute(self, *args, **options):
if output:
if self.output_transaction:
# This needs to be imported here, because it relies on settings.
- from django.db import backend
- if backend.get_start_transaction_sql():
- print self.style.SQL_KEYWORD(backend.get_start_transaction_sql())
+ from django.db import connection
+ if connection.ops.start_transaction_sql():
+ print self.style.SQL_KEYWORD(connection.ops.start_transaction_sql())
print output
if self.output_transaction:
print self.style.SQL_KEYWORD("COMMIT;")
View
11 django/core/management/commands/createcachetable.py
@@ -8,7 +8,7 @@ class Command(LabelCommand):
requires_model_validation = False
def handle_label(self, tablename, **options):
- from django.db import backend, connection, transaction, models
+ from django.db import connection, transaction, models
fields = (
# "key" is a reserved word in MySQL, so use "cache_key" instead.
models.CharField(name='cache_key', max_length=255, unique=True, primary_key=True),
@@ -17,8 +17,9 @@ def handle_label(self, tablename, **options):
)
table_output = []
index_output = []
+ qn = connection.ops.quote_name
for f in fields:
- field_output = [backend.quote_name(f.name), f.db_type()]
+ field_output = [qn(f.name), f.db_type()]
field_output.append("%sNULL" % (not f.null and "NOT " or ""))
if f.unique:
field_output.append("UNIQUE")
@@ -27,10 +28,10 @@ def handle_label(self, tablename, **options):
if f.db_index:
unique = f.unique and "UNIQUE " or ""
index_output.append("CREATE %sINDEX %s_%s ON %s (%s);" % \
- (unique, tablename, f.name, backend.quote_name(tablename),
- backend.quote_name(f.name)))
+ (unique, tablename, f.name, qn(tablename),
+ qn(f.name)))
table_output.append(" ".join(field_output))
- full_statement = ["CREATE TABLE %s (" % backend.quote_name(tablename)]
+ full_statement = ["CREATE TABLE %s (" % qn(tablename)]
for i, line in enumerate(table_output):
full_statement.append(' %s%s' % (line, i < len(table_output)-1 and ',' or ''))
full_statement.append(');')
View
4 django/core/management/commands/loaddata.py
@@ -15,7 +15,7 @@ class Command(BaseCommand):
def handle(self, *fixture_labels, **options):
from django.db.models import get_apps
from django.core import serializers
- from django.db import connection, transaction, backend
+ from django.db import connection, transaction
from django.conf import settings
self.style = no_style()
@@ -105,7 +105,7 @@ def handle(self, *fixture_labels, **options):
(format, fixture_name, humanize(fixture_dir))
if count[0] > 0:
- sequence_sql = backend.get_sql_sequence_reset(self.style, models)
+ sequence_sql = connection.ops.sequence_reset_sql(self.style, models)
if sequence_sql:
if verbosity > 1:
print "Resetting sequences"
View
4 django/core/management/commands/sqlsequencereset.py
@@ -5,5 +5,5 @@ class Command(AppCommand):
output_transaction = True
def handle_app(self, app, **options):
- from django.db import backend, models
- return '\n'.join(backend.get_sql_sequence_reset(self.style, models.get_models(app)))
+ from django.db import connection, models
+ return '\n'.join(connection.ops.sequence_reset_sql(self.style, models.get_models(app)))
View
8 django/core/management/commands/syncdb.py
@@ -12,7 +12,7 @@ class Command(NoArgsCommand):
args = '[--verbosity] [--noinput]'
def handle_noargs(self, **options):
- from django.db import backend, connection, transaction, models
+ from django.db import connection, transaction, models
from django.conf import settings
from django.core.management.sql import table_list, installed_models, sql_model_create, sql_for_pending_references, many_to_many_sql_for_model, custom_sql_for_model, sql_indexes_for_model, emit_post_sync_signal
@@ -34,7 +34,7 @@ def handle_noargs(self, **options):
# Get a list of all existing database tables,
# so we know what needs to be added.
table_list = table_list()
- if backend.uses_case_insensitive_names:
+ if connection.features.uses_case_insensitive_names:
table_name_converter = str.upper
else:
table_name_converter = lambda x: x
@@ -125,6 +125,6 @@ def handle_noargs(self, **options):
else:
transaction.commit_unless_managed()
- # Install the 'initialdata' fixture, using format discovery
+ # Install the 'initial_data' fixture, using format discovery
from django.core.management import call_command
- call_command('loaddata', 'initial_data', **options)
+ call_command('loaddata', 'initial_data', verbosity=verbosity)
View
134 django/core/management/sql.py
@@ -15,12 +15,12 @@ def table_list():
def installed_models(table_list):
"Returns a set of all models that are installed, given a list of existing table names."
- from django.db import backend, models
+ from django.db import connection, models
all_models = []
for app in models.get_apps():
for model in models.get_models(app):
all_models.append(model)
- if backend.uses_case_insensitive_names:
+ if connection.features.uses_case_insensitive_names:
converter = lambda x: x.upper()
else:
converter = lambda x: x
@@ -95,7 +95,7 @@ def sql_create(app, style):
def sql_delete(app, style):
"Returns a list of the DROP TABLE SQL statements for the given app."
- from django.db import backend, connection, models, get_introspection_module
+ from django.db import connection, models, get_introspection_module
from django.db.backends.util import truncate_name
introspection = get_introspection_module()
@@ -110,12 +110,13 @@ def sql_delete(app, style):
table_names = introspection.get_table_list(cursor)
else:
table_names = []
- if backend.uses_case_insensitive_names:
+ if connection.features.uses_case_insensitive_names:
table_name_converter = str.upper
else:
table_name_converter = lambda x: x
output = []
+ qn = connection.ops.quote_name
# Output DROP TABLE statements for standard application tables.
to_delete = set()
@@ -136,8 +137,8 @@ def sql_delete(app, style):
if cursor and table_name_converter(model._meta.db_table) in table_names:
# Drop the table now
output.append('%s %s;' % (style.SQL_KEYWORD('DROP TABLE'),
- style.SQL_TABLE(backend.quote_name(model._meta.db_table))))
- if backend.supports_constraints and model in references_to_delete:
+ style.SQL_TABLE(qn(model._meta.db_table))))
+ if connection.features.supports_constraints and model in references_to_delete:
for rel_class, f in references_to_delete[model]:
table = rel_class._meta.db_table
col = f.column
@@ -146,12 +147,14 @@ def sql_delete(app, style):
r_name = '%s_refs_%s_%x' % (col, r_col, abs(hash((table, r_table))))
output.append('%s %s %s %s;' % \
(style.SQL_KEYWORD('ALTER TABLE'),
- style.SQL_TABLE(backend.quote_name(table)),
- style.SQL_KEYWORD(backend.get_drop_foreignkey_sql()),
- style.SQL_FIELD(truncate_name(r_name, backend.get_max_name_length()))))
+ style.SQL_TABLE(qn(table)),
+ style.SQL_KEYWORD(connection.ops.drop_foreignkey_sql()),
+ style.SQL_FIELD(truncate_name(r_name, connection.ops.max_name_length()))))
del references_to_delete[model]
- if model._meta.has_auto_field and hasattr(backend, 'get_drop_sequence'):
- output.append(backend.get_drop_sequence(model._meta.db_table))
+ if model._meta.has_auto_field:
+ ds = connection.ops.drop_sequence_sql(model._meta.db_table)
+ if ds:
+ output.append(ds)
# Output DROP TABLE statements for many-to-many tables.
for model in app_models:
@@ -159,9 +162,10 @@ def sql_delete(app, style):
for f in opts.many_to_many:
if cursor and table_name_converter(f.m2m_db_table()) in table_names:
output.append("%s %s;" % (style.SQL_KEYWORD('DROP TABLE'),
- style.SQL_TABLE(backend.quote_name(f.m2m_db_table()))))
- if hasattr(backend, 'get_drop_sequence'):
- output.append(backend.get_drop_sequence("%s_%s" % (model._meta.db_table, f.column)))
+ style.SQL_TABLE(qn(f.m2m_db_table()))))
+ ds = connection.ops.drop_sequence_sql("%s_%s" % (model._meta.db_table, f.column))
+ if ds:
+ output.append(ds)
app_label = app_models[0]._meta.app_label
@@ -178,9 +182,9 @@ def sql_reset(app, style):
return sql_delete(app, style) + sql_all(app, style)
def sql_flush(style):
- "Returns a list of the SQL statements used to flush the database"
- from django.db import backend
- statements = backend.get_sql_flush(style, table_list(), sequence_list())
+ "Returns a list of the SQL statements used to flush the database."
+ from django.db import connection
+ statements = connection.ops.sql_flush(style, table_list(), sequence_list())
return statements
def sql_custom(app):
@@ -213,12 +217,13 @@ def sql_model_create(model, style, known_models=set()):
Returns the SQL required to create a single model, as a tuple of:
(list_of_sql, pending_references_dict)
"""
- from django.db import backend, models
+ from django.db import connection, models
opts = model._meta
final_output = []
table_output = []
pending_references = {}
+ qn = connection.ops.quote_name
for f in opts.fields:
col_type = f.db_type()
tablespace = f.db_tablespace or opts.db_tablespace
@@ -227,23 +232,23 @@ def sql_model_create(model, style, known_models=set()):
# database columns in this table.
continue
# Make the definition (e.g. 'foo VARCHAR(30)') for this field.
- field_output = [style.SQL_FIELD(backend.quote_name(f.column)),
+ field_output = [style.SQL_FIELD(qn(f.column)),
style.SQL_COLTYPE(col_type)]
field_output.append(style.SQL_KEYWORD('%sNULL' % (not f.null and 'NOT ' or '')))
- if f.unique and (not f.primary_key or backend.allows_unique_and_pk):
+ if f.unique and (not f.primary_key or connection.features.allows_unique_and_pk):
field_output.append(style.SQL_KEYWORD('UNIQUE'))
if f.primary_key:
field_output.append(style.SQL_KEYWORD('PRIMARY KEY'))
- if tablespace and backend.supports_tablespaces and (f.unique or f.primary_key) and backend.autoindexes_primary_keys:
+ if tablespace and connection.features.supports_tablespaces and (f.unique or f.primary_key) and connection.features.autoindexes_primary_keys:
# We must specify the index tablespace inline, because we
# won't be generating a CREATE INDEX statement for this field.
- field_output.append(backend.get_tablespace_sql(tablespace, inline=True))
+ field_output.append(connection.ops.tablespace_sql(tablespace, inline=True))
if f.rel:
if f.rel.to in known_models:
field_output.append(style.SQL_KEYWORD('REFERENCES') + ' ' + \
- style.SQL_TABLE(backend.quote_name(f.rel.to._meta.db_table)) + ' (' + \
- style.SQL_FIELD(backend.quote_name(f.rel.to._meta.get_field(f.rel.field_name).column)) + ')' +
- backend.get_deferrable_sql()
+ style.SQL_TABLE(qn(f.rel.to._meta.db_table)) + ' (' + \
+ style.SQL_FIELD(qn(f.rel.to._meta.get_field(f.rel.field_name).column)) + ')' +
+ connection.ops.deferrable_sql()
)
else:
# We haven't yet created the table to which this field
@@ -251,25 +256,25 @@ def sql_model_create(model, style, known_models=set()):
pr = pending_references.setdefault(f.rel.to, []).append((model, f))
table_output.append(' '.join(field_output))
if opts.order_with_respect_to:
- table_output.append(style.SQL_FIELD(backend.quote_name('_order')) + ' ' + \
+ table_output.append(style.SQL_FIELD(qn('_order')) + ' ' + \
style.SQL_COLTYPE(models.IntegerField().db_type()) + ' ' + \
style.SQL_KEYWORD('NULL'))
for field_constraints in opts.unique_together:
table_output.append(style.SQL_KEYWORD('UNIQUE') + ' (%s)' % \
- ", ".join([backend.quote_name(style.SQL_FIELD(opts.get_field(f).column)) for f in field_constraints]))
+ ", ".join([qn(style.SQL_FIELD(opts.get_field(f).column)) for f in field_constraints]))
- full_statement = [style.SQL_KEYWORD('CREATE TABLE') + ' ' + style.SQL_TABLE(backend.quote_name(opts.db_table)) + ' (']
+ full_statement = [style.SQL_KEYWORD('CREATE TABLE') + ' ' + style.SQL_TABLE(qn(opts.db_table)) + ' (']
for i, line in enumerate(table_output): # Combine and add commas.
full_statement.append(' %s%s' % (line, i < len(table_output)-1 and ',' or ''))
full_statement.append(')')
- if opts.db_tablespace and backend.supports_tablespaces:
- full_statement.append(backend.get_tablespace_sql(opts.db_tablespace))
+ if opts.db_tablespace and connection.features.supports_tablespaces:
+ full_statement.append(connection.ops.tablespace_sql(opts.db_tablespace))
full_statement.append(';')
final_output.append('\n'.join(full_statement))
- if opts.has_auto_field and hasattr(backend, 'get_autoinc_sql'):
- # Add any extra SQL needed to support auto-incrementing primary keys
- autoinc_sql = backend.get_autoinc_sql(opts.db_table)
+ if opts.has_auto_field:
+ # Add any extra SQL needed to support auto-incrementing primary keys.
+ autoinc_sql = connection.ops.autoinc_sql(opts.db_table)
if autoinc_sql:
for stmt in autoinc_sql:
final_output.append(stmt)
@@ -280,11 +285,12 @@ def sql_for_pending_references(model, style, pending_references):
"""
Returns any ALTER TABLE statements to add constraints after the fact.
"""
- from django.db import backend
+ from django.db import connection
from django.db.backends.util import truncate_name
+ qn = connection.ops.quote_name
final_output = []
- if backend.supports_constraints:
+ if connection.features.supports_constraints:
opts = model._meta
if model in pending_references:
for rel_class, f in pending_references[model]:
@@ -297,60 +303,61 @@ def sql_for_pending_references(model, style, pending_references):
# So we are careful with character usage here.
r_name = '%s_refs_%s_%x' % (r_col, col, abs(hash((r_table, table))))
final_output.append(style.SQL_KEYWORD('ALTER TABLE') + ' %s ADD CONSTRAINT %s FOREIGN KEY (%s) REFERENCES %s (%s)%s;' % \
- (backend.quote_name(r_table), truncate_name(r_name, backend.get_max_name_length()),
- backend.quote_name(r_col), backend.quote_name(table), backend.quote_name(col),
- backend.get_deferrable_sql()))
+ (qn(r_table), truncate_name(r_name, connection.ops.max_name_length()),
+ qn(r_col), qn(table), qn(col),
+ connection.ops.deferrable_sql()))
del pending_references[model]
return final_output
def many_to_many_sql_for_model(model, style):
- from django.db import backend, models
+ from django.db import connection, models
from django.contrib.contenttypes import generic
opts = model._meta
final_output = []
+ qn = connection.ops.quote_name
for f in opts.many_to_many:
if not isinstance(f.rel, generic.GenericRel):
tablespace = f.db_tablespace or opts.db_tablespace
- if tablespace and backend.supports_tablespaces and backend.autoindexes_primary_keys:
- tablespace_sql = ' ' + backend.get_tablespace_sql(tablespace, inline=True)
+ if tablespace and connection.features.supports_tablespaces and connection.features.autoindexes_primary_keys:
+ tablespace_sql = ' ' + connection.ops.tablespace_sql(tablespace, inline=True)
else:
tablespace_sql = ''
table_output = [style.SQL_KEYWORD('CREATE TABLE') + ' ' + \
- style.SQL_TABLE(backend.quote_name(f.m2m_db_table())) + ' (']
+ style.SQL_TABLE(qn(f.m2m_db_table())) + ' (']
table_output.append(' %s %s %s%s,' % \
- (style.SQL_FIELD(backend.quote_name('id')),
+ (style.SQL_FIELD(qn('id')),
style.SQL_COLTYPE(models.AutoField(primary_key=True).db_type()),
style.SQL_KEYWORD('NOT NULL PRIMARY KEY'),
tablespace_sql))
table_output.append(' %s %s %s %s (%s)%s,' % \
- (style.SQL_FIELD(backend.quote_name(f.m2m_column_name())),
+ (style.SQL_FIELD(qn(f.m2m_column_name())),
style.SQL_COLTYPE(models.ForeignKey(model).db_type()),
style.SQL_KEYWORD('NOT NULL REFERENCES'),
- style.SQL_TABLE(backend.quote_name(opts.db_table)),
- style.SQL_FIELD(backend.quote_name(opts.pk.column)),
- backend.get_deferrable_sql()))
+ style.SQL_TABLE(qn(opts.db_table)),
+ style.SQL_FIELD(qn(opts.pk.column)),
+ connection.ops.deferrable_sql()))
table_output.append(' %s %s %s %s (%s)%s,' % \
- (style.SQL_FIELD(backend.quote_name(f.m2m_reverse_name())),
+ (style.SQL_FIELD(qn(f.m2m_reverse_name())),
style.SQL_COLTYPE(models.ForeignKey(f.rel.to).db_type()),
style.SQL_KEYWORD('NOT NULL REFERENCES'),
- style.SQL_TABLE(backend.quote_name(f.rel.to._meta.db_table)),
- style.SQL_FIELD(backend.quote_name(f.rel.to._meta.pk.column)),
- backend.get_deferrable_sql()))
+ style.SQL_TABLE(qn(f.rel.to._meta.db_table)),
+ style.SQL_FIELD(qn(f.rel.to._meta.pk.column)),
+ connection.ops.deferrable_sql()))
table_output.append(' %s (%s, %s)%s' % \
(style.SQL_KEYWORD('UNIQUE'),
- style.SQL_FIELD(backend.quote_name(f.m2m_column_name())),
- style.SQL_FIELD(backend.quote_name(f.m2m_reverse_name())),
+ style.SQL_FIELD(qn(f.m2m_column_name())),
+ style.SQL_FIELD(qn(f.m2m_reverse_name())),
tablespace_sql))
table_output.append(')')
- if opts.db_tablespace and backend.supports_tablespaces:
+ if opts.db_tablespace and connection.features.supports_tablespaces:
# f.db_tablespace is only for indices, so ignore its value here.
- table_output.append(backend.get_tablespace_sql(opts.db_tablespace))
+ table_output.append(connection.ops.tablespace_sql(opts.db_tablespace))
table_output.append(';')
final_output.append('\n'.join(table_output))
# Add any extra SQL needed to support auto-incrementing PKs
- autoinc_sql = backend.get_autoinc_sql(f.m2m_db_table())
+ autoinc_sql = connection.ops.autoinc_sql(f.m2m_db_table())
if autoinc_sql:
for stmt in autoinc_sql:
final_output.append(stmt)
@@ -386,23 +393,24 @@ def custom_sql_for_model(model):
def sql_indexes_for_model(model, style):
"Returns the CREATE INDEX SQL statements for a single model"
- from django.db import backend
+ from django.db import connection
output = []
+ qn = connection.ops.quote_name
for f in model._meta.fields:
- if f.db_index and not ((f.primary_key or f.unique) and backend.autoindexes_primary_keys):
+ if f.db_index and not ((f.primary_key or f.unique) and connection.features.autoindexes_primary_keys):
unique = f.unique and 'UNIQUE ' or ''
tablespace = f.db_tablespace or model._meta.db_tablespace
- if tablespace and backend.supports_tablespaces:
- tablespace_sql = ' ' + backend.get_tablespace_sql(tablespace)
+ if tablespace and connection.features.supports_tablespaces:
+ tablespace_sql = ' ' + connection.ops.tablespace_sql(tablespace)
else:
tablespace_sql = ''
output.append(
style.SQL_KEYWORD('CREATE %sINDEX' % unique) + ' ' + \
- style.SQL_TABLE(backend.quote_name('%s_%s' % (model._meta.db_table, f.column))) + ' ' + \
+ style.SQL_TABLE(qn('%s_%s' % (model._meta.db_table, f.column))) + ' ' + \
style.SQL_KEYWORD('ON') + ' ' + \
- style.SQL_TABLE(backend.quote_name(model._meta.db_table)) + ' ' + \
- "(%s)" % style.SQL_FIELD(backend.quote_name(f.column)) + \
+ style.SQL_TABLE(qn(model._meta.db_table)) + ' ' + \
+ "(%s)" % style.SQL_FIELD(qn(f.column)) + \
"%s;" % tablespace_sql
)
return output
View
218 django/db/backends/__init__.py
@@ -0,0 +1,218 @@
+try:
+ # Only exists in Python 2.4+
+ from threading import local
+except ImportError:
+ # Import copy of _thread_local.py from Python 2.4
+ from django.utils._threading_local import local
+
+class BaseDatabaseWrapper(local):
+ """
+ Represents a database connection.
+ """
+ ops = None
+ def __init__(self, **kwargs):
+ self.connection = None
+ self.queries = []
+ self.options = kwargs
+
+ def _commit(self):
+ if self.connection is not None:
+ return self.connection.commit()
+
+ def _rollback(self):
+ if self.connection is not None:
+ return self.connection.rollback()
+
+ def close(self):
+ if self.connection is not None:
+ self.connection.close()
+ self.connection = None
+
+ def cursor(self):
+ from django.conf import settings
+ cursor = self._cursor(settings)
+ if settings.DEBUG:
+ return self.make_debug_cursor(cursor)
+ return cursor
+
+ def make_debug_cursor(self, cursor):
+ from django.db.backends import util
+ return util.CursorDebugWrapper(cursor, self)
+
+class BaseDatabaseFeatures(object):
+ allows_group_by_ordinal = True
+ allows_unique_and_pk = True
+ autoindexes_primary_keys = True
+ needs_datetime_string_cast = True
+ needs_upper_for_iops = False
+ supports_constraints = True
+ supports_tablespaces = False
+ uses_case_insensitive_names = False
+ uses_custom_queryset = False
+
+class BaseDatabaseOperations(object):
+ """
+ This class encapsulates all backend-specific differences, such as the way
+ a backend performs ordering or calculates the ID of a recently-inserted
+ row.
+ """
+ def autoinc_sql(self, table):
+ """
+ Returns any SQL needed to support auto-incrementing primary keys, or
+ None if no SQL is necessary.
+
+ This SQL is executed when a table is created.
+ """
+ return None
+
+ def date_extract_sql(self, lookup_type, field_name):
+ """
+ Given a lookup_type of 'year', 'month' or 'day', returns the SQL that
+ extracts a value from the given date field field_name.
+ """
+ raise NotImplementedError()
+
+ def date_trunc_sql(self, lookup_type, field_name):
+ """
+ Given a lookup_type of 'year', 'month' or 'day', returns the SQL that
+ truncates the given date field field_name to a DATE object with only
+ the given specificity.
+ """
+ raise NotImplementedError()
+
+ def datetime_cast_sql(self):
+ """
+ Returns the SQL necessary to cast a datetime value so that it will be
+ retrieved as a Python datetime object instead of a string.
+
+ This SQL should include a '%s' in place of the field's name. This
+ method should return None if no casting is necessary.
+ """
+ return None
+
+ def deferrable_sql(self):
+ """
+ Returns the SQL necessary to make a constraint "initially deferred"
+ during a CREATE TABLE statement.
+ """
+ return ''
+
+ def drop_foreignkey_sql(self):
+ """
+ Returns the SQL command that drops a foreign key.
+ """
+ return "DROP CONSTRAINT"
+
+ def drop_sequence_sql(self, table):
+ """
+ Returns any SQL necessary to drop the sequence for the given table.
+ Returns None if no SQL is necessary.
+ """
+ return None
+
+ def field_cast_sql(self, db_type):
+ """
+ Given a column type (e.g. 'BLOB', 'VARCHAR'), returns the SQL necessary
+ to cast it before using it in a WHERE statement. Note that the
+ resulting string should contain a '%s' placeholder for the column being
+ searched against.
+ """
+ return '%s'
+
+ def fulltext_search_sql(self, field_name):
+ """
+ Returns the SQL WHERE clause to use in order to perform a full-text
+ search of the given field_name. Note that the resulting string should
+ contain a '%s' placeholder for the value being searched against.
+ """
+ raise NotImplementedError('Full-text search is not implemented for this database backend')
+
+ def last_insert_id(self, cursor, table_name, pk_name):
+ """
+ Given a cursor object that has just performed an INSERT statement into
+ a table that has an auto-incrementing ID, returns the newly created ID.
+
+ This method also receives the table name and the name of the primary-key
+ column.
+ """
+ return cursor.lastrowid
+
+ def limit_offset_sql(self, limit, offset=None):
+ """
+ Returns a LIMIT/OFFSET SQL clause, given a limit and optional offset.
+ """
+ # 'LIMIT 40 OFFSET 20'
+ sql = "LIMIT %s" % limit
+ if offset and offset != 0:
+ sql += " OFFSET %s" % offset
+ return sql
+
+ def max_name_length(self):
+ """
+ Returns the maximum length of table and column names, or None if there
+ is no limit.
+ """
+ return None
+
+ def pk_default_value(self):
+ """
+ Returns the value to use during an INSERT statement to specify that
+ the field should use its default value.
+ """
+ return 'DEFAULT'
+
+ def query_set_class(self, DefaultQuerySet):
+ """
+ Given the default QuerySet class, returns a custom QuerySet class
+ to use for this backend. Returns None if a custom QuerySet isn't used.
+ See also BaseDatabaseFeatures.uses_custom_queryset, which regulates
+ whether this method is called at all.
+ """
+ return None
+
+ def quote_name(self, name):
+ """
+ Returns a quoted version of the given table, index or column name. Does
+ not quote the given name if it's already been quoted.
+ """
+ raise NotImplementedError()
+
+ def random_function_sql(self):
+ """
+ Returns a SQL expression that returns a random value.
+ """
+ return 'RANDOM()'
+
+ def sql_flush(self, style, tables, sequences):
+ """
+ Returns a list of SQL statements required to remove all data from
+ the given database tables (without actually removing the tables
+ themselves).
+
+ The `style` argument is a Style object as returned by either
+ color_style() or no_style() in django.core.management.color.
+ """
+ raise NotImplementedError()
+
+ def sequence_reset_sql(self, style, model_list):
+ """
+ Returns a list of the SQL statements required to reset sequences for
+ the given models.
+
+ The `style` argument is a Style object as returned by either
+ color_style() or no_style() in django.core.management.color.
+ """
+ return [] # No sequence reset required by default.
+
+ def start_transaction_sql(self):
+ """
+ Returns the SQL statement required to start a transaction.
+ """
+ return "BEGIN;"
+
+ def tablespace_sql(self, tablespace, inline=False):
+ """
+ Returns the tablespace SQL, or None if the backend doesn't use
+ tablespaces.
+ """
+ return None
View
195 django/db/backends/ado_mssql/base.py
@@ -4,12 +4,12 @@
Requires adodbapi 2.0.1: http://adodbapi.sourceforge.net/
"""
-from django.db.backends import util
+from django.db.backends import BaseDatabaseWrapper, BaseDatabaseFeatures, BaseDatabaseOperations, util
try:
import adodbapi as Database
except ImportError, e:
from django.core.exceptions import ImproperlyConfigured
- raise ImproperlyConfigured, "Error loading adodbapi module: %s" % e
+ raise ImproperlyConfigured("Error loading adodbapi module: %s" % e)
import datetime
try:
import mx
@@ -48,148 +48,65 @@ def variantToPython(variant, adType):
return res
Database.convertVariantToPython = variantToPython
-try:
- # Only exists in Python 2.4+
- from threading import local
-except ImportError:
- # Import copy of _thread_local.py from Python 2.4
- from django.utils._threading_local import local
-
-class DatabaseWrapper(local):
- def __init__(self, **kwargs):
- self.connection = None
- self.queries = []
-
- def cursor(self):
- from django.conf import settings
+class DatabaseFeatures(BaseDatabaseFeatures):
+ supports_tablespaces = True
+
+class DatabaseOperations(BaseDatabaseOperations):
+ def date_extract_sql(self, lookup_type, field_name):
+ return "DATEPART(%s, %s)" % (lookup_type, field_name)
+
+ def date_trunc_sql(self, lookup_type, field_name):
+ if lookup_type == 'year':
+ return "Convert(datetime, Convert(varchar, DATEPART(year, %s)) + '/01/01')" % field_name
+ if lookup_type == 'month':
+ return "Convert(datetime, Convert(varchar, DATEPART(year, %s)) + '/' + Convert(varchar, DATEPART(month, %s)) + '/01')" % (field_name, field_name)
+ if lookup_type == 'day':
+ return "Convert(datetime, Convert(varchar(12), %s))" % field_name
+
+ def deferrable_sql(self):
+ return " DEFERRABLE INITIALLY DEFERRED"
+
+ def last_insert_id(self, cursor, table_name, pk_name):
+ cursor.execute("SELECT %s FROM %s WHERE %s = @@IDENTITY" % (pk_name, table_name, pk_name))
+ return cursor.fetchone()[0]
+
+ def quote_name(self, name):
+ if name.startswith('[') and name.endswith(']'):
+ return name # Quoting once is enough.
+ return '[%s]' % name
+
+ def random_function_sql(self):
+ return 'RAND()'
+
+ def tablespace_sql(self, tablespace, inline=False):
+ return "ON %s" % self.quote_name(tablespace)
+
+class DatabaseWrapper(BaseDatabaseWrapper):
+ features = DatabaseFeatures()
+ ops = DatabaseOperations()
+ operators = {
+ 'exact': '= %s',
+ 'iexact': 'LIKE %s',
+ 'contains': 'LIKE %s',
+ 'icontains': 'LIKE %s',
+ 'gt': '> %s',
+ 'gte': '>= %s',
+ 'lt': '< %s',
+ 'lte': '<= %s',
+ 'startswith': 'LIKE %s',
+ 'endswith': 'LIKE %s',
+ 'istartswith': 'LIKE %s',
+ 'iendswith': 'LIKE %s',
+ }
+
+ def _cursor(self, settings):
if self.connection is None:
if settings.DATABASE_NAME == '' or settings.DATABASE_USER == '':
from django.core.exceptions import ImproperlyConfigured
- raise ImproperlyConfigured, "You need to specify both DATABASE_NAME and DATABASE_USER in your Django settings file."
+ raise ImproperlyConfigured("You need to specify both DATABASE_NAME and DATABASE_USER in your Django settings file.")
if not settings.DATABASE_HOST:
settings.DATABASE_HOST = "127.0.0.1"
# TODO: Handle DATABASE_PORT.
conn_string = "PROVIDER=SQLOLEDB;DATA SOURCE=%s;UID=%s;PWD=%s;DATABASE=%s" % (settings.DATABASE_HOST, settings.DATABASE_USER, settings.DATABASE_PASSWORD, settings.DATABASE_NAME)
self.connection = Database.connect(conn_string)
- cursor = self.connection.cursor()
- if settings.DEBUG:
- return util.CursorDebugWrapper(cursor, self)
- return cursor
-
- def _commit(self):
- if self.connection is not None:
- return self.connection.commit()
-
- def _rollback(self):
- if self.connection is not None:
- return self.connection.rollback()
-
- def close(self):
- if self.connection is not None:
- self.connection.close()
- self.connection = None
-
-allows_group_by_ordinal = True
-allows_unique_and_pk = True
-autoindexes_primary_keys = True
-needs_datetime_string_cast = True
-needs_upper_for_iops = False
-supports_constraints = True
-supports_tablespaces = True
-uses_case_insensitive_names = False
-
-def quote_name(name):
- if name.startswith('[') and name.endswith(']'):
- return name # Quoting once is enough.
- return '[%s]' % name
-
-dictfetchone = util.dictfetchone
-dictfetchmany = util.dictfetchmany
-dictfetchall = util.dictfetchall
-
-def get_last_insert_id(cursor, table_name, pk_name):
- cursor.execute("SELECT %s FROM %s WHERE %s = @@IDENTITY" % (pk_name, table_name, pk_name))
- return cursor.fetchone()[0]
-
-def get_date_extract_sql(lookup_type, table_name):
- # lookup_type is 'year', 'month', 'day'
- return "DATEPART(%s, %s)" % (lookup_type, table_name)
-
-def get_date_trunc_sql(lookup_type, field_name):
- # lookup_type is 'year', 'month', 'day'
- if lookup_type=='year':
- return "Convert(datetime, Convert(varchar, DATEPART(year, %s)) + '/01/01')" % field_name
- if lookup_type=='month':
- return "Convert(datetime, Convert(varchar, DATEPART(year, %s)) + '/' + Convert(varchar, DATEPART(month, %s)) + '/01')" % (field_name, field_name)
- if lookup_type=='day':
- return "Convert(datetime, Convert(varchar(12), %s))" % field_name
-
-def get_datetime_cast_sql():
- return None
-
-def get_limit_offset_sql(limit, offset=None):
- # TODO: This is a guess. Make sure this is correct.
- sql = "LIMIT %s" % limit
- if offset and offset != 0:
- sql += " OFFSET %s" % offset
- return sql
-
-def get_random_function_sql():
- return "RAND()"
-
-def get_deferrable_sql():
- return " DEFERRABLE INITIALLY DEFERRED"
-
-def get_fulltext_search_sql(field_name):
- raise NotImplementedError
-
-def get_drop_foreignkey_sql():
- return "DROP CONSTRAINT"
-
-def get_pk_default_value():
- return "DEFAULT"
-
-def get_max_name_length():
- return None
-
-def get_start_transaction_sql():
- return "BEGIN;"
-
-def get_tablespace_sql(tablespace, inline=False):
- return "ON %s" % quote_name(tablespace)
-
-def get_autoinc_sql(table):
- return None
-
-def get_sql_flush(style, tables, sequences):
- """Return a list of SQL statements required to remove all data from
- all tables in the database (without actually removing the tables
- themselves) and put the database in an empty 'initial' state
- """
- # Return a list of 'TRUNCATE x;', 'TRUNCATE y;', 'TRUNCATE z;'... style SQL statements
- # TODO - SQL not actually tested against ADO MSSQL yet!
- # TODO - autoincrement indices reset required? See other get_sql_flush() implementations
- sql_list = ['%s %s;' % \
- (style.SQL_KEYWORD('TRUNCATE'),
- style.SQL_FIELD(quote_name(table))
- ) for table in tables]
-
-def get_sql_sequence_reset(style, model_list):
- "Returns a list of the SQL statements to reset sequences for the given models."
- # No sequence reset required
- return []
-
-OPERATOR_MAPPING = {
- 'exact': '= %s',
- 'iexact': 'LIKE %s',
- 'contains': 'LIKE %s',
- 'icontains': 'LIKE %s',
- 'gt': '> %s',
- 'gte': '>= %s',
- 'lt': '< %s',
- 'lte': '<= %s',
- 'startswith': 'LIKE %s',
- 'endswith': 'LIKE %s',
- 'istartswith': 'LIKE %s',
- 'iendswith': 'LIKE %s',
-}
+ return self.connection.cursor()
View
35 django/db/backends/dummy/base.py
@@ -21,7 +21,14 @@ class DatabaseError(Exception):
class IntegrityError(DatabaseError):
pass
-class DatabaseWrapper:
+class ComplainOnGetattr(object):
+ def __getattr__(self, *args, **kwargs):
+ complain()
+
+class DatabaseWrapper(object):
+ features = ComplainOnGetattr()
+ ops = ComplainOnGetattr()
+ operators = {}
cursor = complain
_commit = complain
_rollback = ignore
@@ -30,28 +37,4 @@ def __init__(self, **kwargs):
pass
def close(self):
- pass # close()
-
-supports_constraints = False
-supports_tablespaces = False
-quote_name = complain
-dictfetchone = complain
-dictfetchmany = complain
-dictfetchall = complain
-get_last_insert_id = complain
-get_date_extract_sql = complain
-get_date_trunc_sql = complain
-get_datetime_cast_sql = complain
-get_limit_offset_sql = complain
-get_random_function_sql = complain
-get_deferrable_sql = complain
-get_fulltext_search_sql = complain
-get_drop_foreignkey_sql = complain
-get_pk_default_value = complain
-get_max_name_length = ignore
-get_start_transaction_sql = complain
-get_autoinc_sql = complain
-get_sql_flush = complain
-get_sql_sequence_reset = complain
-
-OPERATOR_MAPPING = {}
+ pass
View
252 django/db/backends/mysql/base.py
@@ -4,12 +4,12 @@
Requires MySQLdb: http://sourceforge.net/projects/mysql-python
"""
-from django.db.backends import util
+from django.db.backends import BaseDatabaseWrapper, BaseDatabaseFeatures, BaseDatabaseOperations, util
try:
import MySQLdb as Database
except ImportError, e:
from django.core.exceptions import ImproperlyConfigured
- raise ImproperlyConfigured, "Error loading MySQLdb module: %s" % e
+ raise ImproperlyConfigured("Error loading MySQLdb module: %s" % e)
# We want version (1, 2, 1, 'final', 2) or later. We can't just use
# lexicographic ordering in this check because then (1, 2, 1, 'gamma')
@@ -17,7 +17,7 @@
version = Database.version_info
if (version < (1,2,1) or (version[:3] == (1, 2, 1) and
(len(version) < 5 or version[3] != 'final' or version[4] < 2))):
- raise ImportError, "MySQLdb-1.2.1p2 or newer is required; you have %s" % Database.__version__
+ raise ImportError("MySQLdb-1.2.1p2 or newer is required; you have %s" % Database.__version__)
from MySQLdb.converters import conversions
from MySQLdb.constants import FIELD_TYPE
@@ -53,19 +53,94 @@
# standard util.CursorDebugWrapper can be used. Also, using sql_mode
# TRADITIONAL will automatically cause most warnings to be treated as errors.
-try:
- # Only exists in Python 2.4+
- from threading import local
-except ImportError:
- # Import copy of _thread_local.py from Python 2.4
- from django.utils._threading_local import local
+class DatabaseFeatures(BaseDatabaseFeatures):
+ autoindexes_primary_keys = False
+
+class DatabaseOperations(BaseDatabaseOperations):
+ def date_extract_sql(self, lookup_type, field_name):
+ # http://dev.mysql.com/doc/mysql/en/date-and-time-functions.html
+ return "EXTRACT(%s FROM %s)" % (lookup_type.upper(), field_name)
+
+ def date_trunc_sql(self, lookup_type, field_name):
+ fields = ['year', 'month', 'day', 'hour', 'minute', 'second']
+ format = ('%%Y-', '%%m', '-%%d', ' %%H:', '%%i', ':%%s') # Use double percents to escape.
+ format_def = ('0000-', '01', '-01', ' 00:', '00', ':00')
+ try:
+ i = fields.index(lookup_type) + 1
+ except ValueError:
+ sql = field_name
+ else:
+ format_str = ''.join([f for f in format[:i]] + [f for f in format_def[i:]])
+ sql = "CAST(DATE_FORMAT(%s, '%s') AS DATETIME)" % (field_name, format_str)
+ return sql
+
+ def drop_foreignkey_sql(self):
+ return "DROP FOREIGN KEY"
+
+ def fulltext_search_sql(self, field_name):
+ return 'MATCH (%s) AGAINST (%%s IN BOOLEAN MODE)' % field_name
+
+ def limit_offset_sql(self, limit, offset=None):
+ # 'LIMIT 20,40'
+ sql = "LIMIT "
+ if offset and offset != 0:
+ sql += "%s," % offset
+ return sql + str(limit)
+
+ def quote_name(self, name):
+ if name.startswith("`") and name.endswith("`"):
+ return name # Quoting once is enough.
+ return "`%s`" % name
+
+ def random_function_sql(self):
+ return 'RAND()'
+
+ def sql_flush(self, style, tables, sequences):
+ # NB: The generated SQL below is specific to MySQL
+ # 'TRUNCATE x;', 'TRUNCATE y;', 'TRUNCATE z;'... style SQL statements
+ # to clear all tables of all data
+ if tables:
+ sql = ['SET FOREIGN_KEY_CHECKS = 0;']
+ for table in tables:
+ sql.append('%s %s;' % (style.SQL_KEYWORD('TRUNCATE'), style.SQL_FIELD(self.quote_name(table))))
+ sql.append('SET FOREIGN_KEY_CHECKS = 1;')
+
+ # 'ALTER TABLE table AUTO_INCREMENT = 1;'... style SQL statements
+ # to reset sequence indices
+ sql.extend(["%s %s %s %s %s;" % \
+ (style.SQL_KEYWORD('ALTER'),
+ style.SQL_KEYWORD('TABLE'),
+ style.SQL_TABLE(self.quote_name(sequence['table'])),
+ style.SQL_KEYWORD('AUTO_INCREMENT'),
+ style.SQL_FIELD('= 1'),
+ ) for sequence in sequences])
+ return sql
+ else:
+ return []
+
+class DatabaseWrapper(BaseDatabaseWrapper):
+ features = DatabaseFeatures()
+ ops = DatabaseOperations()
+ operators = {
+ 'exact': '= %s',
+ 'iexact': 'LIKE %s',
+ 'contains': 'LIKE BINARY %s',
+ 'icontains': 'LIKE %s',
+ 'regex': 'REGEXP BINARY %s',
+ 'iregex': 'REGEXP %s',
+ 'gt': '> %s',
+ 'gte': '>= %s',
+ 'lt': '< %s',
+ 'lte': '<= %s',
+ 'startswith': 'LIKE BINARY %s',
+ 'endswith': 'LIKE BINARY %s',
+ 'istartswith': 'LIKE %s',
+ 'iendswith': 'LIKE %s',
+ }
-class DatabaseWrapper(local):
def __init__(self, **kwargs):
- self.connection = None
- self.queries = []
+ super(DatabaseWrapper, self).__init__(**kwargs)
self.server_version = None
- self.options = kwargs