web-dev-qa-db-fra.com

Django: erreur de capture d'intégrité et affichage d'un message personnalisé à l'aide d'un modèle

Dans mon application alimentée par Django, il n'y a qu'un seul cas évident où "IntegrityError" peut survenir.
Alors, comment puis-je détecter cette erreur et afficher un message à l'aide de modèles?

56
Rajat Saxena

Utilisez juste essayer et attraper.

from Django.db import IntegrityError
from Django.shortcuts import render_to_response

try:
    # code that produces error
except IntegrityError as e:
    return render_to_response("template.html", {"message": e.message})

Si vous le souhaitez, vous pouvez utiliser le message dans votre modèle.

MODIFIER

Merci pour Jill-Jênn Vie , vous devez utiliser e.__cause__, comme décrit ici .

130
Joe

Si vous utilisez des vues basées sur les classes avec le mixin CreateView, vous voudrez "essayer" l'appel à la valeur_formulaire de la superclasse, par exemple:

from Django.db import IntegrityError
...
class KumquatCreateView(CreateView):
    model = Kumquat
    form_class = forms.KumquatForm
    ...
    def form_valid(self, form):
        ...
        try:
            return super(KumquatCreateView, self).form_valid(form)
        except IntegrityError:
            return HttpResponse("ERROR: Kumquat already exists!")

Vous pouvez utiliser un modèle, render_to_response etc. pour rendre la sortie plus agréable, bien sûr.

9
Chirael

Solution la plus simple: écrivez un middleware implémentant process_exception qui ne capture que IntegrityError et renvoie une réponse HttpResponse avec votre modèle de rendu, et assurez-vous qu'il est après le middleware de traitement des erreurs par défaut, de sorte qu'il est appelé avant (cf https: //docs.djangoproject. com/fr/dev/topics/http/middleware/# process-exception pour les autres).

Maintenant, si j'étais vous, je ne supposerais pas une chose comme "il n'y a qu'un seul cas évident où" IntegrityError "puisse survenir", c'est pourquoi je vous recommande fortement de consigner l'exception (et d'envoyer des alertes par e-mail) dans votre middleware.

3

Je le validerais avec ModelForm. Par exemple:

Vous avez un modèle:

class Manufacturer(models.Model):
    name = models.CharField(default='', max_length=40, unique=True)

Et ModelForm:

class ManufacturerForm(forms.ModelForm):

    def clean(self):
        cleaned_data = super(ManufacturerForm, self).clean()
        name = cleaned_data.get('name')
        if Manufacturer.objects.filter(name=name).exists():
            raise forms.ValidationError('Category already exists')

    class Meta:
        model = Manufacturer

Dans ce cas, lorsque vous soumettez un nom unique. Vous obtiendrez une erreur de validation avant IntegrityError. Le message 'La catégorie existe déjà' sera affiché dans votre formulaire dans le modèle

1
Krzysiek Hans

Importez simplement IntegrityError
de Django.db import IntegrityError
C'est tout.

0
lilhamad

Je l'ai fait comme ça

from Django.db import IntegrityError
from Django.shortcuts import render

from .models import Person
from .forms import PersonForm

class PersonView(View):

def get(self, request):
    pd = PersonForm()
    return render(request, "app1/my_form.html", context={ 'form': pd })



def post(self, request):
    pd = PersonForm(request.POST)


    if pd.is_valid():
        name = pd.cleaned_data['name']
        age = pd.cleaned_data['age']
        height = pd.cleaned_data['height']

        p = Person()
        p.name = name
        p.age = age
        p.height = height
        try:
            p.save()
        except IntegrityError as e:
            e = 'this data already exists in the database'
            return render(request, "app1/my_form.html", context={ 'form': pd, 'e': e})

        context = {
        'person': {
            'name': name,
            'age': age,
            'height': height,
        },
        'form': pd
        }

    else:
        print("Form is invalid")
        context = { 'form': pd }

    return render(request, "app1/my_form.html", context=context)

dans le modèle, je peux accéder à l'erreur en tant que {{e}}

0
Luke Marak