Форма Django с исключением IntegrityError - PullRequest
0 голосов
/ 22 ноября 2018

Я хотел бы получить вашу помощь, чтобы использовать except IntegrityError в моем formset.

У меня есть файл моей модели:

class Document(models.Model):

    code = models.CharField(max_length=25, verbose_name=_('code'), unique=True, null=False, blank=False, default='')
    language = models.CharField(max_length=2, verbose_name=_('language'), choices=LANGUAGE_CHOICES)
    format = models.CharField(max_length=10, verbose_name=_('format'), choices=FORMAT_CHOICES)
    title = models.CharField(max_length=512, verbose_name=_('title'))
    publication = models.ForeignKey(Publication, verbose_name=_('publication title'), related_name='documents')
    upload = models.FileField(upload_to='media/', validators=[validate_file_extension], verbose_name=_('document file'), )

    class Meta:
        verbose_name = _('document')
        verbose_name_plural = _('documents')

    def save(self, *args, **kwargs):
        self.code = f"{self.publication.pub_id}-{self.language.upper()}-{self.format.upper()}"
        super(Document, self).save(*args, **kwargs)

    def __str__(self):
        return f"{self.title}"

Как видите,code field зависит от данных, заполненных пользователем с помощью соответствующей формы.Каждое поле code должно быть уникальным.

У меня есть набор форм:

class DocumentForm(forms.ModelForm):

    def __init__(self, *args, **kwargs):
        super(DocumentForm, self).__init__(*args, **kwargs)

        for key in self.fields:
            self.fields[key].required = True

    class Meta:
        model = Document
        fields = ['publication', 'language', 'format', 'title', 'upload']


DocumentFormSet = inlineformset_factory(Publication, Document, form=DocumentForm, extra=1, max_num=4, can_delete=True)

И у меня есть файл views.py с except IntegrityError, если пользователь заполняет различные формы в наборе формс тем же значением.Потому что он создаст тот же code и пользователь получит ошибку.

class PublicationCreateView(CreateView):
    model = Publication
    template_name = 'publication_form.html'

    def get_context_data(self, **kwargs):
        context = super(PublicationCreateView, self).get_context_data(**kwargs)
        document_queryset = Document.objects.all()
        context['DocumentFormSets'] = DocumentFormSet(self.request.POST or None, self.request.FILES or None,
                                                      prefix='doc', queryset=document_queryset)
        return context

    def form_valid(self, form):
        try:
            context = self.get_context_data()
            formsets = context['DocumentFormSets']
            if form.is_valid():
                self.object = form.save()
                if formsets.is_valid():
                    formsets.instance = self.object
                    formsets.save(commit=False)
                    for element in formsets:
                        element.save(commit=False)
                        formsets.save()
            return super(PublicationCreateView, self).form_valid(form)
        except IntegrityError:
            messages.error(self.request, _(f"Issue with documents"))
            return render(self.request, self.template_name)

Вы можете найти мой шаблон, но я не знаю, нужно ли это!

<form method="post" action="" enctype="multipart/form-data" novalidate>
      {% csrf_token %}
{#      {{ form.management_form }}#}

      <fieldset>
        <legend class="title"><span class="name">{% trans 'Publication form' %}</span></legend>
        <div class="row">
          <div class="col-xs-6">
            {{ form.category|as_crispy_field }}
          </div>
          <div class="col-xs-6">
            {{ form.pub_id|as_crispy_field }}
          </div>
        </div>
        <div class="row">
          <div class="col-xs-6">
            {{ form.title|as_crispy_field }}
          </div>
          <div class="col-xs-6">
            {{ form.cover|as_crispy_field }}
          </div>
        </div>
        <div class="row">
          <div class="col-xs-12">
            {{ form.description|as_crispy_field }}
          </div>
        </div>
      </fieldset>

      <fieldset>
        <legend class="title"><span class="name">{% trans 'Document form' %}</span></legend>
        {{ DocumentFormSets.management_form }}
        <div id="form_set">
          {% for form in DocumentFormSets.forms %}
            <div class='formset-document'>
              <table class='no_error'>
                <div class="row">
                  <div class="col-xs-3">
                    {{ form.title|as_crispy_field }}
                  </div>
                  <div class="col-xs-3">
                    {{ form.language|as_crispy_field }}
                  </div>
                  <div class="col-xs-3">
                    {{ form.format|as_crispy_field }}
                  </div>
                  <div class="col-xs-3">
                    {{ form.upload|as_crispy_field }}
                  </div>
                </div>
              </table>
            </div>
          {% endfor %}
        </div>
        <br>
        <input type="button" class="btn btn-default" value="Add More" id="add_more">
        <div id="empty_form" style="display:none">
          <table class='no_error'>
            <div class="row">
              <div class="col-xs-3">
                {{ DocumentFormSets.empty_form.title|as_crispy_field }}
              </div>
              <div class="col-xs-3">
                {{ DocumentFormSets.empty_form.language|as_crispy_field }}
              </div>
              <div class="col-xs-3">
                {{ DocumentFormSets.empty_form.format|as_crispy_field }}
              </div>
              <div class="col-xs-3">
                {{ DocumentFormSets.empty_form.upload|as_crispy_field }}
              </div>
            </div>
          </table>
        </div>
      </fieldset>

      <br>
      <input type="submit" class="btn btn-default" value="{% trans 'Save' %}"/>
      <a href="{{ request.META.HTTP_REFERER }}" class="btn btn-default">{% trans 'Cancel' %}</a>
    </form>

Я получаю эту проблему:

Exception Value: |as_crispy_field got passed an invalid or inexistent field

Потому что:

Вышеуказанное исключение (дублирующее значение ключа нарушает уникальное ограничение "freepub_document_code_key" ПОДРОБНЕЕ: Ключ (код) = (PUBSD-8119-FR-PDF) уже существует.) Была прямой причиной следующего исключения: formsets.save ()

РЕДАКТИРОВАТЬ:

Я пытался:

try:
    context = self.get_context_data()
    formsets = context['DocumentFormSets']
    if form.is_valid():
        self.object = form.save()
        if formsets.is_valid():
            formsets.instance = self.object
            formsets.save(commit=False)
            for element in formsets:
                element.save(commit=False)
                formsets.save()
    return super(PublicationCreateView, self).form_valid(form)
except IntegrityError:
    messages.error(self.request, _(f"Issue with documents"))
    return super(PublicationCreateView, self).form_invalid(form)

Кажется, я работаю, но, может быть, мне не нужно использовать ту же самую первую форму, потому что у нее тоже уникальное значение, и если я изменяю значение в соответствии с form_invalid (), я тоже должен изменить это.

...