Невозможно понять, как ModelForm отображается с использованием универсального UpdateView - PullRequest
0 голосов
/ 19 мая 2018

Я пытаюсь выяснить, как создается экземпляр ModelForm, когда я использую универсальный UpdateView.

Я просмотрел исходный код django и изучил UpdateView и соответствующие Form классы, но я не вижу ни одной строки кода, где мы явно передаем instance объекту ModelForm класса.

Например, скажем, у нас есть PostForm как ModelForm, тогда мы бы написали:

form = PostForm(instance=Post.object.get(pk=pk))

для визуализации формы из объекта моделей.

Я не вижу подобного кода в исходном коде django и не могу понять, как универсальный ModelForm заполняется в случае UpdateView, т. Е. Как создается атрибут self.instance моей формы при отправке данныхпосле размещения формы.

Ответы [ 2 ]

0 голосов
/ 20 мая 2018

Атрибут instance ModelForm создается в get_form_kwargs(), определенном в ModelFormMixin

Подробное объяснение см. Ниже:

Представление UpdateView наследует SingleObjectTemplateResponseMixin, BaseUpdateView

BaseUpdateView далее наследует ModelFormMixin и ProcessFormView
Он также определяет get и post методы, которые вызываются с помощью диспетчерских
Эти get и post методовустанавливает атрибут object в качестве объекта текущей модели.Ниже приведен фрагмент кода из документации django:

class BaseUpdateView(ModelFormMixin, ProcessFormView):
    """
    Base view for updating an existing object.

    Using this base class requires subclassing to provide a response mixin.
    """
    def get(self, request, *args, **kwargs):
        self.object = self.get_object()
        return super(BaseUpdateView, self).get(request, *args, **kwargs)

    def post(self, request, *args, **kwargs):
        self.object = self.get_object()
        return super(BaseUpdateView, self).post(request, *args, **kwargs)

Методы get и post также вызывают метод get и post родителя, т. Е. Get и post, определенные в ProcessFormView

Во времяЗапрос GET
Метод get, определенный в ProcessFormView, вызывает get_context_data(), переопределенный в FormMixin, который дополнительно вызывает get_form() для возврата экземпляра формы, которая будет использоваться в представлении.

def get_context_data(self, **kwargs):
    """
    Insert the form into the context dict.
    """
    if 'form' not in kwargs:
        kwargs['form'] = self.get_form()
    return super(FormMixin, self).get_context_data(**kwargs)

get_form() вызывает get_form_kwargs(), который лежит в ModelFormMixin, а также FormMixin, но поскольку ModelFormMixin наследуется от FormMixin, метод, определенный в ModelFormMixin, переопределяет метод, определенный вFormMixin.Этот метод get_form_kwargs() сначала вызывает метод super / parent, а затем устанавливает атрибут instance формы для объекта текущей модели, то есть self.object (или просто object).
Фрагмент кода из документов ниже:

def get_form_kwargs(self): #defined in ModelFormMixin class
    """
    Returns the keyword arguments for instantiating the form.
    """
    kwargs = super(ModelFormMixin, self).get_form_kwargs()
    if hasattr(self, 'object'):
        kwargs.update({'instance': self.object})
    return kwargs

Затем форма отображается с использованием атрибутов объекта модели

Во время запроса POST:
Как упоминалось ранее (см. Первый фрагмент кода), какМетод get(), post() также устанавливает атрибут object для объекта текущей модели, т.е. self.object=self.get_object().(get_object () наследуется от SingleObjectMixin класса)
Затем он вызывает post метод ProcessFormView, то есть родительский класс, который создает экземпляр form с использованием метода get_form().(Точно так же, как get_context_method в случае get запроса) get_form() вызывает get_form_kwargs, который дополнительно устанавливает атрибут instance формы для self.object, созданного при первом вызове метода post.
Фрагмент кода ниже:

class ProcessFormView(View):
"""
A mixin that renders a form on GET and processes it on POST.
"""
def get(self, request, *args, **kwargs):
    """
    Handles GET requests and instantiates a blank version of the form.
    """
    return self.render_to_response(self.get_context_data())

def post(self, request, *args, **kwargs):
    """
    Handles POST requests, instantiating a form instance with the passed
    POST variables and then checked for validity.
    """
    form = self.get_form()
    if form.is_valid():
        return self.form_valid(form)
    else:
        return self.form_invalid(form)

# PUT is a valid HTTP verb for creating (with a known URL) or editing an
# object, note that browsers only support POST for now.
def put(self, *args, **kwargs):
    return self.post(*args, **kwargs)

Затем форма проверяется на соответствие основным ограничениям, и это делается путем вызова метода form.is_valid(), который унаследован от класса BaseForm.Это очень важный шаг, поскольку в этот момент атрибуты объекта instance обновляются до данных, отправленных в форме.

Все это достигается с помощью следующего стека вызовов:

form.is_valid() вызывает -> errors свойство -> которое вызывает full_clean() -> _clean_fields() -> _clean_form() -> _post_clean()
_post_clean() создает данные instance из POST путем вызова construct_instance_method

Чтобы понять эти функции, лучше прочитайте класс BaseForm для is_valid() здесь и BaseModelForm класс для _post_clean() здесь

0 голосов
/ 20 мая 2018

Я думаю, вы, возможно, ищете метод FormMixin.get_form_kwargs().

Вот источник из Github репо :

def get_form_kwargs(self):
    ...
    if self.request.method in ('POST', 'PUT'):
        kwargs.update({
            'data': self.request.POST,
            'files': self.request.FILES,
        })
    return kwargs

Как вы можете видеть, если запрос POST, данные из POST и FILES возвращаются из этого метода, который, в свою очередь, используется для создания экземпляра формы, как вы можете видеть во втором фрагменте ниже из того же источник :

def get_form(self, form_class=None):
    ...
    return form_class(**self.get_form_kwargs())
...