Django/migrate時の処理を読む(テーブル作成)
をテンプレートにして作成
[
トップ
] [
新規
|
一覧
|
単語検索
|
最終更新
|
ヘルプ
]
開始行:
[[Djangoを読む]]
#contents
*はじめに [#r08c1023]
makemigrationsでマイグレーションが作られる様子を見たので...
+アプリのmigrationsディレクトリにあるファイルを読み込む(...
+実行するマイグレーションの決定(django.db.migrations.exe...
+各マイグレーションの実行(django.db.migrations.executor....
で、前に見たように「各マイグレーションの実行」で肝となる...
#code(Python){{
with self.connection.schema_editor(atomic=migration.atomi...
state = migration.apply(state, schema_editor)
}}
connectionはデータベースとの接続、より具体的に言うと、dja...
*django/db/backends/base/base.py [#o549a7fd]
schema_editorメソッドは基底クラスのBaseDatabaseWrapperの...
#code(Python){{
def schema_editor(self, *args, **kwargs):
"""
Returns a new instance of this backend's SchemaEd...
"""
if self.SchemaEditorClass is None:
raise NotImplementedError(
'The SchemaEditorClass attribute of this ...
return self.SchemaEditorClass(self, *args, **kwar...
}}
ちゃんと動くので、もちろんSchemaEditorClassは適切に設定さ...
#code(Python){{
from .schema import DatabaseSchemaEditor ...
class DatabaseWrapper(BaseDatabaseWrapper):
SchemaEditorClass = DatabaseSchemaEditor
}}
*django/db/backends/base/schema.py [#q0aa141c]
SchemaEditorの方も同じようにbaseと個別のDBMS用の実装の構...
基底クラスのBaseDatabaseSchemaEditorに以下の記述がありま...
#code(Python){{
def __enter__(self):
self.deferred_sql = []
if self.atomic_migration:
self.atomic = atomic(self.connection.alias)
self.atomic.__enter__()
return self
def __exit__(self, exc_type, exc_value, traceback):
if exc_type is None:
for sql in self.deferred_sql:
self.execute(sql)
if self.atomic_migration:
self.atomic.__exit__(exc_type, exc_value, tra...
}}
with文に入るときに__enter__が実行され、出るときに__exit__...
atomicは、実際なところatomicに実行されるようなのですがめ...
サブクラスのsqlite3.schema.DatabaseSchemaEditorでは__ente...
*django/db/migrations/migration.py [#ef1bccbf]
Migrationクラスのapplyメソッド
#code(Python){{
def apply(self, project_state, schema_editor, collect...
"""
Takes a project_state representing all migrations...
and a schema_editor for a live database and appli...
in a forwards order.
Returns the resulting project state for efficient...
Migrations.
"""
for operation in self.operations:
# If this operation cannot be represented as ...
# there instead
if collect_sql:
# 省略
# Save the state before the operation has run
old_state = project_state.clone()
operation.state_forwards(self.app_label, proj...
# Run the operation
atomic_operation = operation.atomic or (self....
if not schema_editor.atomic_migration and ato...
# Force a transaction on a non-transactio...
# atomic operation inside a non-atomic mi...
with atomic(schema_editor.connection.alia...
operation.database_forwards(self.app_...
else:
# Normal behaviour
operation.database_forwards(self.app_labe...
return project_state
}}
atomicかどうかはともかく、各operationのdatabase_forwards...
**django/db/migrations/operations [#obee2162]
基底クラスOperationのdatabase_forwardsは例外を投げるだけ...
#code(Python){{
def database_forwards(self, app_label, schema_editor,...
model = to_state.apps.get_model(app_label, self.n...
if self.allow_migrate_model(schema_editor.connect...
schema_editor.create_model(model)
}}
allow_migrateって、許可してもらわないと困るのですが(笑)、...
*BaseDatabaseSchemaEditor.create_model [#dad76d68]
さて、SchemaEditorに戻ってcreate_modelメソッドです。まず...
#code(Python){{
def create_model(self, model):
"""
Takes a model and creates a table for it in the d...
Will also create any accompanying indexes or uniq...
"""
# Create column SQL, add FK deferreds if needed
column_sqls = []
params = []
for field in model._meta.local_fields:
# SQL
definition, extra_params = self.column_sql(mo...
if definition is None:
continue
# Check constraints can go on the column SQL ...
db_params = field.db_parameters(connection=se...
if db_params['check']:
definition += " CHECK (%s)" % db_params['...
# Autoincrement SQL (for backends with inline...
col_type_suffix = field.db_type_suffix(connec...
if col_type_suffix:
definition += " %s" % col_type_suffix
params.extend(extra_params)
# FK
if field.remote_field and field.db_constraint:
to_table = field.remote_field.model._meta...
to_column = field.remote_field.model._met...
if self.connection.features.supports_fore...
self.deferred_sql.append(self._create...
elif self.sql_create_inline_fk:
definition += " " + self.sql_create_i...
"to_table": self.quote_name(to_ta...
"to_column": self.quote_name(to_c...
}
# Add the SQL to our big list
column_sqls.append("%s %s" % (
self.quote_name(field.column),
definition,
))
# Autoincrement SQL (for backends with post t...
if field.get_internal_type() in ("AutoField",...
autoinc_sql = self.connection.ops.autoinc...
if autoinc_sql:
self.deferred_sql.extend(autoinc_sql)
}}
モデルのフィールドごとにSQLの列を作っている雰囲気です。こ...
#code(Python){{
migrations.CreateModel(
name='Choice',
fields=[
('id', models.AutoField(auto_created=True...
('choice_text', models.CharField(max_leng...
('votes', models.IntegerField(default=0)),
],
),
}}
対応する出力(SQLiteの場合。「python manage.py sqlmigrate...
CREATE TABLE "polls_choice" ("id" integer NOT NULL PRIMA...
"choice_text" varchar(200) NOT NULL, "votes" integer NOT...
では追いかけていきましょう。
**column_sql [#p5bf0d36]
coolumn_sqlメソッド。include_defaultがFalseで呼ばれている...
#code(Python){{
def column_sql(self, model, field, include_default=Fa...
"""
Takes a field and returns its column definition.
The field must already have had set_attributes_fr...
"""
# Get the column's type and use that as the basis...
db_params = field.db_parameters(connection=self.c...
sql = db_params['type']
params = []
# Check for fields that aren't actually columns (...
if sql is None:
return None, None
# Work out nullability
null = field.null
# If we were told to include a default value, do so
include_default = include_default and not self.sk...
if include_default:
# 省略
# Oracle treats the empty string ('') as null, so...
# option whenever '' is a possible value.
if (field.empty_strings_allowed and not field.pri...
self.connection.features.interprets_empty...
null = True
if null and not self.connection.features.implied_...
sql += " NULL"
elif not null:
sql += " NOT NULL"
# Primary key/unique outputs
if field.primary_key:
sql += " PRIMARY KEY"
elif field.unique:
sql += " UNIQUE"
# Optionally add the tablespace if it's an implic...
tablespace = field.db_tablespace or model._meta.d...
if tablespace and self.connection.features.suppor...
sql += " %s" % self.connection.ops.tablespace...
# Return the sql
return sql, params
}}
fields、すなわち、django.db.models.fields.Fieldのdb_param...
#code(Python){{
def db_parameters(self, connection):
"""
Extension of db_type(), providing a range of diff...
values (type, checks).
This will look at db_type(), allowing custom mode...
"""
type_string = self.db_type(connection)
check_string = self.db_check(connection)
return {
"type": type_string,
"check": check_string,
}
def db_type(self, connection):
"""
Return the database column data type for this fie...
connection.
"""
data = DictWrapper(self.__dict__, connection.ops....
try:
return connection.data_types[self.get_interna...
except KeyError:
return None
def get_internal_type(self):
return self.__class__.__name__
}}
connection、つまり、DatabaseWrapperクラスを確認するとフィ...
#code(Python){{
data_types = {
'AutoField': 'integer',
'CharField': 'varchar(%(max_length)s)',
'IntegerField': 'integer',
他のマッピング...
}
}}
CharFieldの場合、selfの__dict__(をラップしたもの)を渡す...
**オートインクリメントの処理(テーブル定義内) [#t70f2bda]
制御がcreate_modelに戻って今度はFieldクラスのdb_type_suff...
#code(Python){{
# Autoincrement SQL (for backends with inline...
col_type_suffix = field.db_type_suffix(connec...
if col_type_suffix:
definition += " %s" % col_type_suffix
}}
#code(Python){{
def db_type_suffix(self, connection):
return connection.data_types_suffix.get(self.get_...
}}
connection(DatabaseWrapper)のdata_types定義(SQLiteのや...
#code(Python){{
data_types_suffix = {
'AutoField': 'AUTOINCREMENT',
'BigAutoField': 'AUTOINCREMENT',
}
}}
というわけでAUTOINCREMENTが付加されます。
余談ですが、ループの最後にあるオートインクリメントSQLが実...
**外部キーの処理 [#g21ba9b5]
先ほど挙げた中には外部キーの記述はなかったのですが、とい...
sqlmigrateで出力すると外部キーの部分は次のようになります。
"question_id" integer NOT NULL REFERENCES "polls_questio...
REFERENCES以下を作っているのはここ
#code(Python){{
if self.connection.features.supports_fore...
self.deferred_sql.append(self._create...
elif self.sql_create_inline_fk:
definition += " " + self.sql_create_i...
"to_table": self.quote_name(to_ta...
"to_column": self.quote_name(to_c...
}
}}
featuresはfeaturesモジュールのDatabaseFeaturesクラスです...
*BaseDatabaseSchemaEditor.create_model続き [#j32f3a46]
こんな感じに各フィールドのSQL表現ができたらいよいよテーブ...
#code(Python){{
# Add any unique_togethers (always deferred, as s...
# created afterwards, like geometry fields with s...
for fields in model._meta.unique_together:
columns = [model._meta.get_field(field).colum...
self.deferred_sql.append(self._create_unique_...
# Make the table
sql = self.sql_create_table % {
"table": self.quote_name(model._meta.db_table),
"definition": ", ".join(column_sqls)
}
if model._meta.db_tablespace:
tablespace_sql = self.connection.ops.tablespa...
if tablespace_sql:
sql += ' ' + tablespace_sql
# Prevent using [] as params, in the case a liter...
self.execute(sql, params or None)
# Add any field index and index_together's (defer...
self.deferred_sql.extend(self._model_indexes_sql(...
# Make M2M tables
for field in model._meta.local_many_to_many:
if field.remote_field.through._meta.auto_crea...
self.create_model(field.remote_field.thro...
}}
いろいろやっていますが、executeだけ見ておけばいいでしょう。
#code(Python){{
def execute(self, sql, params=[]):
"""
Executes the given SQL statement, with optional p...
"""
# Log the command we're running, then run it
logger.debug("%s; (params %r)", sql, params, extr...
if self.collect_sql:
# 省略
else:
with self.connection.cursor() as cursor:
cursor.execute(sql, params)
}}
connectionからcursorを取得し、そちらに処理を委譲していま...
*BaseDatabaseWrapper.cursor [#ne476698]
話がDatabaseWrapperにやってきました。cursorメソッドは基底...
#code(Python){{
def cursor(self):
"""
Creates a cursor, opening a connection if necessa...
"""
self.validate_thread_sharing()
if self.queries_logged:
cursor = self.make_debug_cursor(self._cursor())
else:
cursor = self.make_cursor(self._cursor())
return cursor
}}
場合分けされていますが、_cursorとmake_cursorを見ておけば...
#code(Python){{
def _cursor(self):
self.ensure_connection()
with self.wrap_database_errors:
return self.create_cursor()
}}
**connect [#q400f5c6]
ensure_connectionに進む。
#code(Python){{
def ensure_connection(self):
"""
Guarantees that a connection to the database is e...
"""
if self.connection is None:
with self.wrap_database_errors:
self.connect()
}}
しつこい(笑)。connectメソッドです。
#code(Python){{
def connect(self):
"""Connects to the database. Assumes that the con...
# Check for invalid configurations.
self.check_settings()
# In case the previous connection was closed whil...
self.in_atomic_block = False
self.savepoint_ids = []
self.needs_rollback = False
# Reset parameters defining when to close the con...
max_age = self.settings_dict['CONN_MAX_AGE']
self.close_at = None if max_age is None else time...
self.closed_in_transaction = False
self.errors_occurred = False
# Establish the connection
conn_params = self.get_connection_params()
self.connection = self.get_new_connection(conn_pa...
self.set_autocommit(self.settings_dict['AUTOCOMMI...
self.init_connection_state()
connection_created.send(sender=self.__class__, co...
self.run_on_commit = []
}}
接続を行っています。connectで呼ばれているメソッドのうち、...
**create_cursor [#sa29827d]
create_cursorメソッドもサブクラスで実装すべきメソッドです...
#code(Python){{
def create_cursor(self):
return self.connection.cursor(factory=SQLiteCurso...
}}
ややこしいですが、このconnectionというのは先ほどのconnect...
そのsqliteのConnectionオブジェクトのcursorメソッドを呼び...
**django.db.backends.utils.CursorWrapper [#zac8ccf1]
さて、create_cursorメソッドで個々のDBMSのカーソルが返され...
#code(Python){{
def make_cursor(self, cursor):
"""
Creates a cursor without debug logging.
"""
return utils.CursorWrapper(cursor, self)
}}
Wrapperもう飽きたよ(笑)ってところですが、ラップされ返され...
で、そんなこんなで返されたDjangoレベルでのカーソルオブジ...
#code(Python){{
def execute(self, sql, params=None):
self.db.validate_no_broken_transaction()
with self.db.wrap_database_errors:
if params is None:
return self.cursor.execute(sql)
else:
return self.cursor.execute(sql, params)
}}
実際にはさらにここでSQLiteCursorWrapperのexecuteが呼ばれ...
*おわりに [#aea207a0]
今回はデータベースマイグレーションの様子、モデルに対する...
終了行:
[[Djangoを読む]]
#contents
*はじめに [#r08c1023]
makemigrationsでマイグレーションが作られる様子を見たので...
+アプリのmigrationsディレクトリにあるファイルを読み込む(...
+実行するマイグレーションの決定(django.db.migrations.exe...
+各マイグレーションの実行(django.db.migrations.executor....
で、前に見たように「各マイグレーションの実行」で肝となる...
#code(Python){{
with self.connection.schema_editor(atomic=migration.atomi...
state = migration.apply(state, schema_editor)
}}
connectionはデータベースとの接続、より具体的に言うと、dja...
*django/db/backends/base/base.py [#o549a7fd]
schema_editorメソッドは基底クラスのBaseDatabaseWrapperの...
#code(Python){{
def schema_editor(self, *args, **kwargs):
"""
Returns a new instance of this backend's SchemaEd...
"""
if self.SchemaEditorClass is None:
raise NotImplementedError(
'The SchemaEditorClass attribute of this ...
return self.SchemaEditorClass(self, *args, **kwar...
}}
ちゃんと動くので、もちろんSchemaEditorClassは適切に設定さ...
#code(Python){{
from .schema import DatabaseSchemaEditor ...
class DatabaseWrapper(BaseDatabaseWrapper):
SchemaEditorClass = DatabaseSchemaEditor
}}
*django/db/backends/base/schema.py [#q0aa141c]
SchemaEditorの方も同じようにbaseと個別のDBMS用の実装の構...
基底クラスのBaseDatabaseSchemaEditorに以下の記述がありま...
#code(Python){{
def __enter__(self):
self.deferred_sql = []
if self.atomic_migration:
self.atomic = atomic(self.connection.alias)
self.atomic.__enter__()
return self
def __exit__(self, exc_type, exc_value, traceback):
if exc_type is None:
for sql in self.deferred_sql:
self.execute(sql)
if self.atomic_migration:
self.atomic.__exit__(exc_type, exc_value, tra...
}}
with文に入るときに__enter__が実行され、出るときに__exit__...
atomicは、実際なところatomicに実行されるようなのですがめ...
サブクラスのsqlite3.schema.DatabaseSchemaEditorでは__ente...
*django/db/migrations/migration.py [#ef1bccbf]
Migrationクラスのapplyメソッド
#code(Python){{
def apply(self, project_state, schema_editor, collect...
"""
Takes a project_state representing all migrations...
and a schema_editor for a live database and appli...
in a forwards order.
Returns the resulting project state for efficient...
Migrations.
"""
for operation in self.operations:
# If this operation cannot be represented as ...
# there instead
if collect_sql:
# 省略
# Save the state before the operation has run
old_state = project_state.clone()
operation.state_forwards(self.app_label, proj...
# Run the operation
atomic_operation = operation.atomic or (self....
if not schema_editor.atomic_migration and ato...
# Force a transaction on a non-transactio...
# atomic operation inside a non-atomic mi...
with atomic(schema_editor.connection.alia...
operation.database_forwards(self.app_...
else:
# Normal behaviour
operation.database_forwards(self.app_labe...
return project_state
}}
atomicかどうかはともかく、各operationのdatabase_forwards...
**django/db/migrations/operations [#obee2162]
基底クラスOperationのdatabase_forwardsは例外を投げるだけ...
#code(Python){{
def database_forwards(self, app_label, schema_editor,...
model = to_state.apps.get_model(app_label, self.n...
if self.allow_migrate_model(schema_editor.connect...
schema_editor.create_model(model)
}}
allow_migrateって、許可してもらわないと困るのですが(笑)、...
*BaseDatabaseSchemaEditor.create_model [#dad76d68]
さて、SchemaEditorに戻ってcreate_modelメソッドです。まず...
#code(Python){{
def create_model(self, model):
"""
Takes a model and creates a table for it in the d...
Will also create any accompanying indexes or uniq...
"""
# Create column SQL, add FK deferreds if needed
column_sqls = []
params = []
for field in model._meta.local_fields:
# SQL
definition, extra_params = self.column_sql(mo...
if definition is None:
continue
# Check constraints can go on the column SQL ...
db_params = field.db_parameters(connection=se...
if db_params['check']:
definition += " CHECK (%s)" % db_params['...
# Autoincrement SQL (for backends with inline...
col_type_suffix = field.db_type_suffix(connec...
if col_type_suffix:
definition += " %s" % col_type_suffix
params.extend(extra_params)
# FK
if field.remote_field and field.db_constraint:
to_table = field.remote_field.model._meta...
to_column = field.remote_field.model._met...
if self.connection.features.supports_fore...
self.deferred_sql.append(self._create...
elif self.sql_create_inline_fk:
definition += " " + self.sql_create_i...
"to_table": self.quote_name(to_ta...
"to_column": self.quote_name(to_c...
}
# Add the SQL to our big list
column_sqls.append("%s %s" % (
self.quote_name(field.column),
definition,
))
# Autoincrement SQL (for backends with post t...
if field.get_internal_type() in ("AutoField",...
autoinc_sql = self.connection.ops.autoinc...
if autoinc_sql:
self.deferred_sql.extend(autoinc_sql)
}}
モデルのフィールドごとにSQLの列を作っている雰囲気です。こ...
#code(Python){{
migrations.CreateModel(
name='Choice',
fields=[
('id', models.AutoField(auto_created=True...
('choice_text', models.CharField(max_leng...
('votes', models.IntegerField(default=0)),
],
),
}}
対応する出力(SQLiteの場合。「python manage.py sqlmigrate...
CREATE TABLE "polls_choice" ("id" integer NOT NULL PRIMA...
"choice_text" varchar(200) NOT NULL, "votes" integer NOT...
では追いかけていきましょう。
**column_sql [#p5bf0d36]
coolumn_sqlメソッド。include_defaultがFalseで呼ばれている...
#code(Python){{
def column_sql(self, model, field, include_default=Fa...
"""
Takes a field and returns its column definition.
The field must already have had set_attributes_fr...
"""
# Get the column's type and use that as the basis...
db_params = field.db_parameters(connection=self.c...
sql = db_params['type']
params = []
# Check for fields that aren't actually columns (...
if sql is None:
return None, None
# Work out nullability
null = field.null
# If we were told to include a default value, do so
include_default = include_default and not self.sk...
if include_default:
# 省略
# Oracle treats the empty string ('') as null, so...
# option whenever '' is a possible value.
if (field.empty_strings_allowed and not field.pri...
self.connection.features.interprets_empty...
null = True
if null and not self.connection.features.implied_...
sql += " NULL"
elif not null:
sql += " NOT NULL"
# Primary key/unique outputs
if field.primary_key:
sql += " PRIMARY KEY"
elif field.unique:
sql += " UNIQUE"
# Optionally add the tablespace if it's an implic...
tablespace = field.db_tablespace or model._meta.d...
if tablespace and self.connection.features.suppor...
sql += " %s" % self.connection.ops.tablespace...
# Return the sql
return sql, params
}}
fields、すなわち、django.db.models.fields.Fieldのdb_param...
#code(Python){{
def db_parameters(self, connection):
"""
Extension of db_type(), providing a range of diff...
values (type, checks).
This will look at db_type(), allowing custom mode...
"""
type_string = self.db_type(connection)
check_string = self.db_check(connection)
return {
"type": type_string,
"check": check_string,
}
def db_type(self, connection):
"""
Return the database column data type for this fie...
connection.
"""
data = DictWrapper(self.__dict__, connection.ops....
try:
return connection.data_types[self.get_interna...
except KeyError:
return None
def get_internal_type(self):
return self.__class__.__name__
}}
connection、つまり、DatabaseWrapperクラスを確認するとフィ...
#code(Python){{
data_types = {
'AutoField': 'integer',
'CharField': 'varchar(%(max_length)s)',
'IntegerField': 'integer',
他のマッピング...
}
}}
CharFieldの場合、selfの__dict__(をラップしたもの)を渡す...
**オートインクリメントの処理(テーブル定義内) [#t70f2bda]
制御がcreate_modelに戻って今度はFieldクラスのdb_type_suff...
#code(Python){{
# Autoincrement SQL (for backends with inline...
col_type_suffix = field.db_type_suffix(connec...
if col_type_suffix:
definition += " %s" % col_type_suffix
}}
#code(Python){{
def db_type_suffix(self, connection):
return connection.data_types_suffix.get(self.get_...
}}
connection(DatabaseWrapper)のdata_types定義(SQLiteのや...
#code(Python){{
data_types_suffix = {
'AutoField': 'AUTOINCREMENT',
'BigAutoField': 'AUTOINCREMENT',
}
}}
というわけでAUTOINCREMENTが付加されます。
余談ですが、ループの最後にあるオートインクリメントSQLが実...
**外部キーの処理 [#g21ba9b5]
先ほど挙げた中には外部キーの記述はなかったのですが、とい...
sqlmigrateで出力すると外部キーの部分は次のようになります。
"question_id" integer NOT NULL REFERENCES "polls_questio...
REFERENCES以下を作っているのはここ
#code(Python){{
if self.connection.features.supports_fore...
self.deferred_sql.append(self._create...
elif self.sql_create_inline_fk:
definition += " " + self.sql_create_i...
"to_table": self.quote_name(to_ta...
"to_column": self.quote_name(to_c...
}
}}
featuresはfeaturesモジュールのDatabaseFeaturesクラスです...
*BaseDatabaseSchemaEditor.create_model続き [#j32f3a46]
こんな感じに各フィールドのSQL表現ができたらいよいよテーブ...
#code(Python){{
# Add any unique_togethers (always deferred, as s...
# created afterwards, like geometry fields with s...
for fields in model._meta.unique_together:
columns = [model._meta.get_field(field).colum...
self.deferred_sql.append(self._create_unique_...
# Make the table
sql = self.sql_create_table % {
"table": self.quote_name(model._meta.db_table),
"definition": ", ".join(column_sqls)
}
if model._meta.db_tablespace:
tablespace_sql = self.connection.ops.tablespa...
if tablespace_sql:
sql += ' ' + tablespace_sql
# Prevent using [] as params, in the case a liter...
self.execute(sql, params or None)
# Add any field index and index_together's (defer...
self.deferred_sql.extend(self._model_indexes_sql(...
# Make M2M tables
for field in model._meta.local_many_to_many:
if field.remote_field.through._meta.auto_crea...
self.create_model(field.remote_field.thro...
}}
いろいろやっていますが、executeだけ見ておけばいいでしょう。
#code(Python){{
def execute(self, sql, params=[]):
"""
Executes the given SQL statement, with optional p...
"""
# Log the command we're running, then run it
logger.debug("%s; (params %r)", sql, params, extr...
if self.collect_sql:
# 省略
else:
with self.connection.cursor() as cursor:
cursor.execute(sql, params)
}}
connectionからcursorを取得し、そちらに処理を委譲していま...
*BaseDatabaseWrapper.cursor [#ne476698]
話がDatabaseWrapperにやってきました。cursorメソッドは基底...
#code(Python){{
def cursor(self):
"""
Creates a cursor, opening a connection if necessa...
"""
self.validate_thread_sharing()
if self.queries_logged:
cursor = self.make_debug_cursor(self._cursor())
else:
cursor = self.make_cursor(self._cursor())
return cursor
}}
場合分けされていますが、_cursorとmake_cursorを見ておけば...
#code(Python){{
def _cursor(self):
self.ensure_connection()
with self.wrap_database_errors:
return self.create_cursor()
}}
**connect [#q400f5c6]
ensure_connectionに進む。
#code(Python){{
def ensure_connection(self):
"""
Guarantees that a connection to the database is e...
"""
if self.connection is None:
with self.wrap_database_errors:
self.connect()
}}
しつこい(笑)。connectメソッドです。
#code(Python){{
def connect(self):
"""Connects to the database. Assumes that the con...
# Check for invalid configurations.
self.check_settings()
# In case the previous connection was closed whil...
self.in_atomic_block = False
self.savepoint_ids = []
self.needs_rollback = False
# Reset parameters defining when to close the con...
max_age = self.settings_dict['CONN_MAX_AGE']
self.close_at = None if max_age is None else time...
self.closed_in_transaction = False
self.errors_occurred = False
# Establish the connection
conn_params = self.get_connection_params()
self.connection = self.get_new_connection(conn_pa...
self.set_autocommit(self.settings_dict['AUTOCOMMI...
self.init_connection_state()
connection_created.send(sender=self.__class__, co...
self.run_on_commit = []
}}
接続を行っています。connectで呼ばれているメソッドのうち、...
**create_cursor [#sa29827d]
create_cursorメソッドもサブクラスで実装すべきメソッドです...
#code(Python){{
def create_cursor(self):
return self.connection.cursor(factory=SQLiteCurso...
}}
ややこしいですが、このconnectionというのは先ほどのconnect...
そのsqliteのConnectionオブジェクトのcursorメソッドを呼び...
**django.db.backends.utils.CursorWrapper [#zac8ccf1]
さて、create_cursorメソッドで個々のDBMSのカーソルが返され...
#code(Python){{
def make_cursor(self, cursor):
"""
Creates a cursor without debug logging.
"""
return utils.CursorWrapper(cursor, self)
}}
Wrapperもう飽きたよ(笑)ってところですが、ラップされ返され...
で、そんなこんなで返されたDjangoレベルでのカーソルオブジ...
#code(Python){{
def execute(self, sql, params=None):
self.db.validate_no_broken_transaction()
with self.db.wrap_database_errors:
if params is None:
return self.cursor.execute(sql)
else:
return self.cursor.execute(sql, params)
}}
実際にはさらにここでSQLiteCursorWrapperのexecuteが呼ばれ...
*おわりに [#aea207a0]
今回はデータベースマイグレーションの様子、モデルに対する...
ページ名: