Django: Model Form „obiekt nie ma atrybutu„ wyczyszczone_dane ””

86

Próbuję zrobić formularz wyszukiwania dla jednego z moich zajęć. Model formularza to:

from django import forms
from django.forms import CharField, ModelMultipleChoiceField, ModelChoiceField
from books.models import Book, Author, Category

class SearchForm(forms.ModelForm):
    authors = ModelMultipleChoiceField(queryset=Author.objects.all(),required=False)    
    category = ModelChoiceField (queryset=Category.objects.all(),required=False)
    class Meta:
        model = Book
        fields = ["title"]

Widok, którego używam, to:

from django.shortcuts import render_to_response, redirect, get_object_or_404
from django.template import RequestContext
from books.models import Book,Author
from books.forms import BookForm, SearchForm
from users.models import User

def search_book(request):
    if request.method == "POST":
        form = SearchForm(request.POST)
        if form.is_valid():
            form = SearchForm(request.POST)
            stitle = form.cleaned_data['title']
            sauthor = form.cleaned_data['author']
            scategory = form.cleaned_data['category']
    else:
        form = SearchForm()
    return render_to_response("books/create.html", {
        "form": form,
    }, context_instance=RequestContext(request))

Formularz wygląda dobrze, ale kiedy go przesyłam, pojawia się błąd: 'SearchForm' object has no attribute 'cleaned_data'

Nie jestem pewien, co się dzieje, czy ktoś może mi pomóc? Dzięki!

Józef
źródło
8
Po co dzwonić form = SearchForm(request.POST)dwa razy?
hughdbrown
@SafwanSamsudeen Mój komentarz mówi to samo, co odpowiedź, która została zaakceptowana jako poprawna 10 lat temu. Problem w rzeczywistości polega na tym, że kod nie powinien wywoływać SearchForm po raz drugi.
hughdbrown

Odpowiedzi:

184

Z jakiegoś powodu po sprawdzeniu ponownie tworzysz wystąpienie formularza is_valid(). Formularze uzyskują cleaned_dataatrybut tylko wtedy, gdy is_valid()został wywołany, a nie wywołałeś go w tej nowej, drugiej instancji.

Po prostu pozbądź się drugiego form = SearchForm(request.POST)i wszystko powinno być dobrze.

Daniel Roseman
źródło
7

Napisałbym taki kod:

def search_book(request):
    form = SearchForm(request.POST or None)
    if request.method == "POST" and form.is_valid():
        stitle = form.cleaned_data['title']
        sauthor = form.cleaned_data['author']
        scategory = form.cleaned_data['category']
        return HttpResponseRedirect('/thanks/')
    return render_to_response("books/create.html", {
        "form": form,
    }, context_instance=RequestContext(request))

Prawie jak dokumentacja .

hughdbrown
źródło
Cóż, to działa! Czy definicja lokalizacji formy ma tak duże znaczenie?
Joseph
Nie wiem, na czym polegał Twój problem, ale myślę, że SearchForm(request.POST)dwukrotne dzwonienie nie było konieczne. Reszta to tylko dekoracja okien: tak się składa, że ​​podoba mi się ten sposób składania argumentów konstrukcji formularza, aby wystarczyło tylko jedno wywołanie.
hughdbrown
Albo dokładnie to, co powiedział @Daniel Roseman. Na twoim miejscu wybrałbym jego odpowiedź jako preferowaną, ponieważ on określa dokładną przyczynę.
hughdbrown
2

Czasami, jeśli zapomnimy o

return self.cleaned_data 

w czystej funkcji formularzy django nie będziemy mieli żadnych danych, chociaż form.is_valid()zwrócą True.

subramanyam
źródło