From 4480645ac3b4d3b72ee2880c774f849965d555d4 Mon Sep 17 00:00:00 2001 From: Malcolm Tredinnick Date: Mon, 1 Sep 2008 00:49:03 +0000 Subject: [PATCH] Fixed #8316 -- Put tighter restrictions on the type of Foreign Key fields created for MySQL (because MySQL + InnoDB has those restrictions). Patch from julianb. git-svn-id: http://code.djangoproject.com/svn/django/trunk@8782 bcc190cf-cafb-0310-a4f2-bffc1f526a37 --- django/db/backends/__init__.py | 3 +++ django/db/backends/mysql/base.py | 1 + django/db/models/fields/related.py | 9 ++++++-- tests/regressiontests/model_regress/models.py | 23 +++++++++++++++++++ 4 files changed, 34 insertions(+), 2 deletions(-) diff --git a/django/db/backends/__init__.py b/django/db/backends/__init__.py index be7aac4c03..23ce12960c 100644 --- a/django/db/backends/__init__.py +++ b/django/db/backends/__init__.py @@ -71,6 +71,9 @@ class BaseDatabaseFeatures(object): interprets_empty_strings_as_nulls = False can_use_chunked_reads = True uses_savepoints = False + # If True, don't use integer foreign keys referring to, e.g., positive + # integer primary keys. + related_fields_match_type = False class BaseDatabaseOperations(object): """ diff --git a/django/db/backends/mysql/base.py b/django/db/backends/mysql/base.py index b93453bc1e..9eb8dece83 100644 --- a/django/db/backends/mysql/base.py +++ b/django/db/backends/mysql/base.py @@ -110,6 +110,7 @@ class CursorWrapper(object): class DatabaseFeatures(BaseDatabaseFeatures): empty_fetchmany_value = () update_can_self_select = False + related_fields_match_type = True class DatabaseOperations(BaseDatabaseOperations): def date_extract_sql(self, lookup_type, field_name): diff --git a/django/db/models/fields/related.py b/django/db/models/fields/related.py index 0513496be2..4532385a4f 100644 --- a/django/db/models/fields/related.py +++ b/django/db/models/fields/related.py @@ -684,7 +684,7 @@ class ForeignKey(RelatedField, Field): def contribute_to_related_class(self, cls, related): setattr(cls, related.get_accessor_name(), ForeignRelatedObjectsDescriptor(related)) - + def formfield(self, **kwargs): defaults = {'form_class': forms.ModelChoiceField, 'queryset': self.rel.to._default_manager.complex_filter(self.rel.limit_choices_to)} defaults.update(kwargs) @@ -695,8 +695,13 @@ class ForeignKey(RelatedField, Field): # of the field to which it points. An exception is if the ForeignKey # points to an AutoField/PositiveIntegerField/PositiveSmallIntegerField, # in which case the column type is simply that of an IntegerField. + # If the database needs similar types for key fields however, the only + # thing we can do is making AutoField an IntegerField. rel_field = self.rel.get_related_field() - if isinstance(rel_field, (AutoField, PositiveIntegerField, PositiveSmallIntegerField)): + if (isinstance(rel_field, AutoField) or + (not connection.features.related_fields_match_type and + isinstance(rel_field, (PositiveIntegerField, + PositiveSmallIntegerField)))): return IntegerField().db_type() return rel_field.db_type() diff --git a/tests/regressiontests/model_regress/models.py b/tests/regressiontests/model_regress/models.py index d79bbca3be..2f2c2facd5 100644 --- a/tests/regressiontests/model_regress/models.py +++ b/tests/regressiontests/model_regress/models.py @@ -32,6 +32,20 @@ class Party(models.Model): class Event(models.Model): when = models.DateTimeField() +class Department(models.Model): + id = models.PositiveIntegerField(primary_key=True) + name = models.CharField(max_length=200) + + def __unicode__(self): + return self.name + +class Worker(models.Model): + department = models.ForeignKey(Department) + name = models.CharField(max_length=200) + + def __unicode__(self): + return self.name + __test__ = {'API_TESTS': """ (NOTE: Part of the regression test here is merely parsing the model declaration. The verbose_name, in particular, did not always work.) @@ -95,5 +109,14 @@ u'' datetime.datetime(2000, 1, 1, 13, 1, 1) >>> e.get_previous_by_when().when datetime.datetime(2000, 1, 1, 6, 1, 1) + +# Check Department and Worker +>>> d = Department(id=10, name='IT') +>>> d.save() +>>> w = Worker(department=d, name='Full-time') +>>> w.save() +>>> w + + """ }