Ticket #21216: 0001-Fixed-21216-Allow-OneToOneField-reverse-accessor-to-.patch

File 0001-Fixed-21216-Allow-OneToOneField-reverse-accessor-to-.patch, 5.9 KB (added by Simon Charette, 11 years ago)
  • django/db/models/fields/related.py

    From a2de78b3b8db5784cc1aecefd90f833ba7d9532e Mon Sep 17 00:00:00 2001
    From: Simon Charette <charette.s@gmail.com>
    Date: Tue, 20 Aug 2013 01:52:32 -0400
    Subject: [PATCH] Fixed #21216 -- Allow `OneToOneField` reverse accessor to be
     hidden.
    
    ---
     django/db/models/fields/related.py |  8 +++-----
     docs/releases/1.7.txt              |  5 +++++
     tests/one_to_one_regress/models.py | 15 +++++++++++++--
     tests/one_to_one_regress/tests.py  | 16 +++++++++++++---
     4 files changed, 34 insertions(+), 10 deletions(-)
    
    diff --git a/django/db/models/fields/related.py b/django/db/models/fields/related.py
    index 6cd8d19..aa2a83b 100644
    a b class ManyToManyRel(object):  
    960960class ForeignObject(RelatedField):
    961961    requires_unique_target = True
    962962    generate_reverse_relation = True
     963    related_accessor_class = ForeignRelatedObjectsDescriptor
    963964
    964965    def __init__(self, to, from_fields, to_fields, **kwargs):
    965966        self.from_fields = from_fields
    class ForeignObject(RelatedField):  
    11601161        # Internal FK's - i.e., those with a related name ending with '+' -
    11611162        # and swapped models don't get a related descriptor.
    11621163        if not self.rel.is_hidden() and not related.model._meta.swapped:
    1163             setattr(cls, related.get_accessor_name(), ForeignRelatedObjectsDescriptor(related))
     1164            setattr(cls, related.get_accessor_name(), self.related_accessor_class(related))
    11641165            if self.rel.limit_choices_to:
    11651166                cls._meta.related_fkey_lookups.append(self.rel.limit_choices_to)
    11661167
    class OneToOneField(ForeignKey):  
    13341335    always returns the object pointed to (since there will only ever be one),
    13351336    rather than returning a list.
    13361337    """
     1338    related_accessor_class = SingleRelatedObjectDescriptor
    13371339    description = _("One-to-one relationship")
    13381340
    13391341    def __init__(self, to, to_field=None, **kwargs):
    class OneToOneField(ForeignKey):  
    13461348            del kwargs['unique']
    13471349        return name, path, args, kwargs
    13481350
    1349     def contribute_to_related_class(self, cls, related):
    1350         setattr(cls, related.get_accessor_name(),
    1351                 SingleRelatedObjectDescriptor(related))
    1352 
    13531351    def formfield(self, **kwargs):
    13541352        if self.rel.parent_link:
    13551353            return None
  • docs/releases/1.7.txt

    diff --git a/docs/releases/1.7.txt b/docs/releases/1.7.txt
    index d613220..8f650a1 100644
    a b Models  
    289289* Explicit :class:`~django.db.models.OneToOneField` for
    290290  :ref:`multi-table-inheritance` are now discovered in abstract classes.
    291291
     292* Is it now possible to avoid creating a backward relation for
     293  :class:`~django.db.models.OneToOneField` by setting its
     294  :attr:`~django.db.models.ForeignKey.related_name` to
     295  `'+'` or ending it with `'+'`.
     296
    292297Signals
    293298^^^^^^^
    294299
  • tests/one_to_one_regress/models.py

    diff --git a/tests/one_to_one_regress/models.py b/tests/one_to_one_regress/models.py
    index 9b65edf..3cd4e17 100644
    a b class Place(models.Model):  
    1212    def __str__(self):
    1313        return "%s the place" % self.name
    1414
     15
    1516@python_2_unicode_compatible
    1617class Restaurant(models.Model):
    1718    place = models.OneToOneField(Place)
    class Restaurant(models.Model):  
    2122    def __str__(self):
    2223        return "%s the restaurant" % self.place.name
    2324
     25
    2426@python_2_unicode_compatible
    2527class Bar(models.Model):
    2628    place = models.OneToOneField(Place)
    class Bar(models.Model):  
    2931    def __str__(self):
    3032        return "%s the bar" % self.place.name
    3133
     34
    3235class UndergroundBar(models.Model):
    3336    place = models.OneToOneField(Place, null=True)
    3437    serves_cocktails = models.BooleanField(default=True)
    3538
     39
    3640@python_2_unicode_compatible
    3741class Favorites(models.Model):
    38     name = models.CharField(max_length = 50)
     42    name = models.CharField(max_length=50)
    3943    restaurants = models.ManyToManyField(Restaurant)
    4044
    4145    def __str__(self):
    4246        return "Favorites for %s" % self.name
    4347
     48
    4449class Target(models.Model):
    4550    pass
    4651
     52
    4753class Pointer(models.Model):
    4854    other = models.OneToOneField(Target, primary_key=True)
    4955
     56
    5057class Pointer2(models.Model):
    51     other = models.OneToOneField(Target)
     58    other = models.OneToOneField(Target, related_name='second_pointer')
     59
     60
     61class HiddenPointer(models.Model):
     62    target = models.OneToOneField(Target, related_name='hidden+')
  • tests/one_to_one_regress/tests.py

    diff --git a/tests/one_to_one_regress/tests.py b/tests/one_to_one_regress/tests.py
    index 3dfe3e4..da4309e 100644
    a b from __future__ import unicode_literals  
    22
    33from django.test import TestCase
    44
    5 from .models import Place, Restaurant, Bar, Favorites, Target, UndergroundBar
     5from .models import (Bar, Favorites, HiddenPointer, Place, Restaurant, Target,
     6    UndergroundBar)
    67
    78
    89class OneToOneRegressionTests(TestCase):
    class OneToOneRegressionTests(TestCase):  
    125126            []
    126127        )
    127128        self.assertQuerysetEqual(
    128             Target.objects.filter(pointer2=None),
     129            Target.objects.filter(second_pointer=None),
    129130            ['<Target: Target object>']
    130131        )
    131132        self.assertQuerysetEqual(
    132             Target.objects.exclude(pointer2=None),
     133            Target.objects.exclude(second_pointer=None),
    133134            []
    134135        )
    135136
    class OneToOneRegressionTests(TestCase):  
    250251        self.p1.delete()
    251252        self.assertTrue(UndergroundBar.objects.filter(pk=u.pk).exists())
    252253        self.assertIsNone(UndergroundBar.objects.get(pk=u.pk).place)
     254
     255    def test_hidden_accessor(self):
     256        """
     257        When a '+' ending related name is specified no reverse accessor should
     258        be added to the related model.
     259        """
     260        self.assertFalse(
     261            hasattr(Target, HiddenPointer._meta.get_field('target').related.get_accessor_name())
     262        )
Back to Top