formdatas: add access from formdata to reverse_links (#57964) #766

Merged
lguerin merged 1 commits from wip/57964-revser-links into main 2023-12-07 18:07:01 +01:00
2 changed files with 193 additions and 0 deletions

View File

@ -5440,3 +5440,101 @@ def test_page_field_var(pub, formdef):
assert 'form_var_page' not in formdata.get_substitution_variables()
assert 'page' not in LazyFormData(formdata).var.inspect_keys()
def test_reverse_links(pub):
CardDef.wipe()
carddef1 = CardDef()
carddef1.name = 'Card 1'
carddef1.digest_templates = {'default': '{{form_var_name1}}'}
carddef1.fields = [
fields.StringField(id='0', label='string', varname='name1'),
]
carddef1.store()
carddata1 = carddef1.data_class()()
carddata1.data = {
'0': 'foo1',
}
carddata1.just_created()
carddata1.store()
ds = {'type': 'carddef:%s' % carddef1.url_name}
carddef2 = CardDef()
carddef2.name = 'Card 2'
carddef2.digest_templates = {'default': '{{form_var_name2}}'}
carddef2.fields = [
fields.StringField(id='0', label='string', varname='name2'),
fields.ItemField(id='1', label='string', varname='foo', data_source=ds),
]
carddef2.store()
carddata2 = carddef2.data_class()()
carddata2.data = {
'0': 'foo2',
'1': str(carddata1.id),
}
carddata2.data['1_display'] = carddef2.fields[1].store_display_value(carddata1.data, '0')
carddata2.data['1_structured'] = carddef2.fields[1].store_structured_value(carddata1.data, '0')
carddata2.just_created()
carddata2.store()
FormDef.wipe()
formdef = FormDef()
formdef.name = 'foobar'
formdef.fields = [fields.ItemField(id='0', label='string', varname='bar', data_source=ds)]
formdef.store()
formdata1 = formdef.data_class()()
formdata1.data = {
'0': str(carddata1.id),
}
formdata1.data['0_display'] = formdef.fields[0].store_display_value(carddata1.data, '0')
formdata1.data['0_structured'] = formdef.fields[0].store_structured_value(carddata1.data, '0')
formdata1.just_created()
formdata1.store()
formdata2 = formdef.data_class()()
formdata2.data = {
'0': str(carddata1.id),
}
formdata2.data['0_display'] = formdef.fields[0].store_display_value(carddata1.data, '0')
formdata2.data['0_structured'] = formdef.fields[0].store_structured_value(carddata1.data, '0')
formdata2.just_created()
formdata2.store()
# test reverse relation
carddef1.store() # build & store reverse_relations
pub.substitutions.reset()
pub.substitutions.feed(pub)
pub.substitutions.feed(carddef1)
pub.substitutions.feed(carddata1)
context = pub.substitutions.get_context_variables(mode='lazy')
assert len(context['form_reverse_links_formdef_foobar_bar']) == 2
assert context['form_reverse_links_formdef_foobar_bar_0_form_internal_id'] == formdata1.id
assert context['form_reverse_links_formdef_foobar_bar_1_form_internal_id'] == formdata2.id
assert len(context['form_reverse_links_carddef_card_2_foo']) == 1
assert context['form_reverse_links_carddef_card_2_foo_0_form_internal_id'] == carddata2.id
# test with natural id
carddef1.id_template = 'X{{ form_var_name1 }}Y'
carddef1.store()
carddata1.store()
assert carddata1.id_display == 'Xfoo1Y'
carddata2.data['1'] = carddata1.get_natural_key()
carddata2.store()
formdata1.data['0'] = carddata1.get_natural_key()
formdata1.just_created()
formdata1.store()
formdata2 = formdef.data_class()()
formdata2.data['0'] = carddata1.get_natural_key()
formdata2.just_created()
formdata2.store()
pub.substitutions.reset()
pub.substitutions.feed(pub)
pub.substitutions.feed(carddef1)
pub.substitutions.feed(carddata1)
context = pub.substitutions.get_context_variables(mode='lazy')
assert len(context['form_reverse_links_formdef_foobar_bar']) == 2
assert context['form_reverse_links_formdef_foobar_bar_0_form_internal_id'] == formdata1.id
assert context['form_reverse_links_formdef_foobar_bar_1_form_internal_id'] == formdata2.id
assert len(context['form_reverse_links_carddef_card_2_foo']) == 1
assert context['form_reverse_links_carddef_card_2_foo_0_form_internal_id'] == carddata2.id

View File

@ -991,6 +991,10 @@ class LazyFormData(LazyFormDef):
return LazyFormDataLinks(self._formdata)
@property
def reverse_links(self):
return LazyFormDataReverseLinks(self._formdata)
@property
def workflow_email(self):
# form_ workflow_email_ <slug (action varname)> _ <index> _ etc.
@ -1057,6 +1061,97 @@ class LazyFormData(LazyFormDef):
raise
class LazyFormDataReverseLinks:
def __init__(self, formdata):
self._formdata = formdata
_relations = None
@property
def relations(self):
if self._relations is not None:
return self._relations
self._relations = {}
for relation in self._formdata.formdef.reverse_relations:
if not relation['varname']:
continue
key = '%s_%s' % (relation['obj'], relation['varname'])
key = key.replace(':', '_').replace('-', '_')
self._relations[key] = relation
return self._relations
def inspect_keys(self):
return self.relations.keys()
def __getitem__(self, key):
if not isinstance(key, str):
raise KeyError(str(key))
relation = self.relations[key]
formdef_type, formdef_slug = relation['obj'].split(':')
formdef_class = FormDef
if formdef_type == 'carddef':
formdef_class = CardDef
formdef = formdef_class.get_by_slug(formdef_slug, ignore_errors=True)
if formdef is None:
return None
lazy_manager = LazyFormDefObjectsManager(formdef=formdef)
formdatas = [
LazyFormDataReverseLinksItem(formdata)
for formdata in lazy_manager.filter_by(relation['varname']).apply_filter_value(
str(self._formdata.get_natural_key())

Peut-être get_natural_key(), pour prendre en compte la possibilité d'id personnalisés ?

Peut-être get_natural_key(), pour prendre en compte la possibilité d'id personnalisés ?
)
]
if not formdatas:
return []
return LazyFormDataReverseLinksItems(formdatas)
class LazyFormDataReverseLinksItems:
inspect_collapse = True
def __init__(self, formdatas):
self._formdatas = formdatas
def inspect_keys(self):
return [str(x) for x in range(len(self._formdatas))]
def __getitem__(self, key):
try:
key = int(key)
except ValueError:
raise KeyError
return self._formdatas[key]
def __len__(self):
return len(self._formdatas)
def __iter__(self):
yield from self._formdatas
class LazyFormDataReverseLinksItem:
inspect_collapse = True
def __init__(self, formdata):
self._formdata = formdata
def inspect_keys(self):
return ['form']
@property
def form(self):

Et ici aussi, get_natural_key ?

Et ici aussi, get_natural_key ?
return self._formdata
def __getitem__(self, key):
try:
return getattr(self, key)
except AttributeError:
compat_dict = CompatibilityNamesDict({'form': self._formdata})
return compat_dict[key]
class LazyFormDataVar:
def __init__(self, fields, data, formdata=None, base_formdata=None):
self._fields = fields