1
0
mirror of https://github.com/django/django.git synced 2025-07-04 17:59: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:
Jason Pellerin 2006-07-03 20:56:24 +00:00
parent 54d611d2a2
commit f194f74aa6
2 changed files with 169 additions and 2 deletions

View File

@ -20,7 +20,9 @@ def ensure_default_manager(sender):
except FieldDoesNotExist:
pass
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)
class Manager(object):
@ -38,7 +40,9 @@ class Manager(object):
# TODO: Use weakref because of possible memory leak / circular reference.
self.model = model
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
#######################
@ -102,6 +106,38 @@ class Manager(object):
def values(self, *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):
# This class ensures managers aren't accessible via model instances.
# For example, Poll.objects works, but poll_obj.objects raises AttributeError.

View 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" (...);')]
"""