web-dev-qa-db-fra.com

Comment traiter un formulaire (via get ou post) à l'aide de vues basées sur les classes?

Im essayant d'apprendre des vues basées sur la classe, pour une vue de détail ou de liste n'est pas si compliquée.

J'ai un formulaire de recherche et je veux juste voir si j'envoie une requête pour afficher les résultats.

Voici le code de la fonction (n'est pas le mien, provient d'un livre 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))

Ignorant le fait ajax (juste pour faciliter le problème pour l'instant), comment puis-je traduire cela en vues basées sur les classes?

J'ai rapidement essayé quelque chose comme ça:

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

Ne fonctionne pas, j'obtiens un: "L'objet 'NoneType' n'est pas appelable"

Très bien, j'ai commencé aujourd'hui avec ce genre de choses.

Alors, quelle est la façon de créer une vue basée sur la classe qui peut gérer une requête get (et une publication aussi si nécessaire)?

J'ai un autre exemple:

@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()

Serait-ce "transformé" de la même manière que le premier? Ou étendent-ils des vues différentes?

Je suis beaucoup confus. Je ne sais pas si le premier est ProcessFormView et le second FormView ou quoi.

Merci.

EDIT: Solution que j'ai terminée avec:

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

Je laisse ceci ici à quelqu'un avec la même question :)

34
Jesus Rodriguez

Le comportement par défaut de la classe FormView consiste à afficher un formulaire indépendant pour les demandes GET et à lier le formulaire pour POST (ou PUT) demandes. Si le formulaire lié est valide, le form_valid est appelée, qui redirige simplement vers l'URL de réussite (définie par le success_url l'attribut ou get_success_url méthode.

Cela correspond assez bien à l'exemple. Vous devez remplacer le form_valid méthode pour créer la nouvelle User, avant d'appeler la méthode superclasse pour rediriger vers l'URL de réussite.

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)

Votre premier exemple ne correspond pas si bien au flux de FormView, car vous ne traitez pas un formulaire avec des données POST et vous ne faites rien lorsque le formulaire est valide.

Je pourrais essayer d'étendre TemplateView et de mettre toute la logique dans get_context_data. Une fois que cela fonctionne, vous pouvez factoriser le code qui analyse les données GET et renvoie les signets dans sa propre méthode. Vous pouvez envisager d'étendre ListView, mais je ne pense pas qu'il y ait un réel avantage, sauf si vous souhaitez paginer les résultats.

28
Alasdair

Remarque, une réponse ici ( Mise à jour des données de contexte dans la méthode FormView form_valid? ) a résolu ce problème comme ceci:

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)

Cela a fonctionné parfaitement pour moi. (même problème que dans cette question)

Comme indiqué ci-dessus, ce n'est pas ma solution, si vous voulez donner des crédits à quelqu'un, allez à la réponse dans le lien et donnez à cette personne les crédits! ( Mise à jour des données de contexte dans la méthode FormView form_valid? )

9
michel.iamit