1
0
mirror of https://github.com/django/django.git synced 2025-07-05 18:29:11 +00:00

[soc2009/multidb] Added a using option to a Model's Meta class. This allows you to select the default database for a specific model, in addition to the global default

git-svn-id: http://code.djangoproject.com/svn/django/branches/soc2009/multidb@11135 bcc190cf-cafb-0310-a4f2-bffc1f526a37
This commit is contained in:
Alex Gaynor 2009-07-01 05:01:59 +00:00
parent 04e3fc8de2
commit 5d462b9ec1
8 changed files with 65 additions and 14 deletions

View File

@ -26,7 +26,4 @@ that need to be done. I'm trying to be as granular as possible.
4) Wait on the merge of the m2m stuff.
5) Add the ``using`` Meta option. Tests and docs(these are to be assumed at
each stage from here on out).
6) Time permitting add support for a ``DatabaseManager``.

View File

@ -419,8 +419,7 @@ class Model(object):
need for overrides of save() to pass around internal-only parameters
('raw', 'cls', and 'origin').
"""
if using is None:
using = DEFAULT_DB_ALIAS
using = using or self._meta.using or DEFAULT_DB_ALIAS
connection = connections[using]
assert not (force_insert and force_update)
if cls is None:
@ -563,8 +562,7 @@ class Model(object):
parent_obj._collect_sub_objects(seen_objs)
def delete(self, using=None):
if using is None:
using = DEFAULT_DB_ALIAS
using = using or self._meta.using or DEFAULT_DB_ALIAS
connection = connections[using]
assert self._get_pk_val() is not None, "%s object can't be deleted because its %s attribute is set to None." % (self._meta.object_name, self._meta.pk.attname)

View File

@ -21,7 +21,7 @@ get_verbose_name = lambda class_name: re.sub('(((?<=[a-z])[A-Z])|([A-Z](?![A-Z]|
DEFAULT_NAMES = ('verbose_name', 'db_table', 'ordering',
'unique_together', 'permissions', 'get_latest_by',
'order_with_respect_to', 'app_label', 'db_tablespace',
'abstract', 'managed', 'proxy')
'abstract', 'managed', 'proxy', 'using')
class Options(object):
def __init__(self, meta, app_label=None):
@ -47,6 +47,7 @@ class Options(object):
self.proxy_for_model = None
self.parents = SortedDict()
self.duplicate_targets = {}
self.using = None
# To handle various inheritance situations, we need to track where
# managers came from (concrete or abstract base classes).
@ -487,4 +488,3 @@ class Options(object):
Returns the index of the primary key field in the self.fields list.
"""
return self.fields.index(self.pk)

View File

@ -33,12 +33,14 @@ class QuerySet(object):
"""
def __init__(self, model=None, query=None):
self.model = model
connection = connections[DEFAULT_DB_ALIAS]
using = model._meta.using or DEFAULT_DB_ALIAS
connection = connections[using]
self.query = query or sql.Query(self.model, connection)
self._result_cache = None
self._iter = None
self._sticky_filter = False
self._using = connections.alias_for_connection(self.query.connection)
self._using = (query and
connections.alias_for_connection(self.query.connection) or using)
########################
# PYTHON MAGIC METHODS #

View File

@ -210,6 +210,17 @@ set of fields::
unique_together = ("driver", "restaurant")
``using``
---------
.. attribute:: Options.using
The alias for the default database to be used for this model. If this is not
provided the default is ``'default'``. If it is porvided it can be overidden
at the ``QuerySet`` level with the ``using()`` method.
.. versionadded:: TODO
``verbose_name``
----------------
@ -232,4 +243,3 @@ The plural name for the object::
verbose_name_plural = "stories"
If this isn't given, Django will use :attr:`~Options.verbose_name` + ``"s"``.

View File

@ -25,6 +25,15 @@ thing to note is that your primary database should have the alias
``'default'``, and any additional databases you have can have whatever alias
you choose.
Selecting a Database for a ``Model``
====================================
In addition to the global default database for all models, it is possible to
select a default database on a per-model level. This is done using the
``using`` option in a model's inner ``Meta`` class. When provided this
database becomes the default database for all lookups, saves, and deletes for
this model. It can be overiden on a per-query basis as described below.
Selecting a Database for a ``QuerySet``
=======================================

View File

@ -1,4 +1,5 @@
from django.db import models
from django.conf import settings
from django.db import models, DEFAULT_DB_ALIAS
class Book(models.Model):
title = models.CharField(max_length=100)
@ -9,3 +10,15 @@ class Book(models.Model):
class Meta:
ordering = ('title',)
if len(settings.DATABASES) > 1:
article_using = filter(lambda o: o != DEFAULT_DB_ALIAS, settings.DATABASES.keys())[0]
class Article(models.Model):
title = models.CharField(max_length=100)
def __unicode__(self):
return self.title
class Meta:
ordering = ('title',)
using = article_using

View File

@ -6,6 +6,13 @@ from django.test import TestCase
from models import Book
try:
# we only have these models if the user is using multi-db, it's safe the
# run the tests without them though.
from models import Article, article_using
except ImportError:
pass
class ConnectionHandlerTestCase(TestCase):
def setUp(self):
settings.DATABASES['__test_db'] = {
@ -71,3 +78,18 @@ class QueryTestCase(TestCase):
months = Book.objects.dates('published', 'month').using(db)
self.assertEqual(sorted(o.month for o in months), [5, 12])
if len(settings.DATABASES) > 1:
class MetaUsingTestCase(TestCase):
def test_meta_using_queries(self):
a = Article.objects.create(title="Django Rules!")
self.assertEqual(Article.objects.get(title="Django Rules!"), a)
for db in connections:
if db == article_using:
self.assertEqual(Article.objects.using(db).get(title="Django Rules!"), a)
else:
self.assertRaises(Article.DoesNotExist,
lambda: Article.objects.using(db).get(title="Django Rules!"))
a.delete()
self.assertRaises(Article.DoesNotExist,
lambda: Article.objects.get(title="Django Rules!"))