30
loading...
This website collects cookies to deliver better user experience
<model_class>._meta.fields[<some_index>].db_type_parameters()
to
and on_delete
are not populated in that dict for ForeignKey
fields. So, knowing the minimum number of parameters needed to properly create an ORM model class for a partition of a table, I constructed a set of "allowed" keys to be the minimum to create a model field and I had to probe the field relation to get the to
and on_delete
values for the ForeignKey
fields.from django.db import transaction
from django.db.models.fields.related import RelatedField
def _create_partition_model(partition_info):
class _Meta:
db_table = partition_info.table_name
model = get_model(partition_info.partitioned_table_name)
partition_model_name = model.__name__ + _get_partition_model_suffix(partition_instance)
partition_model_attrs = {
"Meta": _Meta,
"__module__": model.__module__,
}
allowed_fields = {"null", "primary_key", "default", "editable", "serialize", "db_column", "base_field"}
for field in model._meta.fields:
partition_field_attrs = {
k: v for k, v in field.db_type_parameters(transaction.get_connection()).items() if k in allowed_fields
}
if isinstance(field, RelatedField):
partition_field_attrs["to"] = field.related_model.__name__
partition_field_attrs["on_delete"] = models.DO_NOTHING
for rel_obj in field.related_model._meta.related_objects:
if rel_obj.remote_field == field:
partition_field_attrs["on_delete"] = rel_obj.on_delete
partition_model_attrs[field.name] = type(field)(**partition_field_attrs)
_model = type(partition_model_name, model.__bases__, partition_model_attrs)
return _model
def _create_partition_model(partition_info):
class _Meta:
db_table = partition_info.table_name
model = get_model(partition_info.partitioned_table_name)
partition_model_name = model.__name__ + _get_partition_model_suffix(partition_instance)
Meta.db_table
to the actual table partition name.partition_info
object is simply an object instance that holds information regarding the target table partition.get_model()
with whatever means you would use to dynamically get model classes from django. It'll be some form of django.apps.apps.all_models
probably._get_partition_model_suffix
with whatever means you would use to get the table partition suffix or with whatever name mangling you prefer.partition_model_attrs = {
"Meta": _Meta,
"__module__": model.__module__,
}
allowed_fields = {"null", "primary_key", "default", "editable", "serialize", "db_column", "base_field"}
base_field
for things like an array of another type.for field in model._meta.fields:
partition_field_attrs = {
k: v for k, v in field.db_type_parameters(transaction.get_connection()).items() if k in allowed_fields
}
if isinstance(field, RelatedField):
partition_field_attrs["to"] = field.related_model.__name__
partition_field_attrs["on_delete"] = models.DO_NOTHING
for rel_obj in field.related_model._meta.related_objects:
if rel_obj.remote_field == field:
partition_field_attrs["on_delete"] = rel_obj.on_delete
partition_model_attrs[field.name] = type(field)(**partition_field_attrs)
allowed_fields
set.RelatedField
we need to set to
and on_delete
properly. The to
attribute is easy. The on_delete
attribute is a bit more difficult. The solution I found that works well is to loop through the field's related objects to find the one relation that points back to the field in question. There may be a better way to do this._model = type(partition_model_name, model.__bases__, partition_model_attrs)
return _model
type()
. It was important here to use the __bases__
from the partitioned table's model. Using the model directly creates the problematic subclass. all_models
dict due to the metaprogramming going on under the hood.