#30002: Dynamic model
-------------------------------------+-------------------------------------
     Reporter:  temi4                |                    Owner:  temi4
         Type:  Uncategorized        |                   Status:  assigned
    Component:  Database layer       |                  Version:  2.1
  (models, ORM)                      |
     Severity:  Normal               |               Resolution:
     Keywords:                       |             Triage Stage:
                                     |  Unreviewed
    Has patch:  0                    |      Needs documentation:  0
  Needs tests:  0                    |  Patch needs improvement:  0
Easy pickings:  0                    |                    UI/UX:  0
-------------------------------------+-------------------------------------
Changes (by temi4):

 * owner:  nobody => temi4
 * status:  new => assigned


Old 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?

New 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(city)
       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?

--

-- 
Ticket URL: <https://code.djangoproject.com/ticket/30002#comment:1>
Django <https://code.djangoproject.com/>
The Web framework for perfectionists with deadlines.

-- 
You received this message because you are subscribed to the Google Groups 
"Django updates" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to django-updates+unsubscr...@googlegroups.com.
To post to this group, send email to django-updates@googlegroups.com.
To view this discussion on the web visit 
https://groups.google.com/d/msgid/django-updates/063.451747a5f13423df3449b18daea2a897%40djangoproject.com.
For more options, visit https://groups.google.com/d/optout.

Reply via email to