#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 [email protected].
To post to this group, send email to [email protected].
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