From c05cce5c527225ea27ebaff1f5a94878e1e9b6f8 Mon Sep 17 00:00:00 2001 From: Adrian Holovaty Date: Sun, 25 Sep 2005 18:29:59 +0000 Subject: [PATCH] Fixed #556 -- ManyToManyField join tables no longer assume the primary keys of both associated tables are integers. Also added unit tests to confirm. git-svn-id: http://code.djangoproject.com/svn/django/trunk@682 bcc190cf-cafb-0310-a4f2-bffc1f526a37 --- django/core/management.py | 18 ++++++++---------- django/core/meta/__init__.py | 1 - tests/testapp/models/custom_pk.py | 19 +++++++++++++++++++ 3 files changed, 27 insertions(+), 11 deletions(-) diff --git a/django/core/management.py b/django/core/management.py index 64f902b999..9a970d3a75 100644 --- a/django/core/management.py +++ b/django/core/management.py @@ -44,6 +44,11 @@ def _get_contenttype_insert(opts): def _is_valid_dir_name(s): return bool(re.search(r'^\w+$', s)) +# If the foreign key points to an AutoField, the foreign key should be an +# IntegerField, not an AutoField. Otherwise, the foreign key should be the same +# type of field as the field to which it points. +get_rel_data_type = lambda f: (f.__class__.__name__ == 'AutoField') and 'IntegerField' or f.__class__.__name__ + def get_sql_create(mod): "Returns a list of the CREATE TABLE SQL statements for the given module." from django.core import db, meta @@ -54,14 +59,7 @@ def get_sql_create(mod): for f in opts.fields: if isinstance(f, meta.ForeignKey): rel_field = f.rel.get_related_field() - # If the foreign key points to an AutoField, the foreign key - # should be an IntegerField, not an AutoField. Otherwise, the - # foreign key should be the same type of field as the field - # to which it points. - if rel_field.__class__.__name__ == 'AutoField': - data_type = 'IntegerField' - else: - data_type = rel_field.__class__.__name__ + data_type = get_rel_data_type(rel_field) else: rel_field = f data_type = f.__class__.__name__ @@ -94,9 +92,9 @@ def get_sql_create(mod): table_output = ['CREATE TABLE %s (' % f.get_m2m_db_table(opts)] table_output.append(' id %s NOT NULL PRIMARY KEY,' % db.DATA_TYPES['AutoField']) table_output.append(' %s_id %s NOT NULL REFERENCES %s (%s),' % \ - (opts.object_name.lower(), db.DATA_TYPES['IntegerField'], opts.db_table, opts.pk.column)) + (opts.object_name.lower(), db.DATA_TYPES[get_rel_data_type(opts.pk)] % opts.pk.__dict__, opts.db_table, opts.pk.column)) table_output.append(' %s_id %s NOT NULL REFERENCES %s (%s),' % \ - (f.rel.to.object_name.lower(), db.DATA_TYPES['IntegerField'], f.rel.to.db_table, f.rel.to.pk.column)) + (f.rel.to.object_name.lower(), db.DATA_TYPES[get_rel_data_type(f.rel.to.pk)] % f.rel.to.pk.__dict__, f.rel.to.db_table, f.rel.to.pk.column)) table_output.append(' UNIQUE (%s_id, %s_id)' % (opts.object_name.lower(), f.rel.to.object_name.lower())) table_output.append(');') final_output.append('\n'.join(table_output)) diff --git a/django/core/meta/__init__.py b/django/core/meta/__init__.py index 22bd4817d6..cf9284f480 100644 --- a/django/core/meta/__init__.py +++ b/django/core/meta/__init__.py @@ -893,7 +893,6 @@ def method_get_many_to_many(field_with_rel, self): # Handles setting many-to-many relationships. # Example: Poll.set_sites() def method_set_many_to_many(rel_field, self, id_list): - id_list = map(int, id_list) # normalize to integers current_ids = [obj.id for obj in method_get_many_to_many(rel_field, self)] ids_to_add, ids_to_delete = dict([(i, 1) for i in id_list]), [] for current_id in current_ids: diff --git a/tests/testapp/models/custom_pk.py b/tests/testapp/models/custom_pk.py index 46c6cbfb09..234b5c3308 100644 --- a/tests/testapp/models/custom_pk.py +++ b/tests/testapp/models/custom_pk.py @@ -17,6 +17,16 @@ class Employee(meta.Model): def __repr__(self): return "%s %s" % (self.first_name, self.last_name) +class Business(meta.Model): + name = meta.CharField(maxlength=20, primary_key=True) + employees = meta.ManyToManyField(Employee) + class META: + verbose_name_plural = 'businesses' + module_name = 'businesses' + + def __repr__(self): + return self.name + API_TESTS = """ >>> dan = employees.Employee(employee_code='ABC123', first_name='Dan', last_name='Jones') >>> dan.save() @@ -43,4 +53,13 @@ EmployeeDoesNotExist: Employee does not exist for {'pk': 'foo'} >>> fran.save() >>> employees.get_list(last_name__exact='Jones') [Dan Jones, Fran Jones] + +>>> b = businesses.Business(name='Sears') +>>> b.save() +>>> b.set_employees([dan.employee_code, fran.employee_code]) +True +>>> b.get_employee_list() +[Dan Jones, Fran Jones] +>>> fran.get_business_list() +[Sears] """