Django: флажки не сохраняются, пока FormValidationError

Я работаю с CreateView. При отправке моей формы со всеми правильно заполненными полями также сохраняется поле тикетов (поле ManyToMany). Однако, если я POST мою форму с некоторой ошибкой проверки (например, обязательное поле пусто), тогда все предварительно заполненные поля все еще являются полями через request.POST. Однако предварительно отмеченные мной поля больше не выбираются. Ты знаешь почему?

Демонстрация

view.py

class DiscountCreate(AdminPermissionRequiredMixin, SuccessMessageMixin,
                     FormValidationMixin, BaseDiscountView, CreateView):
    form_class = DiscountForm
    template_name = 'discounts/admin/create.html'
    success_message = _("Discount Code has been successfully created.")

    def get_form_kwargs(self):
        kwargs = super().get_form_kwargs()
        kwargs['event'] = self.request.event
        return kwargs

    def get_success_url(self):
        return reverse('discounts:admin:detail', kwargs = {
            'organizer': self.request.organizer.slug,
            'event': self.request.event.slug,
            'discount': self.instance.pk
        })

    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        context['type_fixed'] = Discount.TYPE_FIXED
        context['type_percentage'] = Discount.TYPE_PERCENTAGE
        return context

    def form_valid(self, form):
        self.instance = form.save(commit=False)
        self.instance.event = self.request.event
        self.instance.status = Discount.STATUS_ACTIVE
        return super().form_valid(form)

Шаблон

<div class = "card">
  <div class = "card-header">
    <h4 class = "card-header-title">
      {% trans "Creating Discount Code" %}
    </h4>
  </div>
  <div class = "card-body">

    <form method = "post" autocomplete = "off" novalidate>
      {% csrf_token %}

      <div class = "form-group">
        <label for = "{{ form.code.id_for_label }}">
          {{ form.code.label }}
        </label>
        {{ form.code }}
        {% if form.code.errors %}
          <div class = "invalid-feedback d-block">
            {{ form.code.errors|first }}
          </div>
        {% endif %}
      </div>

      <div class = "form-group">
        <label for = "{{ form.type.id_for_label }}">
          {{ form.type.label }}
        </label>
        {{ form.type }}
        {% if form.type.errors %}
          <div class = "invalid-feedback d-block">
            {{ form.type.errors|first }}
          </div>
        {% endif %}
      </div>

      <div class = "form-group fixed{% if form.type.value != type_fixed %} d-none {% endif %}">
        {{ form.value.label_tag }}
        <div class = "input-group">
          {{ form.value }}
          <div class = "input-group-append">
            <span class = "input-group-text text-dark">{{ request.event.currency }}</span>
          </div>
        </div>

        {% if form.value.errors %}
          <div class = "invalid-feedback d-block">
            {{ form.value.errors|first }}
          </div>
        {% endif %}
      </div>

      <div class = "form-group percentage{% if form.type.value != type_percentage %} d-none {% endif %}">
        {{ form.percentage.label_tag }}
        <div class = "input-group">
          {{ form.percentage }}
          <div class = "input-group-append">
            <span class = "input-group-text text-dark">&#37;</span>
          </div>
        </div>
        {% if form.percentage.errors %}
          <div class = "invalid-feedback d-block">
            {{ form.percentage.errors|first }}
          </div>
        {% endif %}
      </div>

      <div class = "form-group">
        {{ form.available_amount.label_tag }}
        {{ form.available_amount }}
        {% if form.available_amount.errors %}
          <div class = "invalid-feedback d-block">
            {{ form.available_amount.errors|first }}
          </div>
        {% endif %}
      </div>

      <div class = "form-group">
        <label for = "{{ form.tickets.id_for_label }}">
          {{ form.tickets.label }}
          <span class = "badge badge-light">{% trans "Optional" %}</span>
        </label>
        <small class = "form-text text-muted mt--2">{{ form.tickets.help_text }}</small>
        {% for ticket_id, ticket_label in form.tickets.field.choices %}
          <div class = "custom-control custom-checkbox">
            <input
              type = "checkbox"
              name = "{{ form.tickets.html_name }}"
              value = "{{ ticket_id }}"
              class = "custom-control-input"
              id = "id_{{ form.tickets.html_name }}_{{ forloop.counter }}"
              {% if ticket_id in form.tickets.value %}checked{% endif %}>
            <label class = "custom-control-label" for = "id_{{ form.tickets.html_name }}_{{ forloop.counter }}">{{ ticket_label }}</label>
          </div>
        {% endfor %}
        {% if form.tickets.errors %}
          <div class = "invalid-feedback d-block">
            {{ form.tickets.errors|first }}
          </div>
        {% endif %}
      </div>

      <div class = "form-group">
        <label for = "{{ form.valid_from.id_for_label }}">
          {{ form.valid_from.label }}
          <span class = "badge badge-light">{% trans "Optional" %}</span>
        </label>
        <small class = "form-text text-muted mt--2">{{ form.valid_from.help_text }}</small>
        {{ form.valid_from }}
        {% if form.valid_from.errors %}
          <div class = "invalid-feedback d-block">
            {{ form.valid_from.errors|first }}
          </div>
        {% endif %}
      </div>

      <div class = "form-group">
        <label for = "{{ form.valid_until.id_for_label }}">
          {{ form.valid_until.label }}
          <span class = "badge badge-light">{% trans "Optional" %}</span>
        </label>
        <small class = "form-text text-muted mt--2">{{ form.valid_until.help_text }}</small>
        {{ form.valid_until }}
        {% if form.valid_until.errors %}
          <div class = "invalid-feedback d-block">
            {{ form.valid_until.errors|first }}
          </div>
        {% endif %}
      </div>

      <div class = "form-group">
        <label for = "{{ form.comment.id_for_label }}">
          {{ form.comment.label }}
          <span class = "badge badge-light">{% trans "Optional" %}</span>
        </label>
        <small class = "form-text text-muted mt--2">{{ form.comment.help_text }}</small>
        {{ form.comment }}
        {% if form.comment.errors %}
          <div class = "invalid-feedback d-block">
            {{ form.comment.errors|first }}
          </div>
        {% endif %}
      </div>

      <button type = "submit" class = "btn btn-primary btn-block">{% trans "Create Discount Code" %}</button>
    </form>

  </div>
</div> {# / .card #}

<a class = "btn btn-block btn-link text-muted mb-4" href = "{% url 'discounts:admin:index' request.organizer.slug request.event.slug %}">
  {% trans "Cancel discount code creation" %}
</a>

forms.py

class DiscountForm(forms.ModelForm):
    # Remove required attribute from HTML elements
    use_required_attribute = False
    value = forms.DecimalField(decimal_places=2, required=False)
    percentage = forms.DecimalField(max_digits=4, decimal_places=2, required=False)

    class Meta:
        model = Discount
        fields = (
            'code',
            'type',
            'value',
            'percentage',
            'available_amount',
            'tickets',
            'valid_from',
            'valid_until',
            'comment',
        )

    def __init__(self, *args, **kwargs):
        self.event = kwargs.pop('event')
        super().__init__(*args, **kwargs)

        for visible_field in self.visible_fields():
            visible_field.field.widget.attrs['class'] = 'form-control'

        self.fields['tickets'].queryset = self.event.tickets.all()

        self.fields['code'].widget.attrs['autofocus'] = True
        self.fields['valid_from'].widget.attrs['class'] = 'form-control start-date picker'
        self.fields['valid_until'].widget.attrs['class'] = 'form-control end-date picker'
        self.fields['valid_from'].widget.format = settings.DATETIME_INPUT_FORMATS[0]
        self.fields['valid_until'].widget.format = settings.DATETIME_INPUT_FORMATS[0]
        self.fields['valid_from'].widget.attrs['data-lang'] = get_lang_code()
        self.fields['valid_until'].widget.attrs['data-lang'] = get_lang_code()

    def clean(self):
        cleaned_data = super().clean()
        discount_type = cleaned_data.get('type')

        if discount_type:
            if discount_type == Discount.TYPE_FIXED:
                value = cleaned_data.get('value')
                cleaned_data['percentage'] = None
                if not value:
                    message = _("Please enter how much discount you want to give.")
                    self.add_error('value', forms.ValidationError(message))

            if discount_type == Discount.TYPE_PERCENTAGE:
                percentage = cleaned_data.get('percentage')
                cleaned_data['value'] = None
                if not percentage:
                    message = _("Please enter how much discount you want to give.")
                    self.add_error('percentage', forms.ValidationError(message))

    def clean_value(self):
        value = self.cleaned_data['value']
        if value:
            value = smallest_currency_unit_converter(
                value,
                self.event.currency,
            )
        return value

    def clean_percentage(self):
        percentage = self.cleaned_data['percentage']
        if percentage:
            percentage /= 100  # convert 19 to 0.19
        return percentage

    def clean_valid_until(self):
        valid_until = self.cleaned_data['valid_until']
        if valid_until and valid_until > self.event.end_date:
            valid_until = self.event.end_date
        return valid_until

    def clean_valid_from(self):
        valid_from = self.cleaned_data['valid_from']
        if valid_from and valid_from > self.event.end_date:
            raise forms.ValidationError(_("Discount code should become valid \
                before the event starts."), code='valid_from')
        return valid_from

    def clean_code(self):
        code = self.cleaned_data['code']
        code_check = self.event.discounts.filter(
            code=code
        ).exclude(pk=self.instance.pk).exists()

        if code_check:
            raise forms.ValidationError(_("The code you chose as your discount code \
                    already exists for this event. Please change it."), code='code_exists')
        return code

Теперь я понял, что «request.POST »содержит опубликованные значения билетов, например, ´'tickets ': [' 2 ',' 5 '] `Похоже, моя пользовательская визуализированная форма не получает эти значения. Я до сих пор не знаю почему

Joey Coder 09.11.2018 14:01
Почему в Python есть оператор "pass"?
Почему в Python есть оператор "pass"?
Оператор pass в Python - это простая концепция, которую могут быстро освоить даже новички без опыта программирования.
Некоторые методы, о которых вы не знали, что они существуют в Python
Некоторые методы, о которых вы не знали, что они существуют в Python
Python - самый известный и самый простой в изучении язык в наши дни. Имея широкий спектр применения в области машинного обучения, Data Science,...
Основы Python Часть I
Основы Python Часть I
Вы когда-нибудь задумывались, почему в программах на Python вы видите приведенный ниже код?
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
Алиса и Боб имеют неориентированный граф из n узлов и трех типов ребер:
Оптимизация кода с помощью тернарного оператора Python
Оптимизация кода с помощью тернарного оператора Python
И последнее, что мы хотели бы показать вам, прежде чем двигаться дальше, это
Советы по эффективной веб-разработке с помощью Python
Советы по эффективной веб-разработке с помощью Python
Как веб-разработчик, Python может стать мощным инструментом для создания эффективных и масштабируемых веб-приложений.
0
1
212
1

Ответы 1

После того, как я решил проблему, окончательное решение, которое мне помогло, можно найти здесь: Шаблон Django: {% if 5 in ['4', '3', '5']%} не работает

Другие вопросы по теме