带有自定义字段模板的 Django Crispy Forms 没有添加要请求的字段值
Django Crispy Forms with custom field template is not adding the value of the field to request
我在我的项目中使用 Django 1.10 和 django-crispy-forms 1.6.1。我添加了一个似乎正常运行的自定义 datetimepicker 下拉模板。我现在遇到的问题是,每次我尝试提交表单时,我都会在需要的字段上闪现错误。貌似提交表单后,字段被清空了,字段中加入了错误class。
After submit, form shows errors
当我检查控制台时,我没有收到任何错误,但是当我检查 Chrome DevTools 时,我查看了服务器端发送的请求负载,我发现该字段根本没有添加到要求。这是来自开发工具的请求负载的图片。
DevTools request payload without "time_stamp"
当输入获得焦点时,我能够让日期时间选择器下拉,这似乎工作得很好。这是我的 forms/views 和自定义 template.html:
的相关代码
models.py
class Call(models.Model):
history = AuditlogHistoryField()
analyst = models.ForeignKey(settings.AUTH_USER_MODEL, models.SET_NULL, blank=True, null=True, limit_choices_to={'is_staff': True}, related_name='call_analyst')
contact = models.CharField(max_length=50)
time_stamp = models.DateTimeField(default=datetime.now)
description = models.CharField(max_length=512)
ticket = models.PositiveIntegerField(blank=True, null=True)
CALL_TYPE = (
('M', 'Made'),
('R', 'Received'),
)
call_type = models.CharField(max_length=1, choices=CALL_TYPE)
created_at = models.DateTimeField(auto_now_add=True)
modified_at = models.DateTimeField(auto_now=True)
@python_2_unicode_compatible
def __str__(self):
return "Call instance {}".format(self.pk)
forms.py
class CallForm(forms.ModelForm):
description = forms.CharField(widget=forms.Textarea)
class Meta:
model = Call
fields = ['analyst', 'contact', 'time_stamp', 'description', 'ticket', 'call_type']
def __init__(self, *args, **kwargs):
super(CallForm, self).__init__(*args, **kwargs)
self.helper = FormHelper(self)
self.helper.form_tag = True
self.helper.form_class = 'form-horizontal'
self.helper.label_class = 'col-sm-3'
self.helper.field_class = 'col-sm-9'
self.helper.layout = Layout(
Field('analyst'),
Field('contact'),
Field('time_stamp', template="datetimepicker.html"),
Field('description'),
Field('ticket'),
Field('call_type'),
)
def is_valid(self):
return super(CallForm, self).is_valid()
def full_clean(self):
return super(CallForm, self).full_clean()
def clean_analyst(self):
analyst = self.cleaned_data.get("analyst", None)
return analyst
def clean_contact(self):
contact = self.cleaned_data.get("contact", None)
return contact
def clean_time_stamp(self):
time_stamp = self.cleaned_data.get("time_stamp", None)
return time_stamp
def clean_description(self):
description = self.cleaned_data.get("description", None)
return description
def clean_ticket(self):
ticket = self.cleaned_data.get("ticket", None)
return ticket
def clean_call_type(self):
call_type = self.cleaned_data.get("call_type", None)
return call_type
def clean(self):
return super(CallForm, self).clean()
def validate_unique(self):
return super(CallForm, self).validate_unique()
def save(self, commit=True):
return super(CallForm, self).save(commit)
views.py
class CallCreateView(AjaxCreateView):
model = Call
form_class = CallForm
# fields = ['analyst', 'contact', 'call_timestamp', 'description', 'ticket', 'call_type']
template_name = "reports/../_templates/create_update_template.html"
success_url = reverse_lazy("call_list")
def __init__(self, **kwargs):
super(CallCreateView, self).__init__(**kwargs)
def dispatch(self, request, *args, **kwargs):
return super(CallCreateView, self).dispatch(request, *args, **kwargs)
def get(self, request, *args, **kwargs):
return super(CallCreateView, self).get(request, *args, **kwargs)
def post(self, request, *args, **kwargs):
return super(CallCreateView, self).post(request, *args, **kwargs)
def get_form_class(self):
return super(CallCreateView, self).get_form_class()
def get_form(self, form_class=None):
return super(CallCreateView, self).get_form(form_class)
def get_form_kwargs(self, **kwargs):
return super(CallCreateView, self).get_form_kwargs()
def get_initial(self):
return super(CallCreateView, self).get_initial()
def form_invalid(self, form):
return super(CallCreateView, self).form_invalid(form)
def form_valid(self, form):
obj = form.save(commit=False)
obj.save()
return super(CallCreateView, self).form_valid(form)
def get_context_data(self, **kwargs):
ret = super(CallCreateView, self).get_context_data(**kwargs)
return ret
def render_to_response(self, context, **response_kwargs):
return super(CallCreateView, self).render_to_response(context, **response_kwargs)
def get_template_names(self):
return super(CallCreateView, self).get_template_names()
def get_success_url(self):
return reverse("call_detail", args=(self.object.pk,))
datetimepicker.html
{% load crispy_forms_field %}
<div{% if div.css_id %} id="{{ div.css_id }}"{% endif %}
class="form-group{% if form_show_errors and field.errors %} has-error{% endif %}{% if field.css_classes %} {{ field.css_classes }}{% endif %}{% if div.css_class %} {{ div.css_class }}{% endif %}">
{% if field.label and form_show_labels %}
<label for="{{ field.id_for_label }}"
class="control-label {{ label_class }}{% if field.field.required %} requiredField{% endif %}">
{{ field.label|safe }}{% if field.field.required %}<span class="asteriskField">*</span>{% endif %}
</label>
{% endif %}
<div class="controls date datetimepicker col-sm-9" id="{{ field.id_for_label }}"
data-link-field="{{ field.id_for_label }}" {{ flat_attrs|safe }}>
<input class="form-control" id="{{ field.id_for_label }}" type="text">
</div>
<input type="hidden" id="{{ field.id_for_label }}" value=""/><br/>
{% include 'bootstrap3/layout/help_text_and_errors.html' %}
</div>
{% block datetimepicker %}
<script type="text/javascript">
$(function () {
$('#{{ field.id_for_label }}').datetimepicker({
sideBySide: true,
allowInputToggle: true,
showTodayButton: true,
showClear: true,
showClose: true,
toolbarPlacement: "top",
format: "dddd, MMMM Do YYYY, h:mm A"
})
})
</script>
{% endblock %}
我认为我的模板一定有问题,或者 django-crispy-forms 如何处理使用自定义模板的字段,因为当我从表单助手中删除模板时,使用了常规输入框并且日期时间字符串提交给 django 就好了。感谢大家的帮助。抱歉,我不得不 link 图片,我没有足够高的代表来嵌入它们。
我认为 time_stamp
没有被发送到服务器的原因是日期选择器 input
标签没有 name
属性:
<input class="form-control" id="{{ field.id_for_label }}" type="text">
Note: Only form elements with a name
attribute will have their values passed when submitting a form.
我在我的项目中使用 Django 1.10 和 django-crispy-forms 1.6.1。我添加了一个似乎正常运行的自定义 datetimepicker 下拉模板。我现在遇到的问题是,每次我尝试提交表单时,我都会在需要的字段上闪现错误。貌似提交表单后,字段被清空了,字段中加入了错误class。
After submit, form shows errors
当我检查控制台时,我没有收到任何错误,但是当我检查 Chrome DevTools 时,我查看了服务器端发送的请求负载,我发现该字段根本没有添加到要求。这是来自开发工具的请求负载的图片。
DevTools request payload without "time_stamp"
当输入获得焦点时,我能够让日期时间选择器下拉,这似乎工作得很好。这是我的 forms/views 和自定义 template.html:
的相关代码models.py
class Call(models.Model):
history = AuditlogHistoryField()
analyst = models.ForeignKey(settings.AUTH_USER_MODEL, models.SET_NULL, blank=True, null=True, limit_choices_to={'is_staff': True}, related_name='call_analyst')
contact = models.CharField(max_length=50)
time_stamp = models.DateTimeField(default=datetime.now)
description = models.CharField(max_length=512)
ticket = models.PositiveIntegerField(blank=True, null=True)
CALL_TYPE = (
('M', 'Made'),
('R', 'Received'),
)
call_type = models.CharField(max_length=1, choices=CALL_TYPE)
created_at = models.DateTimeField(auto_now_add=True)
modified_at = models.DateTimeField(auto_now=True)
@python_2_unicode_compatible
def __str__(self):
return "Call instance {}".format(self.pk)
forms.py
class CallForm(forms.ModelForm):
description = forms.CharField(widget=forms.Textarea)
class Meta:
model = Call
fields = ['analyst', 'contact', 'time_stamp', 'description', 'ticket', 'call_type']
def __init__(self, *args, **kwargs):
super(CallForm, self).__init__(*args, **kwargs)
self.helper = FormHelper(self)
self.helper.form_tag = True
self.helper.form_class = 'form-horizontal'
self.helper.label_class = 'col-sm-3'
self.helper.field_class = 'col-sm-9'
self.helper.layout = Layout(
Field('analyst'),
Field('contact'),
Field('time_stamp', template="datetimepicker.html"),
Field('description'),
Field('ticket'),
Field('call_type'),
)
def is_valid(self):
return super(CallForm, self).is_valid()
def full_clean(self):
return super(CallForm, self).full_clean()
def clean_analyst(self):
analyst = self.cleaned_data.get("analyst", None)
return analyst
def clean_contact(self):
contact = self.cleaned_data.get("contact", None)
return contact
def clean_time_stamp(self):
time_stamp = self.cleaned_data.get("time_stamp", None)
return time_stamp
def clean_description(self):
description = self.cleaned_data.get("description", None)
return description
def clean_ticket(self):
ticket = self.cleaned_data.get("ticket", None)
return ticket
def clean_call_type(self):
call_type = self.cleaned_data.get("call_type", None)
return call_type
def clean(self):
return super(CallForm, self).clean()
def validate_unique(self):
return super(CallForm, self).validate_unique()
def save(self, commit=True):
return super(CallForm, self).save(commit)
views.py
class CallCreateView(AjaxCreateView):
model = Call
form_class = CallForm
# fields = ['analyst', 'contact', 'call_timestamp', 'description', 'ticket', 'call_type']
template_name = "reports/../_templates/create_update_template.html"
success_url = reverse_lazy("call_list")
def __init__(self, **kwargs):
super(CallCreateView, self).__init__(**kwargs)
def dispatch(self, request, *args, **kwargs):
return super(CallCreateView, self).dispatch(request, *args, **kwargs)
def get(self, request, *args, **kwargs):
return super(CallCreateView, self).get(request, *args, **kwargs)
def post(self, request, *args, **kwargs):
return super(CallCreateView, self).post(request, *args, **kwargs)
def get_form_class(self):
return super(CallCreateView, self).get_form_class()
def get_form(self, form_class=None):
return super(CallCreateView, self).get_form(form_class)
def get_form_kwargs(self, **kwargs):
return super(CallCreateView, self).get_form_kwargs()
def get_initial(self):
return super(CallCreateView, self).get_initial()
def form_invalid(self, form):
return super(CallCreateView, self).form_invalid(form)
def form_valid(self, form):
obj = form.save(commit=False)
obj.save()
return super(CallCreateView, self).form_valid(form)
def get_context_data(self, **kwargs):
ret = super(CallCreateView, self).get_context_data(**kwargs)
return ret
def render_to_response(self, context, **response_kwargs):
return super(CallCreateView, self).render_to_response(context, **response_kwargs)
def get_template_names(self):
return super(CallCreateView, self).get_template_names()
def get_success_url(self):
return reverse("call_detail", args=(self.object.pk,))
datetimepicker.html
{% load crispy_forms_field %}
<div{% if div.css_id %} id="{{ div.css_id }}"{% endif %}
class="form-group{% if form_show_errors and field.errors %} has-error{% endif %}{% if field.css_classes %} {{ field.css_classes }}{% endif %}{% if div.css_class %} {{ div.css_class }}{% endif %}">
{% if field.label and form_show_labels %}
<label for="{{ field.id_for_label }}"
class="control-label {{ label_class }}{% if field.field.required %} requiredField{% endif %}">
{{ field.label|safe }}{% if field.field.required %}<span class="asteriskField">*</span>{% endif %}
</label>
{% endif %}
<div class="controls date datetimepicker col-sm-9" id="{{ field.id_for_label }}"
data-link-field="{{ field.id_for_label }}" {{ flat_attrs|safe }}>
<input class="form-control" id="{{ field.id_for_label }}" type="text">
</div>
<input type="hidden" id="{{ field.id_for_label }}" value=""/><br/>
{% include 'bootstrap3/layout/help_text_and_errors.html' %}
</div>
{% block datetimepicker %}
<script type="text/javascript">
$(function () {
$('#{{ field.id_for_label }}').datetimepicker({
sideBySide: true,
allowInputToggle: true,
showTodayButton: true,
showClear: true,
showClose: true,
toolbarPlacement: "top",
format: "dddd, MMMM Do YYYY, h:mm A"
})
})
</script>
{% endblock %}
我认为我的模板一定有问题,或者 django-crispy-forms 如何处理使用自定义模板的字段,因为当我从表单助手中删除模板时,使用了常规输入框并且日期时间字符串提交给 django 就好了。感谢大家的帮助。抱歉,我不得不 link 图片,我没有足够高的代表来嵌入它们。
我认为 time_stamp
没有被发送到服务器的原因是日期选择器 input
标签没有 name
属性:
<input class="form-control" id="{{ field.id_for_label }}" type="text">
Note: Only form elements with a
name
attribute will have their values passed when submitting a form.