Commit c7087bc7 authored by Simon Charette's avatar Simon Charette Committed by Tim Graham
Browse files

Fixed #23862 -- Made ManyToManyRel.get_related_field() respect to_field.

parent a7c3d0f2
Loading
Loading
Loading
Loading
+11 −4
Original line number Diff line number Diff line
@@ -1348,11 +1348,18 @@ class ManyToManyRel(object):

    def get_related_field(self):
        """
        Returns the field in the to' object to which this relationship is tied
        (this is always the primary key on the target model). Provided for
        symmetry with ManyToOneRel.
        Returns the field in the 'to' object to which this relationship is tied.
        Provided for symmetry with ManyToOneRel.
        """
        return self.to._meta.pk
        opts = self.through._meta
        if self.through_fields:
            field = opts.get_field(self.through_fields[0])
        else:
            for field in opts.fields:
                rel = getattr(field, 'rel', None)
                if rel and rel.to == self.to:
                    break
        return field.foreign_related_fields[0]


class ForeignObject(RelatedField):
+22 −0
Original line number Diff line number Diff line
@@ -113,3 +113,25 @@ class Relationship(models.Model):
    another = models.ForeignKey(Employee, related_name="rel_another_set", null=True)
    target = models.ForeignKey(Employee, related_name="rel_target_set")
    source = models.ForeignKey(Employee, related_name="rel_source_set")


class Ingredient(models.Model):
    iname = models.CharField(max_length=20, unique=True)

    class Meta:
        ordering = ('iname',)


class Recipe(models.Model):
    rname = models.CharField(max_length=20, unique=True)
    ingredients = models.ManyToManyField(
        Ingredient, through='RecipeIngredient', related_name='recipes',
    )

    class Meta:
        ordering = ('rname',)


class RecipeIngredient(models.Model):
    ingredient = models.ForeignKey(Ingredient, to_field='iname')
    recipe = models.ForeignKey(Recipe, to_field='rname')
+29 −1
Original line number Diff line number Diff line
@@ -6,7 +6,8 @@ from operator import attrgetter
from django.test import TestCase

from .models import (Person, Group, Membership, CustomMembership,
    PersonSelfRefM2M, Friendship, Event, Invitation, Employee, Relationship)
    PersonSelfRefM2M, Friendship, Event, Invitation, Employee, Relationship,
    Ingredient, Recipe, RecipeIngredient)


class M2mThroughTests(TestCase):
@@ -426,3 +427,30 @@ class M2mThroughReferentialTests(TestCase):
            ['peter', 'mary', 'harry'],
            attrgetter('name')
        )


class M2mThroughToFieldsTests(TestCase):
    def setUp(self):
        self.pea = Ingredient.objects.create(iname='pea')
        self.potato = Ingredient.objects.create(iname='potato')
        self.tomato = Ingredient.objects.create(iname='tomato')
        self.curry = Recipe.objects.create(rname='curry')
        RecipeIngredient.objects.create(recipe=self.curry, ingredient=self.potato)
        RecipeIngredient.objects.create(recipe=self.curry, ingredient=self.pea)
        RecipeIngredient.objects.create(recipe=self.curry, ingredient=self.tomato)

    def test_retrieval(self):
        # Forward retrieval
        self.assertQuerysetEqual(
            self.curry.ingredients.all(),
            [self.pea, self.potato, self.tomato], lambda x: x
        )
        # Backward retrieval
        self.assertEqual(self.tomato.recipes.get(), self.curry)

    def test_choices(self):
        field = Recipe._meta.get_field('ingredients')
        self.assertEqual(
            [choice[0] for choice in field.get_choices(include_blank=False)],
            ['pea', 'potato', 'tomato']
        )