В форме Django как сделать поле доступным только для чтения (или отключенным)?
Когда форма используется для создания новой записи, все поля должны быть включены, но когда запись находится в режиме обновления, некоторые поля должны быть доступны только для чтения.
Например, при создании новой Item
модели все поля должны быть доступны для редактирования, но при обновлении записи есть ли способ отключить sku
поле, чтобы оно было видимым, но не могло быть отредактировано?
class Item(models.Model):
sku = models.CharField(max_length=50)
description = models.CharField(max_length=200)
added_by = models.ForeignKey(User)
class ItemForm(ModelForm):
class Meta:
model = Item
exclude = ('added_by')
def new_item_view(request):
if request.method == 'POST':
form = ItemForm(request.POST)
# Validate and save
else:
form = ItemForm()
# Render the view
Можно ItemForm
ли повторно использовать класс ? Какие изменения потребуются в классе ItemForm
или Item
модели? Нужно ли мне писать другой класс " ItemUpdateForm
" для обновления элемента?
def update_item_view(request):
if request.method == 'POST':
form = ItemUpdateForm(request.POST)
# Validate and save
else:
form = ItemUpdateForm()
Ответы:
Как указано в этом ответе , Django 1.9 добавил атрибут Field.disabled :
В Django 1.8 и более ранних версиях, чтобы отключить запись в виджете и предотвратить злонамеренные POST-хаки, вы должны очистить ввод в дополнение к настройке
readonly
атрибута в поле формы:Или замените
if instance and instance.pk
другое условие, указывающее, что вы редактируете. Вы также можете установить атрибутdisabled
в поле ввода вместоreadonly
.clean_sku
Функция гарантирует , чтоreadonly
значение не будет переопределенPOST
.В противном случае, нет встроенного поля формы Django, которое будет отображать значение при отклонении связанных входных данных. Если это то, что вы хотите, вы должны вместо этого создать отдельное
ModelForm
, исключающее не редактируемые поля, и просто распечатать их внутри вашего шаблона.источник
clean_description
метод в класс формы.disabled
добавлен в Django 1.9. ЕслиField.disabled
установлено значениеTrue
, то значение POST для этогоField
игнорируется. Так что, если вы используете 1.9, нет необходимости переопределятьclean
, просто установитеdisabled = True
. Проверьте этот ответ.Django 1.9 добавил атрибут Field.disabled: https://docs.djangoproject.com/en/stable/ref/forms/fields/#disabled
источник
disabled=True
приведет к тому, что модель будет возвращена пользователю с ошибками проверки.Настройка
readonly
для виджета делает ввод только в браузере только для чтения. Добавлениеclean_sku
возвращающегоinstance.sku
гарантирует, что значение поля не изменится на уровне формы.Таким образом, вы можете использовать модель (неизмененное сохранение) и избежать появления ошибки в поле.
источник
return self.cleaned_data['sku']
так же хорошо или лучше? В документах , кажется, предлагают использоватьcleaned_data
: «Возвращаемое значение этого метода заменяет существующее значение вcleaned_data
, поэтому оно должно быть значением поля изcleaned_data
(даже если этот метод не изменит его) или новое значение очищены.»Ответ awalker мне очень помог!
Я изменил его пример для работы с Django 1.3, используя get_readonly_fields .
Обычно вы должны объявить что-то вроде этого в
app/admin.py
:Я адаптировался таким образом:
И это работает отлично. Теперь, если вы добавляете Item,
url
поле доступно для чтения и записи, но при изменении оно становится доступным только для чтения.источник
Чтобы сделать эту работу для
ForeignKey
поля, необходимо внести несколько изменений. Во-первых,SELECT HTML
тег не имеет атрибута readonly. Нам нужно использоватьdisabled="disabled"
вместо этого. Однако браузер не отправляет данные формы для этого поля. Поэтому мы должны установить это поле как необязательное, чтобы поле корректно проверялось. Затем нам нужно сбросить значение обратно к тому, что было раньше, чтобы оно не было пустым.Так что для внешних ключей вам нужно сделать что-то вроде:
Таким образом, браузер не позволит пользователю изменить поле и всегда будет оставаться
POST
пустым. Затем мы переопределяемclean
метод, чтобы установить значение поля равным тому, что было изначально в экземпляре.источник
TabularInline
, но не получилось, потому чтоattrs
были разделены междуwidget
экземплярами и всеми, кроме первой строки, включая только что добавленную, отображаемую только для чтения.Для Django 1.2+ вы можете переопределить поле следующим образом:
источник
Field
disabled
не делает то, что я хочу, потому что это отключает поле, но также удаляет метку / делает его невидимым.Я создал класс MixIn, который вы можете унаследовать, чтобы иметь возможность добавлять итерируемое поле read_only, которое отключит и защитит поля при не первом редактировании:
(На основе ответов Даниила и Мухука)
источник
Я только что создал простейший виджет для поля, доступного только для чтения - я не понимаю, почему в формах его уже нет:
В виде:
Очень просто - и дает мне только вывод. Удобно в форме с набором значений только для чтения. Конечно, вы также можете быть немного умнее и дать ему div с attrs, чтобы вы могли добавлять к нему классы.
источник
unicode(value)
Возможно, сделайте это взамен. Если предположить, что Unicode Dunder имеет смысл, вы получите это.Я столкнулся с подобной проблемой. Похоже, я смог решить эту проблему, определив метод get_readonly_fields в своем классе ModelAdmin.
Что-то вроде этого:
Приятно, что
obj
это будет None, когда вы добавляете новый Предмет, или это будет объект, который редактируется, когда вы меняете существующий Предмет.get_readonly_display задокументировано здесь: http://docs.djangoproject.com/en/1.2/ref/contrib/admin/#modeladmin-methods
источник
Один простой вариант - просто набрать
form.instance.fieldName
шаблон вместоform.fieldName
.источник
verbos_name
илиlabel
поля? Как мне показать `label в шаблоне django? @alzclarkeКак я делаю это с Django 1.11:
источник
Как полезное дополнение к посту Хамфри , у меня были некоторые проблемы с django-reversion, потому что он все еще регистрировал отключенные поля как «измененные». Следующий код решает проблему.
источник
Поскольку я пока не могу комментировать ( решение Мухука ), я отвечу отдельным ответом. Это полный пример кода, который работал для меня:
источник
Еще раз, я собираюсь предложить еще одно решение :) Я использовал код Хамфри , так что это основано на этом.
Тем не менее, я столкнулся с проблемами в этой области
ModelChoiceField
. Все будет работать по первому запросу. Однако, если набор форм попытался добавить новый элемент и не прошел проверку, что-то пошло не так с «существующими» формами, гдеSELECTED
параметр сбрасывался на значение по умолчанию---------
.Во всяком случае, я не мог понять, как это исправить. Итак, вместо этого (и я думаю, что это на самом деле чище в форме), я сделал поля
HiddenInputField()
. Это просто означает, что вы должны сделать немного больше работы в шаблоне.Поэтому для меня было проще упростить форму:
А затем в шаблоне вам нужно будет выполнить некоторые ручные циклы набора форм .
Итак, в этом случае вы должны сделать что-то подобное в шаблоне:
Это сработало немного лучше для меня и с меньшими манипуляциями с формой.
источник
Я столкнулся с той же проблемой, поэтому я создал Mixin, который, кажется, работает для моих вариантов использования.
Использование, просто определите, какие из них должны быть только для чтения:
источник
'collections.OrderedDict' object has no attribute 'iteritems'
если вам нужно несколько полей только для чтения. вы можете использовать любой из методов, приведенных ниже
способ 1
способ 2
метод наследования
источник
Еще два (похожих) подхода с одним обобщенным примером:
1) первый подход - удаление поля в методе save (), например (не проверено;)):
2) второй подход - сброс поля к исходному значению в чистом методе:
Основываясь на втором подходе, я обобщил это так:
источник
Для версии Admin, я думаю, это более компактный способ, если у вас есть более одного поля:
источник
Основываясь на ответе Ямикепа , я нашел лучшее и очень простое решение, которое также обрабатывает
ModelMultipleChoiceField
поля.Удаление поля из
form.cleaned_data
предотвращает сохранение полей:Применение:
источник
Вот немного более сложная версия, основанная на ответе christophe31 . Он не зависит от атрибута «только для чтения». Это делает его проблемы, такие как блоки выбора, все еще изменяемые и сборщики данных, все еще выскакивающие, уходят.
Вместо этого он оборачивает виджет полей формы в виджет только для чтения, тем самым делая форму по-прежнему валидной. Содержимое исходного виджета отображается внутри
<span class="hidden"></span>
тегов. Если у виджета естьrender_readonly()
метод, он использует его в качестве видимого текста, в противном случае он анализирует HTML исходного виджета и пытается угадать наилучшее представление.источник
Это самый простой способ?
Прямо в коде представления что-то вроде этого:
Работает отлично!
источник
Для django 1.9+
Вы можете использовать аргумент «Поля отключен», чтобы отключить поле. Например, в следующем фрагменте кода из файла forms.py я отключил поле employee_code
Ссылка https://docs.djangoproject.com/en/2.0/ref/forms/fields/#disabled
источник
Если вы работаете с
Django ver < 1.9
( атрибут1.9
hasField.disabled
Added), вы можете попробовать добавить следующий декоратор в ваш__init__
метод формы :Основная идея заключается в том, что если поле -
readonly
вам не нужно ничего другого, кромеinitial
.PS: не забудьте установить
yuor_form_field.widget.attrs['readonly'] = True
источник
Если вы используете администратор Django, вот самое простое решение.
источник
Я думаю, что вашим лучшим вариантом будет просто включить атрибут readonly в шаблон, отображаемый в
<span>
или<p>
вместо того, чтобы включать его в форму, если он доступен только для чтения.Формы предназначены для сбора данных, а не их отображения. При этом параметры для отображения в
readonly
виджете и очистки данных POST являются прекрасным решением.источник