В Odoo 16 я пытаюсь сделать все поля из представления формы доступными только для чтения в зависимости от значения другого поля той же формы.
Сначала я попробовал следующее:
<xpath expr = "//field" position = "attributes">
<attribute name = "attrs">{'readonly': [('my_field', '=', True)]}</attribute>
</xpath>
Без результата.
Я не могу использовать <form edit = "false">
, так как мне нужно проверить значение поля.
Правило с <field name = "perm_write">1</field>
работает, но оно не ведет себя так, как мне нужно, поскольку позволяет вам изменять всю форму до тех пор, пока вы не нажмете «Сохранить» и не получите ошибку разрешения.
И перезапись get_view
не является допустимым вариантом, поскольку не может зависеть от значения my_field
.
Единственное решение, которое я могу найти, — это изменить каждое поле формы с помощью xpath
, что довольно неприятно и несовместимо, если в будущем в представление формы будут добавлены дополнительные поля через другие приложения.
Есть ли у кого-нибудь лучшее решение для этого?
О, возможно, это не так уж и сложно, вот пример, как это сделать: github.com/OCA/server-ux/commit/…
@CZoellner отличная идея! Это сработало! Вы можете опубликовать это как ответ, я отредактирую его с помощью кода, который использовал, и сделаю его правильным ответом. Спасибо!
Продление get_view
на самом деле — хорошая идея. В server-ux repo OCA есть модуль, где делается нечто подобное: когда что-то сохраняется в поле one2many, каждое поле в представлении формы будет установлено только для чтения. Для этого для каждого поля перезаписывается модификатор readonly.
Модуль: base_tier_validation
Интересная часть кода: get_view
Код для вашего случая:
@api.model
def get_view(self, view_id=None, view_type = "form", **options):
res = super().get_view(
view_id=view_id,
view_type=view_type,
**options,
)
if view_type == "form":
doc = etree.XML(res["arch"])
for field in doc.xpath("//field[@name][not(ancestor::field)]"):
modifiers = json.loads(
field.attrib.get("modifiers", '{"readonly": false}')
)
if modifiers.get("readonly") is not True:
modifiers["readonly"] = OR(
[
modifiers.get(
"readonly", []
) or [],
[("my_field", " = ", True)],
]
)
field.attrib["modifiers"] = json.dumps(modifiers)
res["arch"] = etree.tostring(doc, pretty_print=True)
return res
@forvas, ты уверен, что удаление предковой части из xpath того стоит?
Конечно, это была не очень хорошая идея, слава вам... без предковой части взаимодействие с любым полем one2many (и многим другим...) выдавало ошибку Uncaught Promise
, что очевидно. Еще раз спасибо!
А как насчет комбинации переопределения
get_view
и добавленияattrs
атрибутов только для чтения? Это может сработать, но вам нужно проверить множество особых случаев, таких как поля дочерней модели (one2many/many2many) или поля, уже имеющие атрибуты. В конце концов, использование XPath - наименее красивый способ, но, вероятно, единственный простой рабочий.