Django - Limit choices to something that depends o

2019-04-23 06:53发布

I have some foos which are organized into categories. For each category, I want to be able to select a winner foo.

Hence I have models which look like this:

class Category(models.Model):
    name = models.CharField(max_length=30)
    # More fields...
    winner = models.ManyToManyField(
        'Foo',
        related_name='winner'
    )

class Foo(models.Model):
    name = models.CharField(max_length=30)
    # More fields...
    category = models.ForeignKey(
        Category,
        related_name='category'
    )

(The reason why winner is a ManyToManyField is that a single foo may belong to several categories, while in a single category there may be more than one winner due to ex-aequo.)

I want to impose the natural constraint that a foo can win in a category only if it belongs to that category. The most reasonable way to do so seems to use the limit_choices_to parameter, but it seems to me that it is not possible to limit the choices based on the current instance of the model.

I may be able to impose this constraint in a given form, but I would like to avoid this for two reasons:

  • the constraint naturally lives at the model level. It is a particular relation that should always hold between two related models
  • the choice of the winner will be made in the admin, and I would like to avoid having to customize the admin forms

Is there any way to impose this constraint in Django?

1条回答
干净又极端
2楼-- · 2019-04-23 07:49

There is no way to put constraint on M2M field on the models level (ie with limit_choices_to). However, you can do this in the form:

class MyForm(forms.ModelForm):
    class Meta:
        model = models.Category

    def __init__(self, *args, **kwargs):
        super(MyForm, self).__init__(*args, **kwargs)
        if 'instance' in kwargs:
            my_category = kwargs['instance']
            self.fields['winner'].queryset = my_category.category.all()

Well, did you notice that?

my_category.category.all()

Probably what you want is:

class Foo(models.Model):
    name = models.CharField(max_length=30)
    # More fields...
    category = models.ForeignKey(
        Category,
        related_name='participants'
    )
查看更多
登录 后发表回答