Source code for django.db.migrations.operations.special

fromdjango.dbimportrouterfrom.baseimportOperation

[docs]classSeparateDatabaseAndState(Operation):""" Take two lists of operations - ones that will be used for the database, and ones that will be used for the state change. This allows operations that don't support state change to have it applied, or have operations that affect the state or not the database, or so on. """serialization_expand_args=['database_operations','state_operations']def__init__(self,database_operations=None,state_operations=None):self.database_operations=database_operationsor[]self.state_operations=state_operationsor[]defdeconstruct(self):kwargs={}ifself.database_operations:kwargs['database_operations']=self.database_operationsifself.state_operations:kwargs['state_operations']=self.state_operationsreturn(self.__class__.__qualname__,[],kwargs)defstate_forwards(self,app_label,state):forstate_operationinself.state_operations:state_operation.state_forwards(app_label,state)defdatabase_forwards(self,app_label,schema_editor,from_state,to_state):# We calculate state separately in here since our state functions aren't usefulfordatabase_operationinself.database_operations:to_state=from_state.clone()database_operation.state_forwards(app_label,to_state)database_operation.database_forwards(app_label,schema_editor,from_state,to_state)from_state=to_statedefdatabase_backwards(self,app_label,schema_editor,from_state,to_state):# We calculate state separately in here since our state functions aren't usefulto_states={}fordbopinself.database_operations:to_states[dbop]=to_stateto_state=to_state.clone()dbop.state_forwards(app_label,to_state)# to_state now has the states of all the database_operations applied# which is the from_state for the backwards migration of the last# operation.fordatabase_operationinreversed(self.database_operations):from_state=to_stateto_state=to_states[database_operation]database_operation.database_backwards(app_label,schema_editor,from_state,to_state)defdescribe(self):return"Custom state/database change combination"

[docs]classRunSQL(Operation):""" Run some raw SQL. A reverse SQL statement may be provided. Also accept a list of operations that represent the state change effected by this SQL change, in case it's custom column/table creation/deletion. """noop=''def__init__(self,sql,reverse_sql=None,state_operations=None,hints=None,elidable=False):self.sql=sqlself.reverse_sql=reverse_sqlself.state_operations=state_operationsor[]self.hints=hintsor{}self.elidable=elidabledefdeconstruct(self):kwargs={'sql':self.sql,}ifself.reverse_sqlisnotNone:kwargs['reverse_sql']=self.reverse_sqlifself.state_operations:kwargs['state_operations']=self.state_operationsifself.hints:kwargs['hints']=self.hintsreturn(self.__class__.__qualname__,[],kwargs)@propertydefreversible(self):returnself.reverse_sqlisnotNonedefstate_forwards(self,app_label,state):forstate_operationinself.state_operations:state_operation.state_forwards(app_label,state)defdatabase_forwards(self,app_label,schema_editor,from_state,to_state):ifrouter.allow_migrate(schema_editor.connection.alias,app_label,**self.hints):self._run_sql(schema_editor,self.sql)defdatabase_backwards(self,app_label,schema_editor,from_state,to_state):ifself.reverse_sqlisNone:raiseNotImplementedError("You cannot reverse this operation")ifrouter.allow_migrate(schema_editor.connection.alias,app_label,**self.hints):self._run_sql(schema_editor,self.reverse_sql)defdescribe(self):return"Raw SQL operation"def_run_sql(self,schema_editor,sqls):ifisinstance(sqls,(list,tuple)):forsqlinsqls:params=Noneifisinstance(sql,(list,tuple)):elements=len(sql)ifelements==2:sql,params=sqlelse:raiseValueError("Expected a 2-tuple but got %d"%elements)schema_editor.execute(sql,params=params)elifsqls!=RunSQL.noop:statements=schema_editor.connection.ops.prepare_sql_script(sqls)forstatementinstatements:schema_editor.execute(statement,params=None)

[docs]classRunPython(Operation):""" Run Python code in a context suitable for doing versioned ORM operations. """reduces_to_sql=Falsedef__init__(self,code,reverse_code=None,atomic=None,hints=None,elidable=False):self.atomic=atomic# Forwards codeifnotcallable(code):raiseValueError("RunPython must be supplied with a callable")self.code=code# Reverse codeifreverse_codeisNone:self.reverse_code=Noneelse:ifnotcallable(reverse_code):raiseValueError("RunPython must be supplied with callable arguments")self.reverse_code=reverse_codeself.hints=hintsor{}self.elidable=elidabledefdeconstruct(self):kwargs={'code':self.code,}ifself.reverse_codeisnotNone:kwargs['reverse_code']=self.reverse_codeifself.atomicisnotNone:kwargs['atomic']=self.atomicifself.hints:kwargs['hints']=self.hintsreturn(self.__class__.__qualname__,[],kwargs)@propertydefreversible(self):returnself.reverse_codeisnotNonedefstate_forwards(self,app_label,state):# RunPython objects have no state effect. To add some, combine this# with SeparateDatabaseAndState.passdefdatabase_forwards(self,app_label,schema_editor,from_state,to_state):# RunPython has access to all models. Ensure that all models are# reloaded in case any are delayed.from_state.clear_delayed_apps_cache()ifrouter.allow_migrate(schema_editor.connection.alias,app_label,**self.hints):# We now execute the Python code in a context that contains a 'models'# object, representing the versioned models as an app registry.# We could try to override the global cache, but then people will still# use direct imports, so we go with a documentation approach instead.self.code(from_state.apps,schema_editor)defdatabase_backwards(self,app_label,schema_editor,from_state,to_state):ifself.reverse_codeisNone:raiseNotImplementedError("You cannot reverse this operation")ifrouter.allow_migrate(schema_editor.connection.alias,app_label,**self.hints):self.reverse_code(from_state.apps,schema_editor)defdescribe(self):return"Raw Python operation"