Opened 10 months ago

Last modified 10 months 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?

Change History (0)

Note: See TracTickets for help on using tickets.
Back to Top