Search code examples
pythondjangoexceptiondjango-modelsdata-integrity

Django - Dealing With Integrity Error And Showing Error Pop up


I have my model.py file as below. I've created a conjugate primary key date & station.

Models.py

from django.db import models
from django import forms
# Create your models here.
from django.db import models
from django.conf import settings
from django.contrib.auth.models import User



# Create your models here.
class ManHour(models.Model):
    class Meta:
        unique_together = (('date', 'station'),)

    station_choices = (
       ('KHI','Station1'),
       ('ISB', 'Station2'),
       ('LHE','Station3'),
       )

    station = models.CharField(
        max_length=3,
        choices=station_choices,
    )
    date = models.DateField()
    date_time  = models.DateTimeField(auto_now=True)
    imports_airside = models.DecimalField(max_digits= 5, decimal_places= 3, default = 0)
    imports_landside = models.DecimalField(max_digits= 5, decimal_places= 3, default = 0)
    exports = models.DecimalField(max_digits= 5, decimal_places= 3, default = 0)

Form.py

from django import forms
from manhourapp.models import ManHour
from datetime import date

class DateInput(forms.DateInput):
    input_type = 'date'

class InputForm(forms.ModelForm):
    class Meta:
        model = ManHour
        fields = ['date','station', 'imports_airside', 'imports_landside', 'exports']
        widgets = {
            'date':forms.widgets.DateInput(attrs={'type': 'date', 'max':str(date.today())})
        }

Views.py

def form_page(request):
    context = {}

    try:
        man_hour = ManHour.objects.get(pk=request.GET.get("pk"))
    except ManHour.DoesNotExist:
        man_hour = None

    if man_hour:
        context["Total_Imports"] = man_hour.imports_airside + man_hour.imports_landside


    if man_hour:
        context["Total_Hours"] = man_hour.imports_airside + man_hour.imports_landside + man_hour.exports

    if request.method == 'POST':
        properties_Form = InputForm(request.POST, instance=man_hour)
        if properties_Form.is_valid():
            obj = properties_Form.save()
            return redirect("%s?pk=%s" % (reverse('form'), obj.pk))
    else:   
        context['form']= InputForm(instance=man_hour)
        return render(request, "form.html", context)

HTML

<!DOCTYPE html>
<html>
    <head>
        <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js" async></script>
    </head>
    <body>
      

        <form target="upload_frame" action="." method="post" enctype="multipart/form-data" >
            {% csrf_token %}
            {{ form.as_p }}<br>
            <input type="text" name="Total_Imports" value="{{ Total_Imports }}" class="form-control" disabled><br>
            <input type="text" name="Total_Hours" value="{{ Total_Hours }}" class="form-control" disabled><br>
            <input type="submit" name="submit" value="Upload" id="submit">
            <div class="user_panel">
                <a href="/logout">logout</a>
            </div>
        </form>           
    </body>
</html>

I am new to Django and I want to understand how can I show a pop up that would tell user that record already exists on this date and station.

I need to understand how can I add an exception handling and show pop up to user?

I've tried to add exception handling using code below but it is not working.

try:
    if request.method == 'POST':
        properties_Form = InputForm(request.POST, instance=man_hour)
        if properties_Form.is_valid():
            obj = properties_Form.save()
            return redirect("%s?pk=%s" % (reverse('form'), obj.pk))
except IntegrityError as e:
    error_message = e.__cause__
    print(error_message)

Solution

  • A Form class in Django will perform validation and cleaning for you. It will not raise errors but catch them itself so using a try-except does not make much sense as the form itself has caught the error.

    Instead you just need to return a response in case .is_valid() returns False. Furthermore the form itself will render the errors to display it to the user when you render it so you should simply render the same page again:

    if request.method == 'POST':
        properties_Form = InputForm(request.POST, instance=man_hour)
        if properties_Form.is_valid():
            obj = properties_Form.save()
            return redirect("%s?pk=%s" % (reverse('form'), obj.pk))
        context['form'] = properties_Form
        return render(request, "form.html", context) # form was not valid so returning a response here
    

    If you want to customize the error message that is generated you can do it by setting the error_messages attribute on the Meta class of the form (See Considerations regarding model’s error_messages [Django docs]):

    from django.core.exceptions import NON_FIELD_ERRORS
    
    
    class InputForm(forms.ModelForm):
        class Meta:
            model = ManHour
            fields = ['date','station', 'imports_airside', 'imports_landside', 'exports']
            widgets = {
                'date':forms.widgets.DateInput(attrs={'type': 'date', 'max':str(date.today())})
            }
            error_messages = {
                NON_FIELD_ERRORS: {
                    'unique_together': "%(model_name)s's %(field_labels)s are not unique.",
                }
            }