mirror of
https://github.com/django/django.git
synced 2025-07-05 02:09:13 +00:00
[multi-db] Added install() and other schema manipulation methods to Manager. Fixed bug in manager assignment for inherited classes (objects and _default_manager in child class were still those belonging to parent class).
git-svn-id: http://code.djangoproject.com/svn/django/branches/multiple-db-support@3266 bcc190cf-cafb-0310-a4f2-bffc1f526a37
This commit is contained in:
parent
54d611d2a2
commit
f194f74aa6
@ -20,7 +20,9 @@ def ensure_default_manager(sender):
|
|||||||
except FieldDoesNotExist:
|
except FieldDoesNotExist:
|
||||||
pass
|
pass
|
||||||
cls.add_to_class('objects', Manager())
|
cls.add_to_class('objects', Manager())
|
||||||
|
elif cls._default_manager.model != cls:
|
||||||
|
# cls is an inherited model; don't want the parent manager
|
||||||
|
cls.add_to_class('objects', Manager())
|
||||||
dispatcher.connect(ensure_default_manager, signal=signals.class_prepared)
|
dispatcher.connect(ensure_default_manager, signal=signals.class_prepared)
|
||||||
|
|
||||||
class Manager(object):
|
class Manager(object):
|
||||||
@ -38,7 +40,9 @@ class Manager(object):
|
|||||||
# TODO: Use weakref because of possible memory leak / circular reference.
|
# TODO: Use weakref because of possible memory leak / circular reference.
|
||||||
self.model = model
|
self.model = model
|
||||||
setattr(model, name, ManagerDescriptor(self))
|
setattr(model, name, ManagerDescriptor(self))
|
||||||
if not hasattr(model, '_default_manager') or self.creation_counter < model._default_manager.creation_counter:
|
if not hasattr(model, '_default_manager') \
|
||||||
|
or self.creation_counter < model._default_manager.creation_counter \
|
||||||
|
or model._default_manager.model != model:
|
||||||
model._default_manager = self
|
model._default_manager = self
|
||||||
|
|
||||||
#######################
|
#######################
|
||||||
@ -102,6 +106,38 @@ class Manager(object):
|
|||||||
def values(self, *args, **kwargs):
|
def values(self, *args, **kwargs):
|
||||||
return self.get_query_set().values(*args, **kwargs)
|
return self.get_query_set().values(*args, **kwargs)
|
||||||
|
|
||||||
|
#######################
|
||||||
|
# SCHEMA MANIPULATION #
|
||||||
|
#######################
|
||||||
|
|
||||||
|
def install(self, initial_data=False):
|
||||||
|
"""Install my model's table, indexes and (if requested) initial data.
|
||||||
|
|
||||||
|
Returns a 2-tuple of the lists of statements executed and
|
||||||
|
statements pending. Pending statements are those that could
|
||||||
|
not yet be executed, such as foreign key constraints for
|
||||||
|
tables that don't exist at install time.
|
||||||
|
"""
|
||||||
|
creator = self.model._meta.connection_info.get_creation_module()
|
||||||
|
run, pending = creator.builder.get_create_table(self.model)
|
||||||
|
run += creator.builder.get_create_indexes(self.model)
|
||||||
|
pending += creator.builder.get_create_many_to_many(self.model)
|
||||||
|
if initial_data:
|
||||||
|
run += creator.builder.get_initialdata(self.model)
|
||||||
|
|
||||||
|
for statement in run:
|
||||||
|
statement.execute()
|
||||||
|
return pending
|
||||||
|
|
||||||
|
def load_initial_data(self):
|
||||||
|
"""Load initial data for my model into the database."""
|
||||||
|
pass # FIXME
|
||||||
|
|
||||||
|
def drop(self):
|
||||||
|
"""Drop my model's table."""
|
||||||
|
pass # FIXME
|
||||||
|
|
||||||
|
|
||||||
class ManagerDescriptor(object):
|
class ManagerDescriptor(object):
|
||||||
# This class ensures managers aren't accessible via model instances.
|
# This class ensures managers aren't accessible via model instances.
|
||||||
# For example, Poll.objects works, but poll_obj.objects raises AttributeError.
|
# For example, Poll.objects works, but poll_obj.objects raises AttributeError.
|
||||||
|
131
tests/othertests/manager_schema_manipulation.py
Normal file
131
tests/othertests/manager_schema_manipulation.py
Normal file
@ -0,0 +1,131 @@
|
|||||||
|
"""
|
||||||
|
# Django uses a model's default manager to perform schema manipulations such as
|
||||||
|
# creating or dropping the model's table.
|
||||||
|
|
||||||
|
>>> from django.db import models
|
||||||
|
|
||||||
|
# default connection
|
||||||
|
>>> class DA(models.Model):
|
||||||
|
... name = models.CharField(maxlength=20)
|
||||||
|
...
|
||||||
|
... def __str__(self):
|
||||||
|
... return self.name
|
||||||
|
|
||||||
|
# connection django_test_db_a
|
||||||
|
>>> class PA(models.Model):
|
||||||
|
... name = models.CharField(maxlength=20)
|
||||||
|
... # This creates a cycle in the dependency graph
|
||||||
|
... c = models.ForeignKey('PC', null=True)
|
||||||
|
...
|
||||||
|
... def __str__(self):
|
||||||
|
... return self.name
|
||||||
|
...
|
||||||
|
... class Meta:
|
||||||
|
... db_connection = 'django_test_db_a'
|
||||||
|
|
||||||
|
>>> class PB(models.Model):
|
||||||
|
... name = models.CharField(maxlength=20)
|
||||||
|
... a = models.ForeignKey(PA)
|
||||||
|
...
|
||||||
|
... def __str__(self):
|
||||||
|
... return self.name
|
||||||
|
...
|
||||||
|
... class Meta:
|
||||||
|
... db_connection = 'django_test_db_a'
|
||||||
|
|
||||||
|
>>> class PC(models.Model):
|
||||||
|
... name = models.CharField(maxlength=20)
|
||||||
|
... b = models.ForeignKey(PB)
|
||||||
|
...
|
||||||
|
... def __str__(self):
|
||||||
|
... return self.name
|
||||||
|
...
|
||||||
|
... class Meta:
|
||||||
|
... db_connection = 'django_test_db_a'
|
||||||
|
|
||||||
|
# connection django_test_db_b
|
||||||
|
>>> class QA(models.Model):
|
||||||
|
... name = models.CharField(maxlength=20)
|
||||||
|
...
|
||||||
|
... def __str__(self):
|
||||||
|
... return self.name
|
||||||
|
...
|
||||||
|
... class Meta:
|
||||||
|
... db_connection = 'django_test_db_b'
|
||||||
|
|
||||||
|
>>> class QB(models.Model):
|
||||||
|
... name = models.CharField(maxlength=20)
|
||||||
|
... a = models.ForeignKey(QA)
|
||||||
|
...
|
||||||
|
... def __str__(self):
|
||||||
|
... return self.name
|
||||||
|
...
|
||||||
|
... class Meta:
|
||||||
|
... db_connection = 'django_test_db_b'
|
||||||
|
|
||||||
|
# many-many
|
||||||
|
>>> class QC(models.Model):
|
||||||
|
... name = models.CharField(maxlength=20)
|
||||||
|
...
|
||||||
|
... def __str__(self):
|
||||||
|
... return self.name
|
||||||
|
...
|
||||||
|
... class Meta:
|
||||||
|
... db_connection = 'django_test_db_b'
|
||||||
|
|
||||||
|
>>> class QD(models.Model):
|
||||||
|
... name = models.CharField(maxlength=20)
|
||||||
|
... qcs = models.ManyToManyField(QC)
|
||||||
|
...
|
||||||
|
... def __str__(self):
|
||||||
|
... return self.name
|
||||||
|
...
|
||||||
|
... class Meta:
|
||||||
|
... db_connection = 'django_test_db_b'
|
||||||
|
|
||||||
|
# Using the manager, models can be installed individually, whether they
|
||||||
|
# use the default connection or a named connection.
|
||||||
|
|
||||||
|
>>> DA.objects.install()
|
||||||
|
[]
|
||||||
|
>>> QA.objects.install()
|
||||||
|
[]
|
||||||
|
>>> QB.objects.install()
|
||||||
|
[]
|
||||||
|
>>> DA.objects.all()
|
||||||
|
[]
|
||||||
|
>>> list(QA.objects.all())
|
||||||
|
[]
|
||||||
|
>>> list(QB.objects.all())
|
||||||
|
[]
|
||||||
|
>>> QA(name="something").save()
|
||||||
|
>>> QA.objects.all()
|
||||||
|
[<QA: something>]
|
||||||
|
|
||||||
|
# The `install()` method returns a tuple, the first element of which is a
|
||||||
|
# list of statements that were executed, and the second, pending
|
||||||
|
# statements that could not be executed because (for instance) they are
|
||||||
|
# meant to establish foreign key relationships to tables that don't
|
||||||
|
# exist. These are bound to the model's connection and should
|
||||||
|
# be executed after all models in the app have been installed.
|
||||||
|
|
||||||
|
# NOTE: pretend db supports constraints for this test
|
||||||
|
>>> real_cnst = PA._meta.connection_info.backend.supports_constraints
|
||||||
|
>>> PA._meta.connection_info.backend.supports_constraints = True
|
||||||
|
>>> result = PA.objects.install()
|
||||||
|
>>> result
|
||||||
|
[BoundStatement('ALTER TABLE "othertests_pa" ADD CONSTRAINT "c_id_referencing_othertests_pc_id" FOREIGN KEY ("c_id") REFERENCES "othertests_pc" ("id");')]
|
||||||
|
|
||||||
|
# NOTE: restore real constraint flag
|
||||||
|
>>> PA._meta.connection_info.backend.supports_constraints = real_cnst
|
||||||
|
|
||||||
|
# Models with many-many relationships will also have pending statement
|
||||||
|
# lists. Like other pending statements, these should be executed after
|
||||||
|
# all models in the app have been installed.
|
||||||
|
|
||||||
|
>>> QC.objects.install()
|
||||||
|
[]
|
||||||
|
>>> QD.objects.install()
|
||||||
|
[BoundStatement('CREATE TABLE "othertests_qd_qcs" (...);')]
|
||||||
|
|
||||||
|
"""
|
Loading…
x
Reference in New Issue
Block a user