Как перехватить IntegrityError в Django при использовании UniqueConstraint для нескольких полей? - PullRequest
0 голосов
/ 15 апреля 2019

У меня есть модель с пользователем как 1 поле (внешний ключ) и еще одно поле skill_group. Мне нужно убедиться, что пользователь не добавляет дубликаты групп навыков, поэтому я добавил UniqueConstraint. Это работает из-за системных ошибок с IntegrityError в / skillgroup / create / значение дубликата ключа нарушает ограничение уникальности «unique_skillgroup» - как мне перехватить это исключение и уведомить пользователя, если дубликат; в противном случае сохранить его?

Впервые в Django / Python / Postgres, и я подумал, что смогу справиться с этим, переопределив функцию save (), но нет доступа к пользователю, который является частью проверки, и я прочитал, что это не должно обрабатываться здесь. Есть ли попытка / сохранение улова / сообщения, которое я должен использовать? Я попробовал несколько вещей без удачи. Я видел подобные вопросы здесь, но они не помогли. Любая помощь приветствуется.

models.py
class SkillGroup(models.Model):
    user = models.ForeignKey(User, on_delete=models.CASCADE)
    skill_group = models.CharField(max_length=35)
    sequence = models.IntegerField(default=999)

    class Meta:
        constraints = [
            models.UniqueConstraint(fields=['user', 'skill_group'], name='unique_skillgroup'),
        ]

    def __str__(self):
        return self.skill_group

    def get_absolute_url(self):
        return reverse('skillgroup-list')
views.py
class SkillGroupCreateView(LoginRequiredMixin, CreateView):
    model = SkillGroup
    fields = ['skill_group']

    def form_valid(self, form):
        form.instance.user = self.request.user
        form.instance.sequence = SkillGroup.objects.filter(user=self.request.user).order_by('sequence').last().sequence + 1
        return super().form_valid(form)
skillgroup_form.html
{% extends "recruiter/baseskills.html" %}
{% load crispy_forms_tags %}

{% block content%}
  <div class="content-section">
      <form method="post">
        {% csrf_token %}
        <fieldset class="form-group">
          <legend class="border-bottom mb-4">Skill Group</legend>
          {{ form|crispy }}
        </fieldset>
        <div class="form-group">
          <button class="btn btn-outline-info" type="submit">Add Skill Group</button>
        </div>
      </form>
  </div>
{% endblock content%}

Я хочу либо поймать исключение и сохранить запись, если не дубликат, либо вывести на экран сообщение с надписью «Группа навыков уже существует» и оставить пользователя на странице создания. Кроме того, я могу удалить UniqueConstraint и обработать его с помощью кода, если это лучшее решение.

Ответы [ 2 ]

0 голосов
/ 16 апреля 2019

Попробуйте проверить skill_group поле в вашем классе формы. Определите clean_skill_group метод как в документах . Здесь вы можете получить набор запросов всех объектов SkillGroup, связанных с вашим пользователем (например, здесь ), а затем сравнить навыки. Но вам нужно как-то выдвинуть ваш пользовательский объект или user_id (чтобы затем получить пользовательский объект) в форму перед вызовом form.is_valid () (или вызвать еще один раз form.is_valid () после). Затем покажите ошибки формы в своем HTML-шаблоне.

class YourForm(forms.ModelForm):
    ....some fields, Meta....
    def clean_skill_group(self):
        your_user_object = ....
        previously_created_skills = your_user_object.skill_group_set.all()
        skill_input = self.cleaned_data["skill_group"]
        if skill_input in previously_created_skills:
            raise forms.ValidationError(("This skill group is already exist"), code="invalid") # I suppose you are using model form 
0 голосов
/ 16 апреля 2019

Вы непреднамеренно пропускаете проверку формы Django здесь, а затем пытаетесь сохранить неверный ввод в базу данных, поэтому Django выдает некрасивую ошибку IntegrityError из базы данных вместо того, чтобы корректно обрабатывать ошибку.

Если выотправив дубликат пользователя и группу навыков в вашей форме, ваш CreateView будет своевременно возвращать сообщение об ошибке обратно в шаблон формы:

  • "Группа навыков с этой группой пользователей и навыков уже существует."

Но это можно сделать только в том случае, если вы включите в форму поле User.Я предполагаю, что вы исключили пользователя, чтобы сохранить шаблон в чистоте, но это не позволяет проверке формы Django проверять, существует ли уже комбинация.

Чтобы обойти это, добавьте User в поле формы в качестве скрытого ввода.Я не думаю, что это возможно, используя скрытую магию CreateView, поэтому вам нужно создать SkillGroupForm, чтобы справиться с этим.

# forms.py
from django import forms
from .models import SkillGroup

class SkillGroupForm(forms.ModelForm):
    class Meta:
        model = SkillGroup
        fields = ('user', 'skill_group')
        widgets = {
            'user': forms.HiddenInput,
        }

# views.py
from .forms import SkillGroupForm

class SkillGroupCreateView(LoginRequiredMixin, CreateView):
    model = SkillGroup
    form_class = SkillGroupForm

    def get_initial(self):
        return {'user': self.request.user}

    def form_valid(self, form):
        form.instance.sequence = SkillGroup.objects.filter(user=self.request.user).order_by('sequence').last().sequence + 1
        return super().form_valid(form)

Метод get_initial проходитrequest.user в качестве начального значения в скрытом поле формы, поэтому ввод пользователя не требуется.

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