Add support for custom to_field names for foreign keys (#486)

Django's ForeignKey supports custom to_fields. The to field is the
primary key by default, but can be modified. The to field is also
used by forms to reduce database lookups.

This patch add support for custom to_field names on both model or
form layer.
This commit is contained in:
Johannes Hoppe 2018-06-30 14:56:32 +02:00 committed by GitHub
parent 496cc7c502
commit f31beec0c4
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 27 additions and 7 deletions

View file

@ -444,11 +444,12 @@ class ModelSelect2Mixin(object):
c for c in selected_choices
if c not in self.choices.field.empty_values
}
choices = (
(obj.pk, self.label_from_instance(obj))
for obj in self.choices.queryset.filter(pk__in=selected_choices)
)
for option_value, option_label in choices:
field_name = self.choices.field.to_field_name or 'pk'
query = Q(**{'%s__in' % field_name: selected_choices})
for obj in self.choices.queryset.filter(query):
option_value = self.choices.choice(obj)[0]
option_label = self.label_from_instance(obj)
selected = (
str(option_value) in value and
(has_selected is False or self.allow_multiple_selected)

View file

@ -22,7 +22,7 @@ from tests.testapp import forms
from tests.testapp.forms import (
NUMBER_CHOICES, HeavySelect2MultipleWidgetForm, TitleModelSelect2Widget
)
from tests.testapp.models import City, Country, Genre
from tests.testapp.models import Artist, City, Country, Genre, Groupie
try:
from django.urls import reverse
@ -362,6 +362,12 @@ class TestModelSelect2Mixin(TestHeavySelect2Mixin):
widget = ModelSelect2Widget(queryset=Genre.objects.all(), search_fields=['title__icontains'])
assert isinstance(widget.get_url(), text_type)
def test_custom_to_field_name(self):
the_best_band_in_the_world = Artist.objects.create(title='Take That')
groupie = Groupie.objects.create(obsession=the_best_band_in_the_world)
form = forms.GroupieForm(instance=groupie)
assert '<option value="Take That" selected>TAKE THAT</option>' in form.as_p()
class TestHeavySelect2TagWidget(TestHeavySelect2Mixin):

View file

@ -195,3 +195,12 @@ class AddressChainedSelect2WidgetForm(forms.Form):
max_results=500,
)
)
class GroupieForm(forms.ModelForm):
class Meta:
model = models.Groupie
fields = '__all__'
widgets = {
'obsession': ArtistCustomTitleWidget
}

View file

@ -12,7 +12,7 @@ class Genre(models.Model):
class Artist(models.Model):
title = models.CharField(max_length=50)
title = models.CharField(max_length=50, unique=True)
genres = models.ManyToManyField(Genre)
class Meta:
@ -56,3 +56,7 @@ class City(models.Model):
def __str__(self):
return self.name
class Groupie(models.Model):
obsession = models.ForeignKey(Artist, to_field='title', on_delete=models.CASCADE)