From 6cd37e0a1ffff06517a62c1cb0009825c551e31c Mon Sep 17 00:00:00 2001 From: Russell Keith-Magee Date: Mon, 8 Jun 2009 04:50:24 +0000 Subject: [PATCH] Fixed #10785 -- Corrected a case for foreign key lookup where the related object is a custom primary key. Thanks to Alex Gaynor for the patch. git-svn-id: http://code.djangoproject.com/svn/django/trunk@10952 bcc190cf-cafb-0310-a4f2-bffc1f526a37 --- django/db/models/fields/related.py | 14 ++++---- tests/modeltests/custom_pk/fields.py | 54 ++++++++++++++++++++++++++++ tests/modeltests/custom_pk/models.py | 27 ++++++++++++++ 3 files changed, 88 insertions(+), 7 deletions(-) create mode 100644 tests/modeltests/custom_pk/fields.py diff --git a/django/db/models/fields/related.py b/django/db/models/fields/related.py index 419695b74b..78019f2bd1 100644 --- a/django/db/models/fields/related.py +++ b/django/db/models/fields/related.py @@ -132,12 +132,13 @@ class RelatedField(object): v, field = getattr(v, v._meta.pk.name), v._meta.pk except AttributeError: pass - if field: - if lookup_type in ('range', 'in'): - v = [v] - v = field.get_db_prep_lookup(lookup_type, v) - if isinstance(v, list): - v = v[0] + if not field: + field = self.rel.get_related_field() + if lookup_type in ('range', 'in'): + v = [v] + v = field.get_db_prep_lookup(lookup_type, v) + if isinstance(v, list): + v = v[0] return v if hasattr(value, 'as_sql') or hasattr(value, '_as_sql'): @@ -958,4 +959,3 @@ class ManyToManyField(RelatedField, Field): # A ManyToManyField is not represented by a single column, # so return None. return None - diff --git a/tests/modeltests/custom_pk/fields.py b/tests/modeltests/custom_pk/fields.py new file mode 100644 index 0000000000..319e42f974 --- /dev/null +++ b/tests/modeltests/custom_pk/fields.py @@ -0,0 +1,54 @@ +import random +import string + +from django.db import models + +class MyWrapper(object): + def __init__(self, value): + self.value = value + + def __repr__(self): + return "<%s: %s>" % (self.__class__.__name__, self.value) + + def __unicode__(self): + return self.value + + def __eq__(self, other): + if isinstance(other, self.__class__): + return self.value == other.value + return self.value == other + +class MyAutoField(models.CharField): + __metaclass__ = models.SubfieldBase + + def __init__(self, *args, **kwargs): + kwargs['max_length'] = 10 + super(MyAutoField, self).__init__(*args, **kwargs) + + def pre_save(self, instance, add): + value = getattr(instance, self.attname, None) + if not value: + value = MyWrapper(''.join(random.sample(string.lowercase, 10))) + setattr(instance, self.attname, value) + return value + + def to_python(self, value): + if not value: + return + if not isinstance(value, MyWrapper): + value = MyWrapper(value) + return value + + def get_db_prep_save(self, value): + if not value: + return + if isinstance(value, MyWrapper): + return unicode(value) + return value + + def get_db_prep_value(self, value): + if not value: + return + if isinstance(value, MyWrapper): + return unicode(value) + return value diff --git a/tests/modeltests/custom_pk/models.py b/tests/modeltests/custom_pk/models.py index 091f7f32b4..b1d0cb37d0 100644 --- a/tests/modeltests/custom_pk/models.py +++ b/tests/modeltests/custom_pk/models.py @@ -9,6 +9,8 @@ this behavior by explicitly adding ``primary_key=True`` to a field. from django.conf import settings from django.db import models, transaction, IntegrityError +from fields import MyAutoField + class Employee(models.Model): employee_code = models.IntegerField(primary_key=True, db_column = 'code') first_name = models.CharField(max_length=20) @@ -28,6 +30,16 @@ class Business(models.Model): def __unicode__(self): return self.name +class Bar(models.Model): + id = MyAutoField(primary_key=True, db_index=True) + + def __unicode__(self): + return repr(self.pk) + + +class Foo(models.Model): + bar = models.ForeignKey(Bar) + __test__ = {'API_TESTS':""" >>> dan = Employee(employee_code=123, first_name='Dan', last_name='Jones') >>> dan.save() @@ -121,6 +133,21 @@ DoesNotExist: Employee matching query does not exist. ... print "Fail with %s" % type(e) Pass +# Regression for #10785 -- Custom fields can be used for primary keys. +>>> new_bar = Bar.objects.create() +>>> new_foo = Foo.objects.create(bar=new_bar) +>>> f = Foo.objects.get(bar=new_bar.pk) +>>> f == new_foo +True +>>> f.bar == new_bar +True + +>>> f = Foo.objects.get(bar=new_bar) +>>> f == new_foo +True +>>> f.bar == new_bar +True + """} # SQLite lets objects be saved with an empty primary key, even though an