how to make unique field exception message on django

I have a create document form which has only two fields first, title second, a foreign key to Note model.

Now i want to make the document title unique so i used;

title = models.CharField(max_length=32, default='document-title', unique=True)

Well it works! but it doesnt show any feedback that new Document couldnt created…
here is the documentation i tried to follow: https://docs.djangoproject.com/en/4.2/topics/forms/modelforms/#considerations-regarding-model-s-error-messages

forms.py

from django import forms
from django.forms import ModelForm
from .models import Document

class DocumentForm(ModelForm):
    class Meta:
        model = Document
        fields = {'title',}
        labels = {'title': '',}

        widgets = {'title': forms.TextInput(attrs={'placeholder': 'document_title'}),}

        error_messages = {
            NON_FIELD_ERRORS: {
                "unique_together": "model name is not unique.",
            }
        }

views.py

def home(request):
    if request.method == 'POST':
        form = DocumentForm(request.POST)

        if form.is_valid():
            document = form.save()
            dummy_note = Note.objects.create(document=document)

            return HttpResponseRedirect('/note')


    form = DocumentForm
    documents = Document.objects.all()

    return render(request, 'note/home.html', {'form': form, 'documents': documents})

home.html

{% extends 'base.html' %}

{% block content %}

<div class="container d-flex flex-column">
  <center class="p-3">
    Note App Home Page!
  </center>

  <div class="d-flex justify-content-between">
    
    <div class="card m-5" style="width: 20em;">
      <div class="card-header">
        Create Document
      </div>
      <div class="card-body">
        <form method=POST>
          {% csrf_token %}
          {{form.as_p}}

          <button name="create_document" type="submit" class="btn btn-primary">Create</button>
        </form>        
      </div>    
    </div>

    <div class="card m-5" style="width: 20em;">
      <ul class="list-group list-group-flush">
        <!-- <li class="list-group-item">An item</li> -->

        {% for document in documents %}
          <li class="list-group-item">
            <a href="{% url 'document-page' document.title %}">{{document.title}}</a>
          </li>
        {% endfor %}

      </ul>
    </div>
  
  </div>

  


</div>




{% endblock %}


i tought it would display a message right next to the input field but it doesnt show anything…
I want to have a display under/next to the input field how can i do it?

>Solution :

You should not create a new form in case the POST request is invalid, so constructing a new form should be done in the else clause in case of a GET request (method is not POST):

def home(request):
    if request.method == 'POST':
        form = DocumentForm(request.POST, request.FILES)
        if form.is_valid():
            dummy_note = Note.objects.create(document=form.save())
            return HttpResponseRedirect('/note')

    else:
        form = DocumentForm()
    documents = Document.objects.all()

    return render(
        request, 'note/home.html', {'form': form, 'documents': documents}
    )

As for the error message, this is not a unique_together: the uniqness is defined on the title field, so you can override the error message with:

class DocumentForm(ModelForm):
    class Meta:
        model = Document
        fields = {
            'title',
        }
        labels = {
            'title': '',
        }

        widgets = {
            'title': forms.TextInput(attrs={'placeholder': 'document_title'}),
        }

        error_messages = {
            'title': {
                'unique': 'model name is not unique.',
            }
        }

Note: While most forms do not process media files, it is probably better to pass request.FILES [Django-doc] to the form anyway, such that if you later add an extra media field, all views that use the form will indeed handle the files properly.

Leave a Reply