Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Make a start on operations and state (not sure if final layout)

  • Loading branch information...
commit 76d93a52cd56be23104f824e6755ecc8d3a34d94 1 parent eb5e502
@andrewgodwin andrewgodwin authored
View
1  django/db/migrations/operations/__init__.py
@@ -0,0 +1 @@
+from .models import CreateModel, DeleteModel
View
38 django/db/migrations/operations/base.py
@@ -0,0 +1,38 @@
+class Operation(object):
+ """
+ Base class for migration operations.
+
+ It's responsible for both mutating the in-memory model state
+ (see db/migrations/state.py) to represent what it performs, as well
+ as actually performing it against a live database.
+
+ Note that some operations won't modify memory state at all (e.g. data
+ copying operations), and some will need their modifications to be
+ optionally specified by the user (e.g. custom Python code snippets)
+ """
+
+ # If this migration can be run in reverse.
+ # Some operations are impossible to reverse, like deleting data.
+ reversible = True
+
+ def state_forwards(self, app, state):
+ """
+ Takes the state from the previous migration, and mutates it
+ so that it matches what this migration would perform.
+ """
+ raise NotImplementedError()
+
+ def database_forwards(self, app, schema_editor, from_state, to_state):
+ """
+ Performs the mutation on the database schema in the normal
+ (forwards) direction.
+ """
+ raise NotImplementedError()
+
+ def database_backwards(self, app, schema_editor, from_state, to_state):
+ """
+ Performs the mutation on the database schema in the reverse
+ direction - e.g. if this were CreateModel, it would in fact
+ drop the model's table.
+ """
+ raise NotImplementedError()
View
26 django/db/migrations/operations/models.py
@@ -0,0 +1,26 @@
+from .base import Operation
+from django.db.migrations.state import ModelState
+
+
+class CreateModel(Operation):
+ """
+ Create a model's table.
+ """
+
+ def __init__(self, name):
+ self.name = name
+
+ def state_forwards(self, app, state):
+ state.models[app, self.name.lower()] = ModelState(state, app, self.name)
+
+ def database_forwards(self, app, schema_editor, from_state, to_state):
+ app_cache = to_state.render()
+ schema_editor.create_model(app_cache.get_model(app, self.name))
+
+ def database_backwards(self, app, schema_editor, from_state, to_state):
+ """
+ Performs the mutation on the database schema in the reverse
+ direction - e.g. if this were CreateModel, it would in fact
+ drop the model's table.
+ """
+ raise NotImplementedError()
View
81 django/db/migrations/state.py
@@ -0,0 +1,81 @@
+from django.db import models
+from django.db.models.loading import BaseAppCache
+
+
+class ProjectState(object):
+ """
+ Represents the entire project's overall state.
+ This is the item that is passed around - we do it here rather than at the
+ app level so that cross-app FKs/etc. resolve properly.
+ """
+
+ def __init__(self, models=None):
+ self.models = models or {}
+ self.app_cache = None
+
+ def clone(self):
+ "Returns an exact copy of this ProjectState"
+ ps = ProjectState(
+ models = dict((k, v.copy()) for k, v in self.models.items())
+ )
+ for model in ps.models.values():
+ model.project_state = ps
+ return ps
+
+ def render(self):
+ "Turns the project state into actual models in a new AppCache"
+ if self.app_cache is None:
+ self.app_cache = BaseAppCache()
+ for model in self.model.values:
+ model.render(self.app_cache)
+ return self.app_cache
+
+
+class ModelState(object):
+ """
+ Represents a Django Model. We don't use the actual Model class
+ as it's not designed to have its options changed - instead, we
+ mutate this one and then render it into a Model as required.
+ """
+
+ def __init__(self, project_state, app_label, name, fields=None, options=None, bases=None):
+ self.project_state = project_state
+ self.app_label = app_label
+ self.name = name
+ self.fields = fields or []
+ self.options = options or {}
+ self.bases = bases or None
+
+ def clone(self):
+ "Returns an exact copy of this ModelState"
+ return self.__class__(
+ project_state = self.project_state,
+ app_label = self.app_label,
+ name = self.name,
+ fields = self.fields,
+ options = self.options,
+ bases = self.bases,
+ )
+
+ def render(self, app_cache):
+ "Creates a Model object from our current state into the given app_cache"
+ # First, make a Meta object
+ meta_contents = {'app_label': self.app_label, "app_cache": app_cache}
+ meta_contents.update(self.options)
+ meta = type("Meta", tuple(), meta_contents)
+ # Then, work out our bases
+ # TODO: Use the actual bases
+ if self.bases:
+ raise NotImplementedError("Custom bases not quite done yet!")
+ else:
+ bases = [models.Model]
+ # Turn fields into a dict for the body, add other bits
+ body = dict(self.fields)
+ body['Meta'] = meta
+ body['__module__'] = "__fake__"
+ # Then, make a Model object
+ return type(
+ self.name,
+ tuple(bases),
+ body,
+ )
Please sign in to comment.
Something went wrong with that request. Please try again.