3

Let me start by saying that I am working with a legacy database so avoiding the custom intermediate table is not an option.

I'm looking for an alternative way to get the limit_choices_to functionality as I need to only present the options flagged by the sample_option boolean in the Sampletype Model in my ModelForm:

class PlanetForm(ModelForm):
    class Meta:
        model = Planet
        fields = ['name', 'samples']

Here is a simplified view of my models

class Planet(models.Model):
    name= models.CharField(unique=True, max_length=256)
    samples = models.ManyToManyField('Sampletype', through='Sample')

class Sample(models.Model):
    planet = models.ForeignKey(Planet, models.DO_NOTHING)
    sampletype = models.ForeignKey('Sampletype', models.DO_NOTHING)

class Sampletype(models.Model):
    name = models.CharField(unique=True, max_length=256)
    sample_option = models.BooleanField(default=True)

Sample is the intermediate table. Normally, if the project had been started with Django in the first place, I could just define the ManyToManyField declaration as:

samples = models.ManyToManyField('Sampletype', limit_choices_to={'sample_option'=True})

But this is not an option.. So how do I get this functionality ? Django clearly states in their documentation that:

limit_choices_to has no effect when used on a ManyToManyField with a custom intermediate table specified using the through parameter.

But they offer no information on how to get that limit in place when you DO have a custom intermediate table.

I tried setting the limit_choices_to option on the ForeignKey in the Sample Model like so:

sampletype = models.ForeignKey('Sampletype', models.DO_NOTHING, limit_choices_to={'sample_option': True})

but that had no effect.

Strangely, I find no answer to this on the web and clearly other people must have to do this in their projects so I'm guessing the solution is really simple but I cannot figure it out.

Thanks in advance for any help or suggestions.

1 Answers1

2

You could set the choices in the __init__ method of the form:

class PlanetForm(ModelForm):

    class Meta:
        model = Planet
        fields = ['name', 'samples']

    def __init__(self, *args, **kwargs):
         super(PlanetForm, self).__init__(*args, **kwargs)

         sample_choices = list(
             Sampletype.objects.filter(sample_option=True).values_list('id', 'name')
         )
         # set these choices on the 'samples' field.
         self.fields['samples'].choices = sample_choices
AKS
  • 18,983
  • 3
  • 43
  • 54
  • 1
    Thank you ! As I suspected, the answer was simple ! I'm a bit new to Django (as you might have figured out).. Can you link the section in the documentation where I might have found information on manually updating the choices offered by a ModelChoiceField ? I had tried setting the values through the queryset parameter but could not get it to work. – JPLaverdure Mar 31 '17 at 16:36
  • 1
    I think you could also set the queryset. Look here: https://docs.djangoproject.com/en/1.10/ref/forms/fields/#fields-which-handle-relationships – AKS Apr 01 '17 at 05:26
  • @AKS agreed, queryset is the better method – tread Oct 31 '17 at 12:48