python - Django:FormValidationError 时不保存复选框
问题描述
我正在使用 CreateView。当发送我的表单并正确填写所有字段时,字段票(ManyToMany 字段)也被保存。但是,如果我POST
的表单有一些验证错误(例如必填字段为空),那么所有预填充的字段仍然是字段request.POST
。但是,我的预先检查的字段不再被选中。你知道为什么吗?
视图.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">%</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>
表格.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
解决方案
在我解决问题后,可以在这里找到帮助我的最终解决方案:Django template: {% if 5 in ['4', '3', '5'] %} doesn't work
推荐阅读
- c++ - gdb 正在跳过指令
- c# - 如何在插入数据的同时将一张表复制到另一张表
- java - 与等效的 Java 代码相比,C# BitConverter 输出错误的双精度值
- r - R 参考类中的非标准集合函数
- java - Groovy OpenCSV 使用反斜杠读取值(例如 "domain\user" )
- python - 设置多对多关系
- kubernetes - 在维护期间强制 Ingress 返回 503
- git - 如何阻止 Git 生成 .new 文件?
- python - 在 Python 中增加 ascii 值时出现 NameError
- c++ - 是否有测试 lambda 对象的类型特征谓词?