Я думал, что поделюсь своим решением, основанным на нескольких других ответах SO.
Во-первых, вам не следует пытаться использовать Layout из Crispy Forms, потому что HTML из Jasny слишком отличается от стандартного шаблона Crispy Form. Сначала мы создаем шаблон Crispy Form, который работает с Jasny. Это в основном просто шаблон field.html, обновленный Jasny HTML.
file_field.html :
{# Custom Crispy Forms template for rendering an image field. #}
{% load crispy_forms_field %}
{% if field.is_hidden %}
{{ field }}
{% else %}
{% if field|is_checkbox %}
<div class="form-group">
{% if label_class %}
<div class="controls col-{{ bootstrap_device_type }}-offset-{{ label_size }} {{ field_class }}">
{% endif %}
{% endif %}
<{% if tag %}{{ tag }}{% else %}div{% endif %} id="div_{{ field.auto_id }}" {% if not field|is_checkbox %}class="form-group{% else %}class="checkbox{% endif %}{% if wrapper_class %} {{ wrapper_class }}{% endif %}{% if form_show_errors%}{% if field.errors %} has-error{% endif %}{% endif %}{% if field.css_classes %} {{ field.css_classes }}{% endif %}">
{% if field.label and not field|is_checkbox 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 %}
{% if field|is_checkboxselectmultiple %}
{% include 'bootstrap3/layout/checkboxselectmultiple.html' %}
{% endif %}
{% if field|is_radioselect %}
{% include 'bootstrap3/layout/radioselect.html' %}
{% endif %}
{% if not field|is_checkboxselectmultiple and not field|is_radioselect %}
{% if field|is_checkbox and form_show_labels %}
<label for="{{ field.id_for_label }}" class="{% if field.field.required %} requiredField{% endif %}">
{% crispy_field field %}
{{ field.label|safe }}
{% include 'bootstrap3/layout/help_text_and_errors.html' %}
</label>
{% else %}
<div class="controls {{ field_class }}">
<div class="fileinput fileinput-{% if field.value and field.value.url %}exists{% else %}new{% endif %}" data-provides="fileinput">
<div class="fileinput-new thumbnail" style="width: 200px; height: 150px;">
<img data-src="holder.js/100%x100%" alt="100%x100%" src="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxOTAiIGhlaWdodD0iMTQwIj48cmVjdCB3aWR0aD0iMTkwIiBoZWlnaHQ9IjE0MCIgZmlsbD0iI2VlZSIvPjx0ZXh0IHRleHQtYW5jaG9yPSJtaWRkbGUiIHg9Ijk1IiB5PSI3MCIgc3R5bGU9ImZpbGw6I2FhYTtmb250LXdlaWdodDpib2xkO2ZvbnQtc2l6ZToxMnB4O2ZvbnQtZmFtaWx5OkFyaWFsLEhlbHZldGljYSxzYW5zLXNlcmlmO2RvbWluYW50LWJhc2VsaW5lOmNlbnRyYWwiPjE5MHgxNDA8L3RleHQ+PC9zdmc+" style="height: 100%; width: 100%; display: block;">
</div>
<div class="fileinput-preview fileinput-exists thumbnail" style="max-width: 200px; max-height: 150px; line-height: 10px;">
{% if field.value and field.value.url %}
<img src="{{ field.value.url }}">
{% endif %}
</div>
{# imgfileinput, imgselect, imremove used for removing image #}
<div id="imgfileinput">
<span id="imgselect" class="btn btn-default btn-file">
<span class="fileinput-new">Select image</span>
<span class="fileinput-exists">Change</span>
<input id="imgfile" type="file" name="{{ field.name }}">
</span> 
<a id="imgremove" href="#" class="btn btn-default fileinput-exists" data-dismiss="fileinput">Remove</a>
</div>
</div>
{# removed {% crispy_field field %} #}
{% include 'bootstrap3/layout/help_text_and_errors.html' %}
</div>
{% endif %}
{% endif %}
</{% if tag %}{{ tag }}{% else %}div{% endif %}>
{% if field|is_checkbox %}
{% if label_class %}
</div>
{% endif %}
</div>
{% endif %}
{% endif %}
Во-вторых, ссылайтесь на шаблон при определении макета формы:
from crispy_forms.layout import Layout, Fieldset, Div, Submit, Reset, HTML, Field, Hidden
class UserForm(forms.ModelForm):
def __init__(self, *args, **kwargs):
super(UserForm, self).__init__(*args, **kwargs)
self.helper = FormHelper()
self.helper.layout = Layout(
Field('avatar', template='file_field.html'),
'username',
'first_name',
'last_name',
)
В-третьих, по умолчанию нет возможности легко очистить изображение с помощью Jasny и Django. Краткое описание поведения Jasny можно найти здесь а>. В основном Jasny отправляет None или пустую строку в зависимости от того, не было ли изображение обновлено или удалено. Django интерпретирует оба из них как изображение, которое не обновляется, а не удаляется.
Django использует виджет ClearableFileInput, который добавляет флажок, который следует установить, если вы хотите удалить файл. Чтобы имитировать эту функциональность, я просто добавил некоторый jQuery, чтобы добавить этот ввод, когда выбрана кнопка удаления, и удалить ввод, когда выбрана кнопка изменения или вставки:
<script>
// Allow image to be deleted
$('#imgremove').on('click', function() {
field_name = $('#imgfile')[0].getAttribute('name');
$('#imgfileinput').append('<input id="imgclear" type="hidden" name="'+field_name+'-clear" value="on">');
})
$('#imgselect').on('click', function() {
$('#imgclear').remove();
})
</script>
Вы заметите, что мой HTML-код Jasny выше был немного изменен, чтобы включить идентификаторы для интересующих тегов, чтобы упростить выбор.
Кажется, что это большая работа, но как только она будет сделана, ее так же легко использовать, как и обычные хрустящие формы.
person
freb
schedule
19.08.2014