Как обработать форму (через get или post) с помощью представлений на основе классов?

Я пытаюсь изучить представления на основе классов, поскольку представление деталей или списка не так уж сложно.

У меня есть форма поиска, и я просто хочу посмотреть, отправляю ли я запрос для отображения результатов.

Вот код функции (не мой, из книги django):

def search_page(request):
    form = SearchForm()
    bookmarks = []
    show_results = False
    if 'query' in request.GET:
        show_results = True
        query = request.GET['query'].strip()
        if query:
            form = SearchForm({'query': query})
            bookmarks = Bookmark.objects.filter(title__icontains=query)[:10]


    show_tags = True
    show_user = True

    if request.is_ajax():
        return render_to_response("bookmarks/bookmark_list.html", locals(), context_instance=RequestContext(request))
    else:
        return render_to_response("search/search.html", locals(), context_instance=RequestContext(request))

Игнорируя факт ajax (просто чтобы упростить проблему на данный момент), как я могу перевести это в представления на основе классов?

Я быстро попробовал что-то вроде этого:

class SearchPageView(FormView):
    template_name = 'search/search.html'

    def get(self, request, *args, **kwargs):
        form = SearchForm()
        self.bookmarks = []
        self.show_results = False
        if 'query' in self.request.GET:
            self.show_results = True
            query = self.request.GET['query'].strip()
            if query:
                form = SearchForm({'query': query})
                self.bookmarks = Bookmark.objects.filter(title__icontains=query)[:10]
        return super(SearchPageView, self).get(request, *args, **kwargs)

    def get_context_data(self, **kwargs):
        context = super(SearchPageView, self).get_context_data(**kwargs)
        context.update({
            'show_tags': True,
            'show_user': True,
            'show_results': self.show_results,
            'bookmarks': self.bookmarks
        })
        return context

Не работает, получаю: "Объект 'NoneType' не вызывается"

Честно говоря, я начал сегодня с этого материала.

Итак, как сделать представления на основе классов, которые могут управлять запросом на получение (и публикацию, если необходимо)?

У меня есть другой пример:

@render_to('registration/register.html')
def register_page(request):
    if request.method == 'POST':
        form = RegistrationForm(request.POST)
        if form.is_valid():
            user = User.objects.create_user(
                username=form.cleaned_data['username'],
                password=form.cleaned_data['password1'],
                email=form.cleaned_data['email']
            )
            return HttpResponseRedirect('/accounts/register/success/')
    else:
        form = RegistrationForm()
    return locals()

Будет ли это «преобразовано» так же, как и первое? Или они расширяют разные представления?

Я сильно запутался. Я не знаю, первый ли это ProcessFormView, а второй FormView или что.

Спасибо.

EDIT: Решение, которым я закончил:

class SearchPageView(FormView):
    template_name = 'search/search.html'

    def get(self, request, *args, **kwargs):
        self.bookmarks = []
        self.show_results = False
        form = SearchForm(self.request.GET or None)
        if form.is_valid():
            self.show_results = True
            self.bookmarks = Bookmark.objects.filter(title__icontains=form.cleaned_data['query'])[:10]

        return self.render_to_response(self.get_context_data(form=form))


    def get_context_data(self, **kwargs):
        context = super(SearchPageView, self).get_context_data(**kwargs)
        context.update({
            'show_tags': True,
            'show_user': True,
            'show_results': self.show_results,
            'bookmarks': self.bookmarks
        })
        return context

Я оставляю это здесь для тех, у кого такой же вопрос :)


person Jesus Rodriguez    schedule 18.01.2012    source источник
comment
Копирование и вставка 'NoneType' object is not callable" не очень помогает. Если вы посмотрите на номер строки в трассировке, вы увидите, какая строка кода вызывает исключение, что может помочь вам исправить это самостоятельно.   -  person Alasdair    schedule 18.01.2012
comment
Вопрос обновлен, вы были правы, мне нужно было лечь спать, и я подумал, что мне нужно указать свой класс формы, и да-да, вы были правы.   -  person Jesus Rodriguez    schedule 18.01.2012


Ответы (2)


Поведение по умолчанию FormView class должен отображать несвязанную форму для запросов GET и привязывать форму для запросов POST (или PUT). Если связанная форма действительна, то вызывается метод form_valid, который просто перенаправляет на URL-адрес успеха (определенный атрибутом success_url или методом get_success_url.

Это вполне соответствует примеру. Вам нужно переопределить метод form_valid, чтобы создать новый User, прежде чем вызывать метод суперкласса для перенаправления на URL-адрес успеха.

class CreateUser(FormView):
    template_name = 'registration/register.html'
    success_url = '/accounts/register/success/'
    form_class = RegistrationForm

    def form_valid(self, form):
        user = User.objects.create_user(
                username=form.cleaned_data['username'],
                password=form.cleaned_data['password1'],
                email=form.cleaned_data['email']
        )
        return super(CreateUser, self).form_valid(form)

Ваш первый пример не так хорошо соответствует потоку FormView, потому что вы не обрабатываете форму с данными POST и ничего не делаете, когда форма действительна.

Я мог бы попробовать расширить TemplateView и поместить всю логику в get_context_data. Как только вы заработаете, вы можете преобразовать код, который анализирует данные GET и возвращает закладки, в отдельный метод. Вы могли бы рассмотреть расширение ListView, но я не думаю, что есть какое-то реальное преимущество, если вы не хотите разбивать результаты на страницы.

person Alasdair    schedule 18.01.2012
comment
Этот пример работает как шарм (изменение имени атрибутов: P). Но я все еще думаю, что в первом примере нужно правильное представление представления на основе классов. - person Jesus Rodriguez; 18.01.2012
comment
Не могли бы вы помочь мне здесь. Когда вы определяете пользовательский объект, куда он идет после метода form_valid, для меня это как волшебство. - person izdi; 24.04.2014
comment
@skzd Боюсь, я не понимаю, что ты имеешь в виду. Если в моем ответе выше нет ошибки, пожалуйста, откройте новый вопрос вместо добавления комментария здесь. - person Alasdair; 24.04.2014
comment
@skzd, после запуска form_valid функция завершается, и страница перенаправляется на Success_url. И так до тех пор, пока не произойдет больше взаимодействия с пользователем. - person AdamG; 14.02.2016

Обратите внимание, ответ здесь (Обновление данных контекста в методе FormView form_valid?) решил эту проблему так:

class ContextFormView(FormView):
    template_name = 'some_template.html'
    success_url = '...'
    form_class = ClassOfTheForm

    def get(self, request, *args, **kwargs):
        form_class = self.get_form_class()
        form = self.get_form(form_class)
        context = self.get_context_data(**kwargs)
        context['form'] = form
        return self.render_to_response(context)

    def post(self, request, *args, **kwargs):
        form_class = self.get_form_class()
        form = self.get_form(form_class)
        if form.is_valid():
            return self.form_valid(form, **kwargs)
        else:
            return self.form_invalid(form, **kwargs)


    def form_invalid(self, form, **kwargs):
        context = self.get_context_data(**kwargs)
        context['form'] = form
        # here you can add things like:
        context[show_results] = False
        return self.render_to_response(context)

    def form_valid(self, form, **kwargs):
        context = self.get_context_data(**kwargs)
        context['form'] = form
        # here you can add things like:
        context[show_results] = True
        return self.render_to_response(context)

Это сработало идеально для меня. (та же проблема, что и в этом вопросе)

Как указано выше, это не мое решение, если вы хотите отдать кому-то кредиты, перейдите к ответу по ссылке и дайте этому человеку кредиты! (Обновление данных контекста в методе FormView form_valid?)

person michel.iamit    schedule 03.01.2015
comment
Могу ли я с помощью этого подхода объединить общие ListView и FormView на одной странице? Так что у меня есть список записей из базы данных И форма на одной странице шаблона. Просто замена класса ListView на FormView, а затем переопределение метода get не работает, в качестве контекста передается только форма, представление передается как <scraping.views.HomePageView object at 0x109ebd070> - person ruslaniv; 09.08.2020