Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Django - Limit choices to something that depends on the instance

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?

like image 599
Andrea Avatar asked Oct 06 '11 10:10

Andrea


People also ask

How do I restrict foreign keys choices to related objects only in Django?

Update: ForeignKey. limit_choices_to allows to specify either a constant, a callable or a Q object to restrict the allowable choices for the key.

What does @property do in Django?

In Python, the @property decorator allows you to call custom model methods as if they were normal model attributes. For example, if you have the following greeting method, class Person: def __init__(self, first_name): self.

What is the class of instance object in Django?

The two main concepts of OOP are classes and objects: Class: Class is basically a blueprint or a template for creating objects. Object: Collection of arguments and methods which can be performed on those data. An object is nothing but an instance of the class.

What is choices in Django model?

Choices limits the input from the user to the particular values specified in models.py . If choices are given, they're enforced by model validation and the default form widget will be a select box with these choices instead of the standard text field.


1 Answers

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'
    )
like image 67
Marat Avatar answered Sep 19 '22 13:09

Marat