Django Не удалось выполнить ограничение UNIQUE: core_organization.name - PullRequest
3 голосов
/ 07 января 2020

Итак, у меня есть модель с названием Organization внутри core / models.py. Я пытаюсь реализовать CRUD Ajax на одной странице. Вдохновленный этим постом . Каждый раз, когда я сохраняю объект этой модели, я получаю эту ошибку, как показано ниже. Я хочу иметь несколько уникальных организаций.

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')

шаблонов / основ. 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>

Шаблоны / ядро ​​/ список_организации. 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 %}

Шаблоны / ядро ​​/ частичная_организация_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 %}

статический /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);

});

И когда я добавляю новую организацию, я получаю следующую ошибку:

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

Как это исправить?

Ответы [ 3 ]

1 голос
/ 22 января 2020

Я полагаю, что ваш javascript файл содержит дубликаты ajax вызовов.

Существует 3 вызова для создания вашего модального режима:

$(function () {

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

вверху файла js , Затем та же функция в середине вашего js файла. И

var loadForm = function ()

, который вы привязываете к событию click в нижней части вашего скрипта.

Кроме того, есть две функции, обрабатывающие представление данных формы:

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

в верхней части и

 var saveForm = function ()

в нижней части.

Дубликат, относящийся к отправке формы, может вызвать уникальную ошибку ограничения, поскольку вы отправляете одни и те же данные дважды. Дублирование загрузки модальной модели, вероятно, не вызывает заметных ошибок, но является ненужной загрузкой.

Нижняя часть вашего javascript файла, то есть часть, начинающаяся с

$(function () {

  /* Functions */

должно быть достаточно.

0 голосов
/ 20 января 2020

Попробуйте обновить экземпляр, а не объект формы. Создайте отдельную конечную точку / logi c для обновления экземпляра и отдельную конечную точку / logi c для создания объектов, используя форму

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')
0 голосов
/ 14 января 2020

Я думаю, что у вас возникла эта проблема из-за ограничения unique=True для вашего поля name

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

Это означает, что имя будет уникальным для всех пользователей, и вы будете продолжайте получать ошибку UNIQUE constraint failed каждый раз, когда вы добавляете одно и то же имя для разных пользователей.


Чтобы решить эту проблему, я предлагаю использовать мета-опцию unique_together. Все, что вам нужно сделать, это удалить ограничение unique из поля имени и добавить класс Meta с опцией unique_toghether, чтобы включить поля user_id и name.

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']

Затем python manage.py makemigrations, python manage.py migrate.

Ограничение UNIQUE будет сохраняться, но оно будет действовать для всех Organization имен, связанных с одним пользователем.

Если USER1 имеет организацию ORG1 и попытался добавить еще ORG1 , произойдет сбой, но если USER2 добавится ORG1 будет работать успешно.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...