简体   繁体   中英

Django UNIQUE constraint failed: core_organization.name

So I have a model called Organization inside core/models.py. I am trying to implement CRUD Ajax on a single page. Inspired by this post . Every time I save an object of this model I get this error as shown below. I want to have multiple organizations that are unique.

core/models.py

class Organization(models.Model):
    name = models.CharField(max_length=255, unique=True)
    user = models.ForeignKey(User, on_delete=models.CASCADE)
    gstin = models.CharField(max_length=15)
    address = models.CharField(max_length=500)
    city = models.CharField(max_length=50)
    state = models.CharField(max_length=50)
    zipcode = models.CharField(max_length=6)
    country = models.CharField(max_length=50)
    is_billed = models.BooleanField(default=False)

    def __str__(self):
        return f'{self.name} Organization'

core/forms.py

class OrganizationForm(forms.ModelForm):
    class Meta:
        model = models.Organization
        fields = ('name', 'address', 'state', 'city', 'zipcode', 'country', 'gstin')

core/views.py


def save_organization_form(request, form, template_name):
    data = dict()
    if request.method == 'POST':
        if form.is_valid():
            stock = form.save(commit=False)
            stock.user = request.user
            stock.save()
            data['form_is_valid'] = True
            organizations = Organization.objects.all()
            data['html_book_list'] = render_to_string('core/includes/partial_organization_list.html', {
                'organizations': organizations
            })
        else:
            data['form_is_valid'] = False
    context = {'form': form}
    data['html_form'] = render_to_string(template_name, context, request=request)
    return JsonResponse(data)


@login_required(login_url="/accounts/login/")
def organization_create(request):
    if request.method == 'POST':
        form = OrganizationForm(request.POST)
    else:
        form = OrganizationForm()
    return save_organization_form(request, form, 'core/includes/partial_organization_create.html')

templates/base.html

{% load static %}
<!DOCTYPE html>
<html>
  <head>
    <title>{% block head_title %}{% endblock %}</title>
    {% block extra_head %}
    {% endblock %}
    <!-- Bootstrap CSS -->
    <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.1.3/css/bootstrap.min.css"
          integrity="sha384-MCw98/SFnGE8fJT3GXwEOngsV7Zt27NXFoaoApmYm81iuXoPkFOJwJ8ERdknLPMO" crossorigin="anonymous">
    <link href='https://fonts.googleapis.com/css?family=Russo One' rel='stylesheet'>
    <link rel="stylesheet" type="text/css" href="{% static 'font/flaticon.css' %}">
    <link rel="stylesheet" href="{% static 'css/style.css' %}">
  </head>
  <body>
    {% block body %}

    {% if messages %}
    <div class="text-center">
      <strong>Messages:</strong>
      <ul>
        {% for message in messages %}
        <li>{{message}}</li>
        {% endfor %}
      </ul>
    </div>
    {% endif %}

    {% block content %}
    {% endblock %}
    {% endblock %}
    {% block extra_body %}
    {% endblock %}
    <!-- Optional JavaScript -->
    <!-- jQuery first, then Popper.js, then Bootstrap JS -->
    <script src="https://code.jquery.com/jquery-3.4.1.min.js"
            integrity="sha256-CSXorXvZcTkaix6Yvo6HppcZGetbYMGWSFlBw8HfCJo=" crossorigin="anonymous"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.3/umd/popper.min.js"
            integrity="sha384-ZMP7rVo3mIykV+2+9J3UJ46jBk0WLaUAdn689aCwoqbBJiSnjAK/l8WvCWPIPm49" crossorigin="anonymous"></script>
    <script src="https://stackpath.bootstrapcdn.com/bootstrap/4.1.3/js/bootstrap.min.js"
            integrity="sha384-ChfqqxuZUCnJSK3+MXmPNIyE6ZbWh2IMqE241rYiqJxyMiZ6OW/JmZQ5stwEULTy" crossorigin="anonymous"></script>
    {% block javascript %}
    {% endblock %}
  </body>
</html>

templates/core/organization_list.html

{% extends 'base.html' %}

{% load static %}

{% block javascript %}
  <script src="{% static 'organizations/js/organizations.js' %}"></script>
{% endblock %}

{% block content %}

  <h1 class="page-header">Organizations</h1>

<!-- BUTTON TO TRIGGER THE ACTION -->
  <p>
    <button type="button"
            class="btn btn-primary js-create-book"
            data-url="{% url 'organization_create' %}">
      <span class="glyphicon glyphicon-plus"></span>
      New Organization
    </button>
  </p>

  <table class="table" id="book-table">
    <thead>
      <tr>
        <th>#</th>
        <th>Name</th>
        <th>Address</th>
        <th>State</th>
        <th>City</th>
        <th>Zipcode</th>
        <th>Country</th>
        <th>Billing Active</th>
      </tr>
    </thead>
    <tbody>
      {% include 'core/includes/partial_organization_list.html' %}
    </tbody>
  </table>

<!-- THE MODAL WE WILL BE USING -->
  <div class="modal fade" id="modal-book">
    <div class="modal-dialog">
      <div class="modal-content">
      </div>
    </div>
  </div>
{% endblock %}

templates/core/partial_organization_list.html

{% for organization in organizations %}
  <tr>
    <td>{{ organization.id }}</td>
    <td>{{ organization.name }}</td>
    <td>{{ organization.address }}</td>
    <td>{{ organization.state }}</td>
    <td>{{ organization.city }}</td>
    <td>{{ organization.zipcode }}</td>
    <td>{{ organization.country }}</td>
    <td>{{ organization.is_billed }}</td>
    <td>
      <button type="button"
              class="btn btn-warning btn-sm js-update-book"
              data-url="{% url 'organization_update' organization.id %}">
        <span class="glyphicon glyphicon-pencil"></span> Edit
      </button>
      <button type="button"
              class="btn btn-danger btn-sm js-delete-book"
              data-url="{% url 'organization_delete' organization.id %}">
        <span class="glyphicon glyphicon-trash"></span> Delete
      </button>
    </td>
  </tr>
{% empty %}
  <tr>
    <td colspan="8" class="text-center bg-warning">No Organization</td>
  </tr>
{% endfor %}

static/organizations/js/organizations.js

$(function () {

  $(".js-create-book").click(function () {
    $.ajax({
      url: '/profile/organization/create/',
      type: 'get',
      dataType: 'json',
      beforeSend: function () {
        $("#modal-book").modal("show");
      },
      success: function (data) {
        $("#modal-book .modal-content").html(data.html_form);
      }
    });
  });

});


$("#modal-book").on("submit", ".js-book-create-form", function () {
    var form = $(this);
    $.ajax({
      url: form.attr("action"),
      data: form.serialize(),
      type: form.attr("method"),
      dataType: 'json',
      success: function (data) {
        if (data.form_is_valid) {
          $("#book-table tbody").html(data.html_book_list);  // <-- Replace the table body
          $("#modal-book").modal("hide");  // <-- Close the modal
        }
        else {
          $("#modal-book .modal-content").html(data.html_form);
        }
      }
    });
    return false;
  });


  $(".js-create-book").click(function () {
  var btn = $(this);  // <-- HERE
  $.ajax({
    url: btn.attr("data-url"),  // <-- AND HERE
    type: 'get',
    dataType: 'json',
    beforeSend: function () {
      $("#modal-book").modal("show");
    },
    success: function (data) {
      $("#modal-book .modal-content").html(data.html_form);
    }
  });
});


$(function () {

  /* Functions */

  var loadForm = function () {
    var btn = $(this);
    $.ajax({
      url: btn.attr("data-url"),
      type: 'get',
      dataType: 'json',
      beforeSend: function () {
        $("#modal-book").modal("show");
      },
      success: function (data) {
        $("#modal-book .modal-content").html(data.html_form);
      }
    });
  };

  var saveForm = function () {
    var form = $(this);
    $.ajax({
      url: form.attr("action"),
      data: form.serialize(),
      type: form.attr("method"),
      dataType: 'json',
      success: function (data) {
        if (data.form_is_valid) {
          $("#book-table tbody").html(data.html_book_list);
          $("#modal-book").modal("hide");
        }
        else {
          $("#modal-book .modal-content").html(data.html_form);
        }
      }
    });
    return false;
  };


  /* Binding */

  // Create book
  $(".js-create-book").click(loadForm);
  $("#modal-book").on("submit", ".js-book-create-form", saveForm);

  // Update book
  $("#book-table").on("click", ".js-update-book", loadForm);
  $("#modal-book").on("submit", ".js-book-update-form", saveForm);

  // Delete book
  $("#book-table").on("click", ".js-delete-book", loadForm);
  $("#modal-book").on("submit", ".js-book-delete-form", saveForm);

});

And when I add a new organization I get the following error:

django.db.utils.IntegrityError: UNIQUE constraint failed: core_organization.name

How do I fix this?

I believe your javascript file contains duplicate ajax calls.

There are 3 calls to create your modal:

$(function () {

  $(".js-create-book").click(function () {

at the top of your js file. Then the same function in the middle of your js file. And

var loadForm = function ()

which your binding to the click event at the bottom of your script.

In addition there are two functions handling the submission of the form data:

$("#modal-book").on("submit", ".js-book-create-form", function ()

in the top part and

 var saveForm = function ()

in the bottom part.

The duplicate regarding the submission of the form can cause the unique constraint error because you are submitting the same data twice. The duplication of the loading of the modal probably does not cause any noticable errors, but is unnecessary load.

The bottom part of your javascript file, ie the part beginning with

$(function () {

  /* Functions */

should be sufficient.

I think you are having this issue, because of the unique=True constraint on your name field

name = models.CharField(max_length=255, unique=True)

This means that the name is going to be unique for all users, and you will keep getting UNIQUE constraint failed error everytime you add the same name for different users.


To solve this, I suggest using unique_together meta option. All you have to do, is removing the unique constraint from name field, and adding Meta class with the unique_toghether option to include both the user_id and name fields.

class Organization(models.Model):
    name = models.CharField(max_length=255)
    user = models.ForeignKey(User, on_delete=models.CASCADE)
    address = models.CharField(max_length=1000, default=None)
    is_billed = models.BooleanField(default=False)

    def __str__(self):
        return f'{self.name} Organization'

    class Meta:
        unique_together = ['name', 'user_id']

Then, python manage.py makemigrations , python manage.py migrate .

The UNIQUE constraint going to remain, but it is going to be for all Organization names related for one user.

If USER1 have organization ORG1 , and tried to add another ORG1 , it is going to fail, but if USER2 added ORG1 it is going to work successfully.

Try updating the instance rather than form object, Create separate endpoint/logic for updating instance and an separate endpoint/logic to create objects using form

views.py

def save_organization_form(request, form, template_name):
    data = dict()
    if request.method == 'POST':
        if form.is_valid():
            stock = form.instance
            stock.user = request.user
            stock.something = request.something
            stock.save()
            data['form_is_valid'] = True
            organizations = Organization.objects.all()
            data['html_book_list'] = render_to_string('core/includes/partial_organization_list.html', {
                'organizations': organizations
            })
        else:
            data['form_is_valid'] = False
    context = {'form': form}
    data['html_form'] = render_to_string(template_name, context, request=request)
    return JsonResponse(data)


@login_required(login_url="/accounts/login/")
def organization_create(request):
    if request.method == 'POST':
        form = OrganizationForm(request.POST)
    else:
        form = OrganizationForm()
    return save_organization_form(request, form, 'core/includes/partial_organization_create.html')

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM