Opened 7 years ago
Last modified 7 years ago
#30002 closed Uncategorized
Dynamic model — at Initial Version
| Reported by: | Artem | Owned by: | nobody |
|---|---|---|---|
| Component: | Database layer (models, ORM) | Version: | 2.1 |
| Severity: | Normal | Keywords: | |
| Cc: | Triage Stage: | Unreviewed | |
| Has patch: | no | Needs documentation: | no |
| Needs tests: | no | Patch needs improvement: | no |
| Easy pickings: | no | UI/UX: | no |
Description
I have ProjectCategoryCountPartition model
class ProjectCategoryCountPartition(models.Model):
city_slug = models.CharField(verbose_name=_('City slug'), max_length=255, db_index=True)
domain = models.CharField(verbose_name=_('Site name'), max_length=255)
category_id = models.PositiveIntegerField(verbose_name=_('Category id'))
name = models.CharField(verbose_name=_('Category project name'), max_length=255)
count = models.PositiveIntegerField(default=0)
class Meta:
db_table = "wbtm_projects_category_partition"
class DefaultMeta:
db_table = "wbtm_projects_category_partition"
ATTRIBUTE = {
'city_slug': models.CharField(verbose_name=_('City slug'), max_length=255, db_index=True),
'domain': models.CharField(verbose_name=_('Site name'), max_length=255),
'category_id': models.PositiveIntegerField(verbose_name=_('Category id')),
'name': models.CharField(verbose_name=_('Category project name'), max_length=255),
'count': models.PositiveIntegerField(default=0)
}
@classmethod
def check_partition(cls, city_slug):
city_slug = cls.check_city_slug(city_slug)
default_db_table = cls.DefaultMeta.db_table
new_db_table = "{}_{}".format(default_db_table, city_slug)
if new_db_table in connection.introspection.table_names():
return True
return False
@classmethod
def check_city_slug(cls, city_slug):
city_slug = city_slug.replace('-', '_')
if not re.match('^[a-zA-Z0-9_]+?$', city_slug):
raise Exception('Unsupported city_slug')
return city_slug
@classmethod
def create_partition(cls, city_slug):
city_slug = cls.check_city_slug(city_slug)
default_db_table = cls.DefaultMeta.db_table
new_db_table = "{}_{}".format(default_db_table, city_slug)
if cls.check_partition(city_slug):
return new_db_table
queries = [
"""
CREATE TABLE {}() INHERITS ({});
""".format(new_db_table, default_db_table),
]
cursor = connection.cursor()
for query in queries:
cursor.execute(query)
return new_db_table
@classmethod
def get_city_model(cls, city_slug):
city_slug = cls.check_city_slug(city_slug)
model_name = city_slug.replace('_','')
db_table = cls.create_partition(city_slug)
attrs = cls.DefaultMeta.ATTRIBUTE.copy()
attrs.update({
'__module__': ProjectCategoryCountPartition.__module__,
'Meta': type(
'Meta',
(),
dict(
# managed=False,
db_table=db_table,
)
),
})
return type("ProjectCategoryCountPartition{}".format(model_name), (models.Model,), attrs)
I write method:
for city in ['moskva', 'london']:
ProjectCategoryCountPartitionModel = ProjectCategoryCountPartition.get_city_model(project_city.slug)
print(ProjectCategoryCountPartitionModel.objects.filter(
city_slug=city,
domain='site.ru',
category_id=1,
).query)
data = {'name': 'Cat1', 'count': 1}
ProjectCategoryCountPartitionModel.objects.update_or_create(
city_slug=city,
domain='site.ru',
category_id=1,
defaults=data
)
But, Second call ProjectCategoryCountPartitionModel, return error query. Example:
SELECT "wbtm_projects_category_partition_london"."id", "wbtm_projects_category_partition_moskva"."city_slug", "wbtm_projects_category_partition_moskva"."domain", "wbtm_projects_category_partition_moskva"."category_id", "wbtm_projects_category_partition_moskva"."name", "wbtm_projects_category_partition_moskva"."count" FROM "wbtm_projects_category_partition_london" WHERE ("wbtm_projects_category_partition_moskva"."category_id" = 1 AND "wbtm_projects_category_partition_moskva"."city_slug" = 'london' AND "wbtm_projects_category_partition_moskva"."domain" = 'site.ru')
Why are the previous model fields cached in the new model?
Note:
See TracTickets
for help on using tickets.