Model.ManyToManyField.all () дает AttributeError: объект «ManyToManyDescriptor» не имеет атрибута «все»

Я использую Django 2.0.2, Python 3.6.4 и PyCharm 2017.3.3.

Модели: (в 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)
        ])

Форма: (в 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'})

Я продолжаю получать AttributeError в RankingForm от

"позиция = формы.ModelMultipleChoiceField(queryset=Application.positions.all())"

когда я пишу

class Application(models.Model):
    ... 

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

он отображается в django-admin как QuerySet (который работает для форм.ModelMultipleChoiceField()), но запись

    class Application(models.Model):
    ... 

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

дает мне ту же ошибку: объект «ManyToManyDescriptor» не имеет атрибута «все»

Пишу

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

работает, но это не то, что я хочу отображать в поле.

Я хочу создать ModelMultipleChoiceField() со всеми позициями из определенного приложения, но эта ошибка продолжает мешать. Кажется, что просто ссылка на модель не работает, но ссылка на себя работает ?? Любая помощь приветствуется! :)

Кстати, я не нашел хорошей документации по этой проблеме, но это кажется кодом для related_descriptors.py, где находится ManyToManyDescriptor


person Pederduel    schedule 25.03.2018    source источник
comment
Ваш вопрос сбивает с толку. Вы знаете рабочий синтаксис, используя себя, так почему вы пытаетесь использовать другую версию?   -  person Daniel Roseman    schedule 26.03.2018
comment
Вам нужен экземпляр приложения, и вы не можете использовать свойство класса, который не инициализирован.   -  person jackotonye    schedule 26.03.2018
comment
У вас должно быть self.positions.all(), а не Application.positions.all() self ссылки на экземпляр приложения. Для формы набор запросов должен оцениваться при инициализации не на уровне класса, т.е. position = forms.ModelMultipleChoiceField(queryset=Positions.objects.none())   -  person jackotonye    schedule 26.03.2018
comment
@DanielRoseman, что вы имеете в виду под другой версией?   -  person Pederduel    schedule 26.03.2018
comment
@jackotonye Да, я хочу сослаться на экземпляр приложения, но как мне это сделать, когда я нахожусь в forms.py?   -  person Pederduel    schedule 26.03.2018


Ответы (2)


Оценка отношений выполняется с экземпляром, который является инициализированным экземпляром класса.

Экземпляр приложения.

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

Измените набор запросов формы после инициализации.

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()
person jackotonye    schedule 25.03.2018
comment
Спасибо! Теперь, когда я думаю об этом, мой вопрос на самом деле сводился только к тому, как создать экземпляр модели, ха-ха. - person Pederduel; 26.03.2018
comment
Но мне нужно создать экземпляр модели для конкретного пользователя, просматривающего форму. Любая помощь в этом? - person Pederduel; 26.03.2018
comment
Экземпляры создаются после того, как пользователь сохраняет форму, представление редактирования ссылается на сохраненный экземпляр формы. - person jackotonye; 26.03.2018

Вы можете получить доступ к текущему экземпляру вашей модели, с которым работает объект ModelForm, используя атрибут instance. Затем вы можете использовать его для создания правильного набора запросов в __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()
person Blender    schedule 25.03.2018