#31846: inspectdb doesn't handle tables with "id" field and without primary key
-------------------------------------+-------------------------------------
               Reporter:  François   |          Owner:  nobody
  Poulain                            |
                   Type:             |         Status:  new
  Uncategorized                      |
              Component:  Core       |        Version:  3.0
  (Management commands)              |
               Severity:  Normal     |       Keywords:
           Triage Stage:             |      Has patch:  1
  Unreviewed                         |
    Needs documentation:  0          |    Needs tests:  0
Patch needs improvement:  0          |  Easy pickings:  0
                  UI/UX:  0          |
-------------------------------------+-------------------------------------
 Hi,

 I plugged django on a crappy drupal DB using inspectdb.py. It is intended
 to be read only. I got models like

 {{{
 class FeedapiStat(models.Model):
     id = models.PositiveIntegerField()
     type = models.CharField(max_length=64)
     timestamp = models.IntegerField()
     time = models.CharField(max_length=20)
     value = models.IntegerField()
 }}}

 And I have been facing with two issues:

 * drupal.FeedapiStat: (models.E004) 'id' can only be used as a field name
 if the field also sets 'primary_key=True'.
 * Then I renamed the field and faced with: (models.E007) Field 'id_field'
 has column name 'id' that is used by another field. HINT: Specify a
 'db_column' for the field. This is because the model has no pk, so django
 automatically try to add one.

 I also got some models with a primary key and an id field which is not a
 pk.

 Since there is no way to tell that a model should not have pk, I modified
 inspectdb as follows:

 {{{
 --- ./venv/lib/python3.7/site-
 packages/django/core/management/commands/inspectdb.py     2020-08-01
 10:28:06.155225992 +0200
 +++ ./base/management/commands/inspectdb.py     2020-08-01
 10:35:06.677586957 +0200
 @@ -101,8 +101,10 @@
                      column_name = row.name
                      is_relation = column_name in relations

 +                    is_pk = column_name == primary_key_column
 +                    has_pk = primary_key_column
                      att_name, params, notes = self.normalize_col_name(
 -                        column_name, used_column_names, is_relation)
 +                        column_name, used_column_names, is_relation,
 is_pk, has_pk)
                      extra_params.update(params)
                      comment_notes.extend(notes)

 @@ -110,7 +112,7 @@
                      column_to_field_name[column_name] = att_name

                      # Add primary_key and unique, if necessary.
 -                    if column_name == primary_key_column:
 +                    if is_pk or (column_name == 'id' and not has_pk):
                          extra_params['primary_key'] = True
                      elif column_name in unique_columns:
                          extra_params['unique'] = True
 @@ -173,7 +175,7 @@
                  for meta_line in self.get_meta(table_name, constraints,
 column_to_field_name, is_view, is_partition):
                      yield meta_line

 -    def normalize_col_name(self, col_name, used_column_names,
 is_relation):
 +    def normalize_col_name(self, col_name, used_column_names,
 is_relation, is_pk, has_pk):
          """
          Modify the column name to make it Python-compatible as a field
 name
          """
 @@ -213,6 +215,10 @@
              new_name += '_field'
              field_notes.append('Field renamed because it was a Python
 reserved word.')

 +        if new_name == 'id' and not is_pk and has_pk:
 +            new_name += '_field'
 +            field_notes.append("Field renamed because 'id' can only be
 used as a field name if the field also sets 'primary_key=True'")
 +
          if new_name[0].isdigit():
              new_name = 'number_%s' % new_name
              field_notes.append("Field renamed because it wasn't a valid
 Python identifier.")
 }}}

 Not sure this is a bug but adding this feature makes inspectdb's behavior
 more convenient, I guess, because the models.E007 error is not easily
 understandable and didn't helped me to find the root of the issue.

 Moreover, when a model has nor pk neither id field, a specific warning
 could be raised, since the automatic id creation will mismatch with the
 db. Maybe, a model instanciated with {{{Meta: managed = False}}} and
 without pk should always raise a check warning.

 How do you think about it?

-- 
Ticket URL: <https://code.djangoproject.com/ticket/31846>
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 view this discussion on the web visit 
https://groups.google.com/d/msgid/django-updates/051.06c97b71473130d5dfd0bd7373d56d8a%40djangoproject.com.

Reply via email to