Предварительный просмотр формы Django - Как работать с 'cleaned_data' - PullRequest
3 голосов
/ 10 марта 2009

Спасибо Инсину за ответ на предыдущий вопрос , связанный с этим.

Его ответ сработал и работает хорошо, однако я озадачен предоставлением 'cleaned_data', или, точнее, как его использовать?

class RegistrationFormPreview(FormPreview):
    preview_template    = 'workshops/workshop_register_preview.html'
    form_template       = 'workshops/workshop_register_form.html'

    def done(self, request, cleaned_data):
        # Do something with the cleaned_data, then redirect
        # to a "success" page. 

        registration            = Registration(cleaned_data)
        registration.user       = request.user
        registration.save()
        # an attempt to work with cleaned_data throws the error: TypeError 
        # int() argument must be a string or a number, not 'dict'
        # obviously the fk are python objects(?) and not fk_id
        # but how to proceed here in an easy way?



        # the following works fine, however, it seems to be double handling the POST data
        # which had already been processed in the django.formtools.preview.post_post
        # method, and passed through to this 'done' method, which is designed to 
        # be overidden.
        '''
        form                    = self.form(request.POST)   # instansiate the form with POST data
        registration            = form.save(commit=False)   # save before adding the user
        registration.user       = request.user              # add the user
        registration.save()                                 # and save.
        '''

        return HttpResponseRedirect('/register/success')

Для быстрого ознакомления, вот содержание метода post_post:

def post_post(self, request):
    "Validates the POST data. If valid, calls done(). Else, redisplays form."
    f = self.form(request.POST, auto_id=AUTO_ID)
    if f.is_valid():
        if self.security_hash(request, f) != request.POST.get(self.unused_name('hash')):
            return self.failed_hash(request) # Security hash failed.
        return self.done(request, f.cleaned_data)
    else:
        return render_to_response(self.form_template,
            {'form': f, 'stage_field': self.unused_name('stage'), 'state': self.state},
            context_instance=RequestContext(request))

1 Ответ

9 голосов
/ 10 марта 2009

Я никогда не пробовал то, что вы делаете здесь с ModelForm, но вы могли бы использовать оператор **, чтобы расширить ваш словарь cleaned_data в аргументы ключевого слова, ожидаемые для вашего конструктора регистрации:

   registration = Registration (**cleaned_data)

Конструктор классов вашей модели принимает аргументы ключевых слов, которые метакласс Django преобразует в атрибуты уровня экземпляра полученного объекта. Оператор ** - это соглашение о вызовах, которое указывает Python расширить ваш словарь на эти ключевые аргументы.

Другими словами ...

То, что вы делаете в настоящее время, равносильно этому:

registration = Registration ({'key':'value', ...})

Это не то, что вам нужно, потому что конструктор ожидает аргументы ключевого слова, а не словарь, содержащий аргументы вашего ключевого слова.

То, что вы хотите сделать, это

registration = Registration (key='value', ...)

Что аналогично этому:

registration = Registration (**{'key':'value', ...})

Опять же, я никогда не пробовал этого, но похоже, что это будет работать, если вы не делаете ничего необычного с вашей формой, например, добавляете в нее новые атрибуты, которые не ожидаются вашим конструктором Registration. В этом случае вам, вероятно, придется изменить элементы в словаре cleaned_data, прежде чем делать это.

Похоже, что вы теряете некоторые функции, присущие ModelForms, хотя и проходите через утилиту предварительного просмотра форм. Возможно, вам следует перенести ваш вариант использования в список рассылки Django и посмотреть, есть ли потенциальное усовершенствование этого API, которое могло бы улучшить его работу с ModelForms.

Редактировать

Если не считать того, что я описал выше, вы всегда можете просто извлечь поля из словаря cleaned_data «вручную» и передать их в конструктор регистрации, но с оговоркой, которую вы должны помнить, чтобы обновить этот код как Вы добавляете новые поля в вашу модель.

registration = Registration (
    x=cleaned_data['x'],
    y=cleaned_data['y'],
    z=cleaned_data['z'],
    ...
)
...