Получение RelatedObjectDoesNotExist ошибка доступа к полю в пользовательской форме

#python #python-3.x #django

#python #python-3.x #django

Вопрос:

Я относительно новичок в Django (и python в целом), и я работаю над проектом, который я не кодировал сам.

В частности, я пытаюсь сохранить некоторую информацию из формы через POST , но я получаю RelatedObjectDoesNotExist сообщение об ошибке при доступе к user полю, определенному в моей пользовательской Profile модели, и я не понимаю, почему.

Вот мой views.py :

 def conferma(request):
    family = request.user.profile.family  # cannot be null
    already_confirmed = request.user.profile.conferma_inviata

    if(already_confirmed == False):

        ProfileFormSet = modelformset_factory(
            Profile, form=ConfirmForm, extra=0)

        if request.method == 'POST':
            formset = ProfileFormSet(
                request.POST, queryset=Profile.objects.filter(family=family))
            if formset.is_valid():
                for form in formset:
                    f = form.save(commit=False)
                    f.conferma_inviata = True
                    f.save()
  

Если я пытаюсь получить доступ f.user , я получаю RelatedObjectDoesNotExist сообщение об ошибке, и мне нужна эта информация для сохранения формы.

Вот мой forms.py:

 class ConfirmForm(forms.ModelForm):
    class Meta:
        model = Profile
        fields = ('user', 'conferma_pranzo',
                  'conferma_sera', 'conferma_inviata',)

    def __init__(self, *args, **kwargs):
        super(ConfirmForm, self).__init__(*args, **kwargs)
        self.fields['user'].required = False
        self.fields['conferma_inviata'].required = False
  

Вот мой models.py :

 class Profile(models.Model):
    user = models.OneToOneField(User, on_delete=models.CASCADE)
    full_day = models.BooleanField(default=True)
    family = models.TextField(max_length=100, blank=True)
    conferma_pranzo = models.BooleanField(default=False)
    conferma_sera = models.BooleanField(default=False)
    conferma_inviata = models.BooleanField(default=False)

    def __str__(self):
        return self.user.first_name   ' '   self.user.last_name
  

Я уже проверил базу данных, но Profile записи правильно сохранены с правильной userd_id ссылкой.

Что я делаю не так?

РЕДАКТИРОВАТЬ Это трассировка, когда я пытаюсь просмотреть user поле в форме с помощью инспектора переменных отладчика:

 Traceback (most recent call last):
  File "/home/simone/.vscode/extensions/ms-python.python-2020.9.114305/pythonFiles/lib/python/debugpy/_vendored/pydevd/_pydevd_bundle/pydevd_resolver.py", line 193, in _get_py_dictionary
    attr = getattr(var, name)
  File "/home/simone/.local/lib/python3.7/site-packages/django/db/models/fields/related_descriptors.py", line 198, in __get__
    "%s has no %s." % (self.field.model.__name__, self.field.name)
invitations.models.Profile.user.RelatedObjectDoesNotExist: Profile has no user.
  

Ответ №1:

Обратные отношения OneToOneField выдают ошибки в django, когда отношение не существует (в отличие от ForeignKeys, которые возвращают тип None).

Без обратной трассировки я не совсем уверен, где у вас ошибка, однако что-то вроде этого может помочь:

models.py:

 from django.db import IntegrityError

class Profile(models.Model):

    # add related name argument to user field for reverse accessing:
    user = models.OneToOneField(User, on_delete=models.CASCADE, related_name='user_profile')
    ...

class User(...):
    ...
    
    # return a None type when a reverse relation does not exist (instead of an IntegrityError)
    @property
    def profile(self): 
        try: return self.user_profile
        except IntegrityError: return None
  

views.py:

 def conferma(request):

    # do something if the user has a profile:
    if request.user.profile:
        ...

    # do something else if the user does not have a profile:
    else:
        ...
  

Комментарии:

1. Привет, Даниэль, спасибо за ваш ответ! Я приложил точную обратную трассировку в исходном сообщении. Я не понимаю, почему я получаю эту ошибку, поскольку я пытаюсь получить доступ к пользователю из формы профиля. Профиль в request.user присутствует (а также с атрибутом user), но меня интересуют профили набора форм, которые не содержат пользователей.

Ответ №2:

Из того, что я понял до сих пор user , данные не отправляются в POST внутри Profile in the ConfirmForm .

Это шаблон, из которого поступает сообщение:

     <form method="post">
        {% csrf_token %}
        {{ formset.management_form }}
        <table align="center" class="w3-table-all" style="width:100%; max-width:400px">

            <tr>
                <th>Nome</th>
                {% if user.profile.full_day %}
                <th class="w3-center">Conferma pranzo</th>
                {% endif %}
                <th class="w3-center">Conferma sera (dalle 18:30)</th>

            </tr>
            {% for form in formset %}

            <tr>
                <td>{{ form.instance.user.first_name }}</td>
                {% if user.profile.full_day %}
                <td class="w3-center">{{ form.conferma_pranzo }}</td>
                {% endif %}
                <td class="w3-center">{{ form.conferma_sera }}</td>

                {{form.id}}
            </tr>
            {% endfor %}
        </table>
        <br>
        <input type="submit" value="Invia conferma">
      </form>
  

Как я могу добавить эту информацию?