Model.ManyToManyField.all() gives AttributeError:

2019-08-01 15:47发布

I'm using Django 2.0.2, Python 3.6.4 and PyCharm 2017.3.3

Models: (in models.py)

class Position(models.Model):
    title = models.CharField(max_length=50)
    gang = models.ForeignKey(Gang, on_delete=models.CASCADE)
    description = models.TextField(max_length=20000)

    def __str__(self):
        return str(self.title) + ', ' + str(self.gang)

class Application(models.Model):
    positions = models.ManyToManyField(Position)
    applicant = models.ForeignKey(User, on_delete=models.CASCADE)

class Ranking(models.Model):
    position = models.ForeignKey(Position, on_delete=models.CASCADE)
    applicant = models.ForeignKey(User, on_delete=models.CASCADE)
    rank = models.IntegerField(default=3,validators=[
            MaxValueValidator(3),
            MinValueValidator(1)
        ])

Form: (in forms.py)

class RankingForm(forms.ModelForm):
    rank = forms.IntegerField(max_value=3, min_value=1)
    position = forms.ModelMultipleChoiceField(queryset=Application.positions.all())

    class Meta:
        model = Ranking
        exclude = ['applicant']
        fields = ('rank', 'position')

    def __init__(self, *args, **kwargs):
        super(RankingForm, self).__init__(*args, **kwargs)
        self.fields['rank'].widget.attrs.update({'class': 'form-control'})

I keep getting the AttributeError in RankingForm from

"position = forms.ModelMultipleChoiceField(queryset=Application.positions.all())"

When i write

class Application(models.Model):
    ... 

    def __str__(self):
        return str(self.positions.all())

it shows in django-admin as a QuerySet (which works for forms.ModelMultipleChoiceField()), but writing

    class Application(models.Model):
    ... 

    def __str__(self):
        return str(Application.positions.all())

gives me the same error: 'ManyToManyDescriptor' object has no attribute 'all'

Writing

    class RankingForm(forms.ModelForm):
        ...
        position = forms.ModelMultipleChoiceField(queryset=Position.objects.all())

works, but this is not what i want the field to display.

I want to make a ModelMultipleChoiceField() with all the positions from a specific application, but this error keeps getting in the way. It seems that just referencing a model doesn't work, but referencing self does?? Any help is greatly appreciated! :)

Btw, I haven't found any good documentation on this problem, but this seems to be the code for related_descriptors.py where ManyToManyDescriptor is located

2条回答
对你真心纯属浪费
2楼-- · 2019-08-01 16:30

You can access the current instance of your model that the ModelForm object is working with using the instance attribute. You can then use it to create the correct queryset in __init__:

class RankingForm(forms.ModelForm):
    ...

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.fields['rank'].widget.attrs.update({'class': 'form-control'})
        self.fields['position'].queryset = self.instance.positions.all()
查看更多
等我变得足够好
3楼-- · 2019-08-01 16:53

Evaluating relationships are done with an instance that is an initialized instance of the class.

An instance of the Application.

application = Application.objects.first()
application.positions.all()

Change the form queryset after initialization.

class RankingForm(forms.ModelForm):
    rank = forms.IntegerField(max_value=3, min_value=1)
    position = forms.ModelMultipleChoiceField(queryset=Positions.objects.none())

    class Meta:
        model = Ranking
        exclude = ['applicant']
        fields = ['rank', 'position']

    def __init__(self, *args, **kwargs):
        super(RankingForm, self).__init__(*args, **kwargs)
        self.fields['rank'].widget.attrs.update({'class': 'form-control'})  
        self.fields['position'].queryset = self.instance.positions.all()
查看更多
登录 后发表回答