Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse code

Fixed #14028 - Added validation for clashing db_columns.

Thanks akaariai for the suggestion.
  • Loading branch information...
commit 41167645b1039067127fa215d4d28296bfa4cfdc 1 parent a53caf2
Helen ST authored September 23, 2013 timgraham committed September 23, 2013
14  django/core/management/validation.py
@@ -63,6 +63,9 @@ def get_validation_errors(outfile, app=None):
63 63
             if not opts.get_field(cls.USERNAME_FIELD).unique:
64 64
                 e.add(opts, 'The USERNAME_FIELD must be unique. Add unique=True to the field parameters.')
65 65
 
  66
+        # Store a list of column names which have already been used by other fields.
  67
+        used_column_names = []
  68
+
66 69
         # Model isn't swapped; do field-specific validation.
67 70
         for f in opts.local_fields:
68 71
             if f.name == 'id' and not f.primary_key and opts.pk.name == 'id':
@@ -75,6 +78,17 @@ def get_validation_errors(outfile, app=None):
75 78
                 # consider NULL and '' to be equal (and thus set up
76 79
                 # character-based fields a little differently).
77 80
                 e.add(opts, '"%s": Primary key fields cannot have null=True.' % f.name)
  81
+
  82
+            # Column name validation.
  83
+            # Determine which column name this field wants to use.
  84
+            _, column_name = f.get_attname_column()
  85
+
  86
+            # Ensure the column name is not already in use.
  87
+            if column_name and column_name in used_column_names:
  88
+                e.add(opts, "Field '%s' has column name '%s' that is already used." % (f.name, column_name))
  89
+            else:
  90
+                used_column_names.append(column_name)
  91
+
78 92
             if isinstance(f, models.CharField):
79 93
                 try:
80 94
                     max_length = int(f.max_length)
53  tests/invalid_models/invalid_models/models.py
@@ -364,6 +364,56 @@ class Meta:
364 364
         ]
365 365
 
366 366
 
  367
+class DuplicateColumnNameModel1(models.Model):
  368
+    """
  369
+    A field (bar) attempts to use a column name which is already auto-assigned
  370
+    earlier in the class. This should raise a validation error.
  371
+    """
  372
+    foo = models.IntegerField()
  373
+    bar = models.IntegerField(db_column='foo')
  374
+
  375
+    class Meta:
  376
+        db_table = 'foobar'
  377
+
  378
+
  379
+class DuplicateColumnNameModel2(models.Model):
  380
+    """
  381
+    A field (foo) attempts to use a column name which is already auto-assigned
  382
+    later in the class. This should raise a validation error.
  383
+    """
  384
+    foo = models.IntegerField(db_column='bar')
  385
+    bar = models.IntegerField()
  386
+
  387
+    class Meta:
  388
+        db_table = 'foobar'
  389
+
  390
+
  391
+class DuplicateColumnNameModel3(models.Model):
  392
+    """Two fields attempt to use each others' names.
  393
+
  394
+    This is not a desirable scenario but valid nonetheless.
  395
+
  396
+    It should not raise a validation error.
  397
+    """
  398
+    foo = models.IntegerField(db_column='bar')
  399
+    bar = models.IntegerField(db_column='foo')
  400
+
  401
+    class Meta:
  402
+        db_table = 'foobar3'
  403
+
  404
+
  405
+class DuplicateColumnNameModel4(models.Model):
  406
+    """Two fields attempt to use the same db_column value.
  407
+
  408
+    This should raise a validation error.
  409
+    """
  410
+    foo = models.IntegerField(db_column='baz')
  411
+    bar = models.IntegerField(db_column='baz')
  412
+
  413
+    class Meta:
  414
+        db_table = 'foobar'
  415
+
  416
+
367 417
 model_errors = """invalid_models.fielderrors: "charfield": CharFields require a "max_length" attribute that is a positive integer.
368 418
 invalid_models.fielderrors: "charfield2": CharFields require a "max_length" attribute that is a positive integer.
369 419
 invalid_models.fielderrors: "charfield3": CharFields require a "max_length" attribute that is a positive integer.
@@ -477,6 +527,9 @@ class Meta:
477 527
 invalid_models.badswappablevalue: TEST_SWAPPED_MODEL_BAD_VALUE is not of the form 'app_label.app_name'.
478 528
 invalid_models.badswappablemodel: Model has been swapped out for 'not_an_app.Target' which has not been installed or is abstract.
479 529
 invalid_models.badindextogether1: "index_together" refers to field_that_does_not_exist, a field that doesn't exist.
  530
+invalid_models.duplicatecolumnnamemodel1: Field 'bar' has column name 'foo' that is already used.
  531
+invalid_models.duplicatecolumnnamemodel2: Field 'bar' has column name 'bar' that is already used.
  532
+invalid_models.duplicatecolumnnamemodel4: Field 'bar' has column name 'baz' that is already used.
480 533
 """
481 534
 
482 535
 if not connection.features.interprets_empty_strings_as_nulls:

0 notes on commit 4116764

Please sign in to comment.
Something went wrong with that request. Please try again.