update related cards/forms on digest change (#68427) #1241
|
@ -604,10 +604,10 @@ def test_item_field_from_custom_view_on_cards(pub):
|
|||
resp = app.get(formdef.data_class().select()[0].get_url())
|
||||
assert resp.pyquery('.field-type-item .value').text() == 'Yattr%sZ' % baz_id
|
||||
|
||||
# remove card (back to value stored at first)
|
||||
# remove card, the value is still displayed
|
||||
carddef.data_class().wipe()
|
||||
resp = app.get(formdef.data_class().select()[0].get_url())
|
||||
assert resp.pyquery('.field-type-item .value').text() == 'Xattr%sY' % baz_id
|
||||
assert resp.pyquery('.field-type-item .value').text() == 'Yattr%sZ' % baz_id
|
||||
|
||||
|
||||
|
||||
def test_item_field_from_custom_view_on_cards_filter_status(pub):
|
||||
|
|
|
@ -13,6 +13,7 @@ from wcs.blocks import BlockDef
|
|||
from wcs.carddef import CardDef
|
||||
from wcs.categories import Category
|
||||
from wcs.data_sources import NamedDataSource
|
||||
from wcs.formdef import FormDef
|
||||
from wcs.wf.create_formdata import Mapping
|
||||
from wcs.workflows import Workflow
|
||||
|
||||
|
@ -634,6 +635,7 @@ def test_form_page_item_with_variable_data_source_prefill(pub):
|
|||
def test_form_page_item_with_card_with_custom_id_prefill(pub):
|
||||
create_user(pub)
|
||||
CardDef.wipe()
|
||||
FormDef.wipe()
|
||||
fpeters
commented
Tests ajoutés récemment, il y a un carddata.store() exécuté avec les restes de reverse_relations sans rapport, il faut nettoyer correctement. Tests ajoutés récemment, il y a un carddata.store() exécuté avec les restes de reverse_relations sans rapport, il faut nettoyer correctement.
|
||||
|
||||
carddef = CardDef()
|
||||
carddef.name = 'Test'
|
||||
|
@ -678,6 +680,7 @@ def test_form_page_item_with_card_with_custom_id_prefill(pub):
|
|||
def test_form_page_block_with_item_with_card_with_custom_id_prefill(pub):
|
||||
create_user(pub)
|
||||
CardDef.wipe()
|
||||
FormDef.wipe()
|
||||
|
||||
carddef = CardDef()
|
||||
carddef.name = 'Test'
|
||||
|
|
|
@ -5,6 +5,7 @@ import xml.etree.ElementTree as ET
|
|||
import pytest
|
||||
|
||||
from wcs.blocks import BlockDef
|
||||
from wcs.carddata import UpdateRelationsAfterJob
|
||||
from wcs.carddef import CardDef
|
||||
from wcs.categories import CardDefCategory
|
||||
from wcs.data_sources import NamedDataSource
|
||||
|
@ -1328,3 +1329,346 @@ def test_card_custom_id_format(pub):
|
|||
assert data_class.force_valid_id_characters('_Fôô bar-') == '_Foo-bar-'
|
||||
assert data_class.force_valid_id_characters('_Fôô bar☭-') == '_Foo-bar-'
|
||||
assert data_class.force_valid_id_characters('_Fôô bar❗') == '_Foo-bar'
|
||||
|
||||
|
||||
def test_card_update_related(pub):
|
||||
BlockDef.wipe()
|
||||
CardDef.wipe()
|
||||
FormDef.wipe()
|
||||
|
||||
carddef = CardDef()
|
||||
carddef.name = 'foo'
|
||||
carddef.fields = [
|
||||
StringField(id='1', label='Test', varname='foo'),
|
||||
]
|
||||
carddef.digest_templates = {'default': '{{ form_var_foo }}'}
|
||||
carddef.store()
|
||||
carddef.data_class().wipe()
|
||||
|
||||
carddata1 = carddef.data_class()()
|
||||
carddata1.data = {'1': 'card1'}
|
||||
carddata1.just_created()
|
||||
carddata1.store()
|
||||
|
||||
carddata2 = carddef.data_class()()
|
||||
carddata2.data = {'1': 'card2'}
|
||||
carddata2.just_created()
|
||||
carddata2.store()
|
||||
|
||||
# check update against item field
|
||||
formdef = FormDef()
|
||||
formdef.name = 'foo'
|
||||
formdef.fields = [
|
||||
ItemField(id='1', label='Test', data_source={'type': 'carddef:foo'}),
|
||||
]
|
||||
formdef.store()
|
||||
|
||||
formdata = formdef.data_class()()
|
||||
formdata.data = {'1': '1'}
|
||||
formdata.data['1_display'] = formdef.fields[0].store_display_value(formdata.data, formdef.fields[0].id)
|
||||
assert formdata.data['1_display'] == 'card1'
|
||||
formdata.just_created()
|
||||
formdata.store()
|
||||
|
||||
pub.cleanup()
|
||||
carddef = carddef.get(carddef.id)
|
||||
carddata1 = carddef.data_class().get(carddata1.id)
|
||||
carddata1.data = {'1': 'card1-change1'}
|
||||
carddata1.store()
|
||||
|
||||
formdata.refresh_from_storage()
|
||||
assert formdata.data['1_display'] == 'card1-change1'
|
||||
|
||||
# check update against items field
|
||||
formdef = FormDef()
|
||||
formdef.name = 'foo'
|
||||
formdef.fields = [
|
||||
ItemsField(id='1', label='Test', data_source={'type': 'carddef:foo'}),
|
||||
]
|
||||
formdef.store()
|
||||
|
||||
formdata = formdef.data_class()()
|
||||
formdata.data = {'1': ['1', '2']}
|
||||
formdata.data['1_display'] = formdef.fields[0].store_display_value(formdata.data, formdef.fields[0].id)
|
||||
assert formdata.data['1_display'] == 'card1-change1, card2'
|
||||
formdata.just_created()
|
||||
formdata.store()
|
||||
|
||||
pub.cleanup()
|
||||
carddef = carddef.get(carddef.id)
|
||||
carddata1 = carddef.data_class().get(carddata1.id)
|
||||
carddata1.data = {'1': 'card1-change2'}
|
||||
carddata1.store()
|
||||
|
||||
formdata.refresh_from_storage()
|
||||
assert formdata.data['1_display'] == 'card1-change2, card2'
|
||||
|
||||
# check update against block field
|
||||
blockdef = BlockDef()
|
||||
blockdef.name = 'foo'
|
||||
blockdef.fields = [
|
||||
ItemField(id='1', label='Test', varname='bar', data_source={'type': 'carddef:foo'}),
|
||||
]
|
||||
blockdef.digest_template = 'bloc:{{ block_var_bar }}'
|
||||
blockdef.store()
|
||||
|
||||
formdef = FormDef()
|
||||
formdef.name = 'foo2'
|
||||
formdef.fields = [
|
||||
BlockField(id='1', label='Test', block_slug=blockdef.slug),
|
||||
]
|
||||
formdef.store()
|
||||
|
||||
formdata = formdef.data_class()()
|
||||
formdata.data = {
|
||||
'1': {
|
||||
'data': [
|
||||
{
|
||||
'1': '1',
|
||||
'1_display': 'card1-change2',
|
||||
},
|
||||
{
|
||||
'1': '2',
|
||||
'1_display': 'card2',
|
||||
},
|
||||
],
|
||||
'schema': {},
|
||||
}
|
||||
}
|
||||
|
||||
formdata.data['1_display'] = formdef.fields[0].store_display_value(formdata.data, formdef.fields[0].id)
|
||||
assert formdata.data['1_display'] == 'bloc:card1-change2, bloc:card2'
|
||||
formdata.just_created()
|
||||
formdata.store()
|
||||
|
||||
pub.cleanup()
|
||||
carddef = carddef.get(carddef.id)
|
||||
carddata1 = carddef.data_class().get(carddata1.id)
|
||||
carddata1.data = {'1': 'card1-change3'}
|
||||
carddata1.store()
|
||||
|
||||
formdata.refresh_from_storage()
|
||||
assert formdata.data['1']['data'][0]['1'] == '1'
|
||||
assert formdata.data['1']['data'][0]['1_display'] == 'card1-change3'
|
||||
assert formdata.data['1']['data'][1]['1'] == '2'
|
||||
assert formdata.data['1']['data'][1]['1_display'] == 'card2'
|
||||
assert formdata.data['1_display'] == 'bloc:card1-change3, bloc:card2'
|
||||
|
||||
|
||||
def test_card_update_related_with_custom_view(pub):
|
||||
CardDef.wipe()
|
||||
FormDef.wipe()
|
||||
pub.custom_view_class.wipe()
|
||||
|
||||
carddef = CardDef()
|
||||
carddef.name = 'foo'
|
||||
carddef.fields = [
|
||||
StringField(id='1', label='Test', varname='foo'),
|
||||
]
|
||||
carddef.digest_templates = {
|
||||
'default': '{{ form_var_foo }}',
|
||||
'custom-view:view': 'view-{{ form_var_foo }}',
|
||||
}
|
||||
carddef.store()
|
||||
carddef.data_class().wipe()
|
||||
|
||||
carddata1 = carddef.data_class()()
|
||||
carddata1.data = {'1': 'card1'}
|
||||
carddata1.just_created()
|
||||
carddata1.store()
|
||||
|
||||
carddata2 = carddef.data_class()()
|
||||
carddata2.data = {'1': 'card2'}
|
||||
carddata2.just_created()
|
||||
carddata2.store()
|
||||
|
||||
custom_view = pub.custom_view_class()
|
||||
custom_view.title = 'view'
|
||||
custom_view.formdef = carddef
|
||||
custom_view.columns = {'list': [{'id': 'id'}]}
|
||||
custom_view.filters = {}
|
||||
custom_view.visibility = 'datasource'
|
||||
custom_view.store()
|
||||
|
||||
formdef = FormDef()
|
||||
formdef.name = 'foo'
|
||||
formdef.fields = [
|
||||
ItemField(id='1', label='Test', data_source={'type': 'carddef:foo:view'}),
|
||||
]
|
||||
formdef.store()
|
||||
|
||||
formdata = formdef.data_class()()
|
||||
formdata.data = {'1': '1'}
|
||||
formdata.data['1_display'] = formdef.fields[0].store_display_value(formdata.data, formdef.fields[0].id)
|
||||
assert formdata.data['1_display'] == 'view-card1'
|
||||
formdata.just_created()
|
||||
formdata.store()
|
||||
|
||||
pub.cleanup()
|
||||
carddef = carddef.get(carddef.id)
|
||||
carddata1 = carddef.data_class().get(carddata1.id)
|
||||
carddata1.data = {'1': 'card1-change1'}
|
||||
carddata1.store()
|
||||
|
||||
formdata.refresh_from_storage()
|
||||
fpeters
commented
Vérification que sur une source de données sur une vue personnalisée, on obtient le résultat du digest template de la vue. Vérification que sur une source de données sur une vue personnalisée, on obtient le résultat du digest template de la vue.
|
||||
assert formdata.data['1_display'] == 'view-card1-change1'
|
||||
|
||||
|
||||
def test_card_update_related_cascading(pub):
|
||||
BlockDef.wipe()
|
||||
CardDef.wipe()
|
||||
FormDef.wipe()
|
||||
|
||||
carddef = CardDef()
|
||||
carddef.name = 'foo'
|
||||
carddef.fields = [
|
||||
StringField(id='1', label='Test', varname='foo'),
|
||||
]
|
||||
carddef.digest_templates = {'default': '{{ form_var_foo }}'}
|
||||
carddef.store()
|
||||
carddef.data_class().wipe()
|
||||
|
||||
carddata1 = carddef.data_class()()
|
||||
carddata1.data = {'1': 'card1'}
|
||||
carddata1.just_created()
|
||||
carddata1.store()
|
||||
|
||||
carddef2 = CardDef()
|
||||
carddef2.name = 'bar'
|
||||
carddef2.fields = [
|
||||
ItemField(id='1', label='Test', varname='foo', data_source={'type': 'carddef:foo'}),
|
||||
]
|
||||
fpeters
commented
Un digest template qui reprend la valeur _display d'une autre fiche, un changement sur la valeur de cette autre fiche amènera donc un changement sur cette fiche, le test vérifie que ça cascade bien ainsi. Un digest template qui reprend la valeur _display d'une autre fiche, un changement sur la valeur de cette autre fiche amènera donc un changement sur cette fiche, le test vérifie que ça cascade bien ainsi.
|
||||
carddef2.digest_templates = {'default': 'bar-{{ form_var_foo }}'}
|
||||
carddef2.store()
|
||||
carddef2.data_class().wipe()
|
||||
|
||||
carddata2 = carddef2.data_class()()
|
||||
carddata2.data = {'1': '1'}
|
||||
carddata2.data['1_display'] = carddef2.fields[0].store_display_value(
|
||||
carddata2.data, carddef2.fields[0].id
|
||||
)
|
||||
carddata2.just_created()
|
||||
carddata2.store()
|
||||
|
||||
formdef = FormDef()
|
||||
formdef.name = 'foo'
|
||||
formdef.fields = [
|
||||
ItemField(id='1', label='Test', data_source={'type': 'carddef:bar'}),
|
||||
]
|
||||
formdef.store()
|
||||
|
||||
formdata = formdef.data_class()()
|
||||
formdata.data = {'1': '1'}
|
||||
formdata.data['1_display'] = formdef.fields[0].store_display_value(formdata.data, formdef.fields[0].id)
|
||||
assert formdata.data['1_display'] == 'bar-card1'
|
||||
formdata.just_created()
|
||||
formdata.store()
|
||||
|
||||
pub.cleanup()
|
||||
carddef = carddef.get(carddef.id)
|
||||
carddata1 = carddef.data_class().get(carddata1.id)
|
||||
carddata1.data = {'1': 'card1-change1'}
|
||||
carddata1.store()
|
||||
|
||||
formdata.refresh_from_storage()
|
||||
assert formdata.data['1_display'] == 'bar-card1-change1'
|
||||
|
||||
|
||||
def test_card_update_related_cascading_loop(pub):
|
||||
BlockDef.wipe()
|
||||
CardDef.wipe()
|
||||
FormDef.wipe()
|
||||
|
||||
carddef = CardDef()
|
||||
carddef.name = 'foo'
|
||||
carddef.fields = [
|
||||
StringField(id='1', label='Test', varname='foo'),
|
||||
ItemField(id='2', label='Test', varname='x', data_source={'type': 'carddef:bar'}),
|
||||
]
|
||||
carddef.digest_templates = {'default': '{{ form_var_foo }} {{ form_var_x }}'}
|
||||
carddef.store()
|
||||
carddef.data_class().wipe()
|
||||
|
||||
carddef2 = CardDef()
|
||||
carddef2.name = 'bar'
|
||||
carddef2.fields = [
|
||||
StringField(id='1', label='Test', varname='foo'),
|
||||
ItemField(id='2', label='Test', varname='x', data_source={'type': 'carddef:foo'}),
|
||||
]
|
||||
carddef2.digest_templates = {'default': '{{ form_var_foo }} {{ form_var_x }}'}
|
||||
carddef2.store()
|
||||
carddef2.data_class().wipe()
|
||||
|
||||
carddata1 = carddef.data_class()()
|
||||
carddata1.data = {'1': 'card1'}
|
||||
carddata1.just_created()
|
||||
carddata1.store()
|
||||
|
||||
carddata2 = carddef2.data_class()()
|
||||
carddata2.data = {'1': 'card2', '2': '1'}
|
||||
carddata2.data['2_display'] = carddef2.fields[1].store_display_value(
|
||||
carddata2.data, carddef2.fields[1].id
|
||||
)
|
||||
assert carddata2.data['2_display'] == 'card1 None'
|
||||
carddata2.just_created()
|
||||
carddata2.store()
|
||||
|
||||
pub.cleanup()
|
||||
carddef = carddef.get(carddef.id)
|
||||
carddata1 = carddef.data_class().get(carddata1.id)
|
||||
carddata1.data['2'] = str(carddata2.id)
|
||||
carddata1.data['2_display'] = carddef.fields[1].store_display_value(carddata1.data, carddef.fields[1].id)
|
||||
carddata1.store()
|
||||
|
||||
# check it will have stopped once getting back to carddata2
|
||||
carddata2.refresh_from_storage()
|
||||
fpeters
commented
Mais il faut éviter que la cascade culbute sans fin. Mais il faut éviter que la cascade culbute sans fin.
|
||||
assert carddata2.data['2_display'] == 'card1 card2 card1 None'
|
||||
|
||||
|
||||
def test_card_update_related_deleted(pub):
|
||||
BlockDef.wipe()
|
||||
CardDef.wipe()
|
||||
FormDef.wipe()
|
||||
|
||||
carddef = CardDef()
|
||||
carddef.name = 'foo'
|
||||
carddef.fields = [
|
||||
StringField(id='1', label='Test', varname='foo'),
|
||||
]
|
||||
carddef.digest_templates = {'default': 'card-{{ form_var_foo }}'}
|
||||
carddef.store()
|
||||
carddef.data_class().wipe()
|
||||
|
||||
carddata1 = carddef.data_class()()
|
||||
carddata1.data = {'1': 'card1'}
|
||||
carddata1.just_created()
|
||||
carddata1.store()
|
||||
|
||||
formdef = FormDef()
|
||||
formdef.name = 'foo'
|
||||
formdef.fields = [
|
||||
ItemField(id='1', label='Test', data_source={'type': 'carddef:foo'}),
|
||||
]
|
||||
formdef.store()
|
||||
|
||||
formdata = formdef.data_class()()
|
||||
formdata.data = {'1': '1'}
|
||||
formdata.data['1_display'] = formdef.fields[0].store_display_value(formdata.data, formdef.fields[0].id)
|
||||
assert formdata.data['1_display'] == 'card-card1'
|
||||
formdata.just_created()
|
||||
formdata.store()
|
||||
formdef.remove_self()
|
||||
|
||||
pub.cleanup()
|
||||
carddef = carddef.get(carddef.id)
|
||||
carddata1 = carddef.data_class().get(carddata1.id)
|
||||
carddata1.data = {'1': 'card1-change1'}
|
||||
carddata1.store() # do not crash looking for related formdef that has been deleted
|
||||
|
||||
# check the job doesn't fail if the carddef or carddata have been removed
|
||||
job = UpdateRelationsAfterJob(carddata=carddata1)
|
||||
carddata1.remove_self()
|
||||
job.execute()
|
||||
|
||||
carddef.remove_self()
|
||||
job.execute()
|
||||
|
|
100
wcs/carddata.py
|
@ -14,12 +14,13 @@
|
|||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
from quixote import get_publisher, get_request, get_session
|
||||
from quixote import get_publisher, get_request, get_response, get_session
|
||||
|
||||
from wcs.formdata import FormData
|
||||
|
||||
from .qommon import _
|
||||
from .sql_criterias import Equal
|
||||
from .qommon.afterjobs import AfterJob
|
||||
from .sql_criterias import Equal, Null, Or, get_field_id
|
||||
|
||||
|
||||
class CardData(FormData):
|
||||
|
@ -133,3 +134,98 @@ class CardData(FormData):
|
|||
}
|
||||
token = get_session().create_token('card-file-by-token', context)
|
||||
return '/api/card-file-by-token/%s' % token.id
|
||||
|
||||
def update_related(self):
|
||||
if self.formdef.reverse_relations:
|
||||
job = UpdateRelationsAfterJob(carddata=self)
|
||||
if get_response():
|
||||
job.store()
|
||||
get_response().add_after_job(job)
|
||||
fpeters marked this conversation as resolved
Outdated
lguerin
commented
un print qui traine un print qui traine
|
||||
else:
|
||||
job.execute()
|
||||
self._has_changed_digest = False
|
||||
|
||||
|
||||
class UpdateRelationsAfterJob(AfterJob):
|
||||
label = _('Updating relations')
|
||||
|
||||
def __init__(self, carddata):
|
||||
super().__init__(carddef_id=carddata.formdef.id, carddata_id=carddata.id)
|
||||
|
||||
def execute(self):
|
||||
from .carddef import CardDef
|
||||
from .formdef import FormDef
|
||||
|
||||
if getattr(get_publisher(), '_update_related_seen', None) is None:
|
||||
get_publisher()._update_related_seen = set()
|
||||
|
||||
# keep track of objects that have been updated, to avoid cycles
|
||||
update_related_seen = get_publisher()._update_related_seen
|
||||
|
||||
try:
|
||||
carddef = CardDef.get(self.kwargs['carddef_id'])
|
||||
carddata = carddef.data_class().get(self.kwargs['carddata_id'])
|
||||
lguerin
commented
et si le job est exécuté alors que la fiche en question a été supprimée ? et si le job est exécuté alors que la fiche en question a été supprimée ?
fpeters
commented
Ça serait vraiment pas de chance, mais en effet, j'ai géré la suppression de carddata ou carddef dans ce commit supplémentaire : Ça serait vraiment pas de chance, mais en effet, j'ai géré la suppression de carddata ou carddef dans ce commit supplémentaire : https://git.entrouvert.org/entrouvert/wcs/commit/aaedccb39f471556466d4747c6075c05b84c4402 (il bouge un peu le dernier test, qui contenait un deuxième modèle de fiche pour rien).
|
||||
except KeyError:
|
||||
# card got removed (probably the afterjob met some unexpected delay), ignore.
|
||||
return
|
||||
|
||||
klass = {'carddef': CardDef, 'formdef': FormDef}
|
||||
|
||||
# check all known reverse relations
|
||||
for obj_ref in {x['obj'] for x in carddef.reverse_relations}:
|
||||
obj_type, obj_slug = obj_ref.split(':')
|
||||
obj_class = klass.get(obj_type)
|
||||
try:
|
||||
objdef = obj_class.get_by_slug(obj_slug)
|
||||
except KeyError:
|
||||
continue
|
||||
criterias = []
|
||||
fields = []
|
||||
|
||||
# get fields referencing the card model (only item and items fields, as string
|
||||
# field with data source is just for completion, and computed field with data
|
||||
# source, do not store a display value.
|
||||
for field in objdef.iter_fields(include_block_fields=True):
|
||||
if field.key not in ('item', 'items'):
|
||||
continue
|
||||
data_source = getattr(field, 'data_source', None)
|
||||
if not data_source:
|
||||
continue
|
||||
data_source_type = data_source.get('type')
|
||||
if (
|
||||
not data_source_type.startswith('carddef:')
|
||||
or data_source_type.split(':')[1] != carddef.slug
|
||||
):
|
||||
continue
|
||||
fields.append(field)
|
||||
criterias.append(Equal(get_field_id(field), carddata.identifier, field=field))
|
||||
if not criterias:
|
||||
continue
|
||||
|
||||
def update_data(field, data):
|
||||
display_value = data.get(f'{field.id}_display')
|
||||
field.set_value(data, data.get(field.id))
|
||||
return bool(data.get(f'{field.id}_display') != display_value)
|
||||
|
||||
# look for all formdata, including drafts, excluding anonymised
|
||||
select_criterias = [Null('anonymised'), Or(criterias)]
|
||||
for objdata in objdef.data_class().select_iterator(clause=select_criterias, itersize=200):
|
||||
objdata_seen_key = f'{objdata.formdef.xml_root_node}:{objdata.formdef.slug}:{objdata.id}'
|
||||
if objdata_seen_key in update_related_seen:
|
||||
# do not allow updates to cycle back
|
||||
continue
|
||||
objdata_changed = False
|
||||
for field in fields:
|
||||
if getattr(field, 'block_field', None):
|
||||
blockdata_changed = False
|
||||
for block_row_data in objdata.data[field.block_field.id]['data']:
|
||||
blockdata_changed |= update_data(field, block_row_data)
|
||||
if blockdata_changed:
|
||||
# if block data changed, maybe block digest changed too
|
||||
update_data(field.block_field, objdata.data)
|
||||
objdata_changed |= blockdata_changed
|
||||
else:
|
||||
objdata_changed |= update_data(field, objdata.data)
|
||||
if objdata_changed:
|
||||
update_related_seen.add(objdata_seen_key)
|
||||
objdata.store()
|
||||
|
|
|
@ -592,6 +592,7 @@ class WcsPublisher(QommonPublisher):
|
|||
|
||||
def cleanup(self):
|
||||
self._cached_user_fields_formdef = None
|
||||
self._update_related_seen = None
|
||||
from . import sql
|
||||
|
||||
sql.cleanup_connection()
|
||||
|
|
|
@ -2267,6 +2267,7 @@ class SqlDataMixin(SqlMixin):
|
|||
def __init__(self, id=None):
|
||||
self.id = id
|
||||
self.data = {}
|
||||
self._has_changed_digest = False
|
||||
|
||||
_evolution = None
|
||||
|
||||
|
@ -2403,6 +2404,7 @@ class SqlDataMixin(SqlMixin):
|
|||
|
||||
def _set_auto_fields(self, cur):
|
||||
if self.set_auto_fields():
|
||||
self._has_changed_digest = True
|
||||
sql_statement = (
|
||||
'''UPDATE %s
|
||||
SET id_display = %%(id_display)s,
|
||||
|
@ -2848,7 +2850,9 @@ class SqlCardData(SqlDataMixin, wcs.carddata.CardData):
|
|||
def store(self, *args, **kwargs):
|
||||
if self.uuid is None:
|
||||
self.uuid = str(uuid.uuid4())
|
||||
return super().store(*args, **kwargs)
|
||||
super().store(*args, **kwargs)
|
||||
if self._has_changed_digest:
|
||||
self.update_related()
|
||||
|
||||
|
||||
class SqlUser(SqlMixin, wcs.users.User):
|
||||
|
|
Dans ce test on vérifiait le fallback sur la valeur stockée en _display en cas de suppression de la fiche; avec cette PR qui met à jour la valeur en _display ça ne marche plus pareil, on peut juste être content que la valeur s'affiche sans planter, ce qui était l'intention initiale de toute façon.