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:
parent
54d611d2a2
commit
f194f74aa6
@ -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.
|
||||
|
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