Django Forms: si non valide, afficher le formulaire avec un message d'erreur

112

Je Django formulaires, il peut vérifier si le formulaire est valide:

if form.is_valid(): 
    return HttpResponseRedirect('/thanks/')

Mais je manque quoi faire si ce n'est pas valide? Comment renvoyer le formulaire avec les messages d'erreur? Je ne vois le «autre» dans aucun des exemples.

user984003
la source

Réponses:

242

Si vous affichez la même vue lorsque le formulaire n'est pas valide, dans le modèle, vous pouvez accéder aux erreurs de formulaire en utilisantform.errors .

{% if form.errors %}
    {% for field in form %}
        {% for error in field.errors %}
            <div class="alert alert-danger">
                <strong>{{ error|escape }}</strong>
            </div>
        {% endfor %}
    {% endfor %}
    {% for error in form.non_field_errors %}
        <div class="alert alert-danger">
            <strong>{{ error|escape }}</strong>
        </div>
    {% endfor %}
{% endif %}

Un exemple:

def myView(request):
    form = myForm(request.POST or None, request.FILES or None)
    if request.method == 'POST':
        if form.is_valid():
            return HttpResponseRedirect('/thanks/')
    return render(request, 'my_template.html', {'form': form})
Aamir Adnan
la source
J'ai ajouté un exemple simple. Assurez-vous de suivre la même approche que j'ai mentionnée.
Aamir Adnan
1
Je vois. Je retourne le même formulaire que celui dans lequel je suis entré. Les messages d'erreur y ont été automatiquement ajoutés par la fonction is_valid ().
user984003
oui vous l'avez tout de suite. Si vous n'avez pas rendu le formulaire manuellement, les erreurs s'afficheront automatiquement pour chaque champ.
Aamir Adnan le
@AlexanderSupertramp myFormest une instance de soit forms.Formou forms.ModelForm, lisez à propos de Django Forms
Aamir Adnan
Que faire si je n'ai pas de vue ... par exemple en utilisant un formulaire d'administration standard dans le CMS. Par exemple sur une UNIQUE constraint failed:exception?
geoidesic
19

views.py

from django.contrib import messages 

def view_name(request):
    if request.method == 'POST':
        form = form_class(request.POST)
        if form.is_valid():
            return HttpResponseRedirect('/thanks'/)
        else:
            messages.error(request, "Error")
return render(request, 'page.html', {'form':form_class()})

Si vous voulez afficher les erreurs du formulaire autres que celles non valides, mettez simplement {{form.as_p}} comme ce que j'ai fait ci-dessous

page.html

<html>
    <head>
        <script>
            {% if messages %}
                {% for message in messages %}
                    alert(message);
                {% endfor %}
            {% endif %}
        </script>
    </head>
    <body>
        {{form.as_p}}
    </body>
</html> 
Catherine
la source
Et puis qu'est-ce que je reviens? Comment cela arrive-t-il à mon modèle?
user984003
Je mets à jour mon code. Vous pouvez également placer un message en boucle dans votre modèle à la place dans un script, si vous le souhaitez.
catherine
1
c'est une bonne approche - mais doit être alerte ('{{message}}');
amchugh89
Comment mettriez-vous quelque chose de plus descriptif dans le message d'erreur de la vue que «Erreur» comme vous l'avez fait messages.error(request, "Error")?
cbuch1800
3
def some_view(request):
    if request.method == 'POST':
        form = SomeForm(request.POST)
        if form.is_valid():
            return HttpResponseRedirect('/thanks'/)
    else:
        form = SomeForm()
    return render(request, 'some_form.html', {'form': form})
Lukasz Koziara
la source
3

MISE À JOUR: Ajout d'une description plus détaillée des erreurs de formset.


Form.errors combine tous les champs et non_field_errors. Par conséquent, vous pouvez simplifier le html à ceci:

modèle

    {% load form_tags %}

    {% if form.errors %}
    <div class="alert alert-danger alert-dismissible col-12 mx-1" role="alert">
        <div id="form_errors">
            {% for key, value in form.errors.items %}
                <span class="fieldWrapper">
                    {{ key }}:{{ value }}
                </span>
            {% endfor %}
        </div>
        <button type="button" class="close" data-dismiss="alert" aria-label="Close">
            <span aria-hidden="true">&times;</span>
        </button>
    </div>
    {% endif %}


If you want to generalise it you can create a list_errors.html which you include in every form template. It handles form and formset errors:

    {% if form.errors %}
    <div class="alert alert-danger alert-dismissible col-12 mx-1" role="alert">
        <div id="form_errors">

            {% for key, value in form.errors.items %}
                <span class="fieldWrapper">
                    {{ key }}:{{ value }}
                </span>
            {% endfor %}
        </div>
        <button type="button" class="close" data-dismiss="alert" aria-label="Close">
            <span aria-hidden="true">&times;</span>
        </button>
    </div>
    {% elif formset.total_error_count %}
    <div class="alert alert-danger alert-dismissible col-12 mx-1" role="alert">
        <div id="form_errors">
            {% if formset.non_form_errors %}
                {{ formset.non_form_errors }}
            {% endif %}
            {% for form in formset.forms %}
                {% if form.errors %}
                    Form number {{ forloop.counter }}:
                    <ul class="errorlist">
                    {% for key, error in form.errors.items %}
                        <li>{{form.fields|get_label:key}}
                            <ul class="errorlist">
                                <li>{{error}}</li>
                            </ul>
                        </li>
                    {% endfor %}
                    </ul>
                {% endif %}
            {% endfor %}

        </div>
    </div>

    {% endif %}

form_tags.py

from django import template

register = template.Library()


def get_label(a_dict, key):
    return getattr(a_dict.get(key), 'label', 'No label')


register.filter("get_label", get_label)

Une mise en garde: contrairement aux formulaires Formset.errors n'inclut pas non_field_errors.

P. Maino
la source
0

vous pouvez simplement faire comme ceci car lorsque vous avez initialisé le formulaire dans contient des données de formulaire et des données invalides également:

def some_func(request):
    form = MyForm(request.POST)
    if form.is_valid():
         //other stuff
    return render(request,template_name,{'form':form})

if soulèvera l'erreur dans le modèle s'il en existe, mais les données du formulaire resteront toujours comme:

error_demo_here

Dinesh Kc
la source
-1

Vous pouvez mettre simplement une variable flag, dans ce cas is_successed .

def preorder_view(request, pk, template_name='preorders/preorder_form.html'):
    is_successed=0
    formset = PreorderHasProductsForm(request.POST)
    client= get_object_or_404(Client, pk=pk)
    if request.method=='POST':
        #populate the form with data from the request
       # formset = PreorderHasProductsForm(request.POST)
        if formset.is_valid():
            is_successed=1
            preorder_date=formset.cleaned_data['preorder_date']
            product=formset.cleaned_data['preorder_has_products']
            return render(request, template_name, {'preorder_date':preorder_date,'product':product,'is_successed':is_successed,'formset':formset})



    return render(request, template_name, {'object':client,'formset':formset})

ensuite dans votre modèle, vous pouvez simplement mettre le code ci-dessous

{%if is_successed == 1 %}
<h1>{{preorder_date}}</h1>
<h2> {{product}}</h2>
{%endif %}
gtopal
la source