Welcome | Get started | Dive into Lino | Contribute | Reference
Delayed values¶
This topic guide explains what a delayed value is.
This is a tested document. The following instructions are used for initialization:
>>> from lino import startup
>>> startup('lino_book.projects.noi1r.settings')
>>> from lino.api.doctest import *
- delayed value¶
A value of a store field that is not computed immediately and for which Lino returns a
dict
object that basically just tells the client to emit another AJAX request if it wants to know that value.
Lino currently uses a delayed value when rendering the summary of a slave table of a detail page.
Delayed values are used only when the front end supports them, which it
says by setting support_async
to True. Only react has this feature
right now.
>>> settings.SITE.kernel.web_front_ends[0].support_async
True
About the name¶
A slave table can be a valid data element of a detail layout, and it is named foos.Foos (i.e. with a dot). But the corresponding store field will be named foos_Foos because we want the names of store fields to be valid Python attribute names.
>>> # ses = rt.login("robin", renderer=settings.SITE.kernel.default_renderer)
>>> t1 = tickets.Ticket.objects.get(pk=1)
>>> dv = tickets.AllTickets
>>> ar = dv.request(user=rt.login("robin").get_user())
>>> store = dv.get_handle().store
>>> pprint(store.row2dict(ar, t1))
...
{'DuplicatesByTicket': <Element div at ...>,
'assigned_to': None,
'assigned_toHidden': None,
'comment': None,
'comments.CommentsByMentioned': {'delayed_value_url': 'values/tickets/AllTickets/1/comments.CommentsByMentioned'},
'comments.CommentsByRFC': {'delayed_value_url': 'values/tickets/AllTickets/1/comments.CommentsByRFC'},
'created': datetime.datetime(..., tzinfo=datetime.timezone.utc),
'deadline': None,
'description': '',
'disable_editing': False,
'disabled_fields': {'DuplicatesByTicket': True,
'created': True,
'end_session': True,
'fixed_since': True,
'id': True,
'mark_refused': True,
'modified': True},
'duplicate_of': None,
'duplicate_ofHidden': None,
'end_user': 'Andreas Arens',
'end_userHidden': 112,
'extra_hours': None,
'fixed_since': None,
'free_hours': Duration('168:21'),
'id': 1,
'modified': datetime.datetime(..., tzinfo=datetime.timezone.utc),
'order': 'welket Rumma & Ko OÜ (SLA 1/2014)',
'orderHidden': 1,
'overview': <Element div at ...>,
'parent': None,
'parentHidden': None,
'planned_time': None,
'priority': 30,
'private': False,
'quick_assign_to': <Element p at ...>,
'ref': None,
'regular_hours': Duration('125:31'),
'site': 'pypi',
'siteHidden': 1,
'state': 'New',
'stateHidden': '10',
'summary': 'Föö fails to bar when baz',
'ticket_type': 'Bugfix',
'ticket_typeHidden': 1,
'tickets.TicketsByParent': {'delayed_value_url': 'values/tickets/AllTickets/1/tickets.TicketsByParent'},
'upgrade_notes': '',
'uploads.UploadsByController': {'delayed_value_url': 'values/tickets/AllTickets/1/uploads.UploadsByController'},
'user': 'Jean',
'userHidden': 7,
'workflow_buttons': <Element span at ...>,
'working.SessionsByTicket': {'delayed_value_url': 'values/tickets/AllTickets/1/working.SessionsByTicket'}}
When the client receives data values of type {'delayed_value_url': ... }, it will render the form with those fields empty, emit for each of them an AJAX request to the specified delayed_value_url and fill in the value as soon as it receives an answer. Here is how such an AJAX request looks like:
>>> url = "values/tickets/AllTickets/1/working.SessionsByTicket"
>>> demo_get('robin', url, None, -1)
GET /values/tickets/AllTickets/1/working.SessionsByTicket for user Robin Rood got
{'data': '<div><p>Total 293:52 hours.</p></div>'}
Don't read on¶
>>> ses = rt.login("robin")
>>> ses.show('tickets.AllTickets.detail', selected_pks=[1])
...
GeneralMoreLinksFöö fails to bar when bazSubscriptionEnd userTicket typeProjectmarc, rolfPrivatePriorityPlanned timeDeadlineRegularExtraFreeTotal 0:00 hours.[✋] [▶] ⚹ New → [☾] [☎] [☉] [⚒] [☐] [☑]My commentNoneComments of #1 (⚹ Föö fails to bar when baz)BodyCreatedAuthor
WhoWhatDone?HimBar HerFoo the BarxThemFloop the pigx...Rolf Rompenbreaking
De : lino@foo.net [mailto:foo@bar.com] Envoyé : mardi 18 octobre 2016 08:52 À : eexample@foo.com Objet : [welcht] YOU modified FOO BAR
Dear Aurélie ,
this is to notify / BAR
BAR modified
TODO: include a summary of the modifications.
Any subsequent notifications about foo/ until you view this notification in the Lino web interface. Please visit
None
and follow your welcome messages...JeanIDReferenceSummaryDescription Resolution Source document: NewStateAssigned toAuthorCreatedModifiedFixed sinceDuplicate ofParentChildren of #1 (⚹ Föö fails to bar when baz)PriorityIDSummaryAssign to302Bar is not always baz
More requests to /values/
¶
>>> test_client.force_login(rt.login('robin').user)
>>> url = "/values/tickets/AllTickets/4694/comments.CommentsByRFC"
>>> res = test_client.get(url, REMOTE_USER='robin')
Traceback (most recent call last):
...
django.core.exceptions.ObjectDoesNotExist: Invalid primary key 4694 for tickets.AllTickets
>>> url = "/values/tickets/AllTickets/112/comments.CommentsByRFC"
>>> res = test_client.get(url, REMOTE_USER='robin')
>>> print(res.status_code)
200
The response to this AJAX request is in JSON:
>>> d = json.loads(res.content.decode())
>>> print(d['data'])
<div><p>...</p></div>
>>> url = "/values/tickets/Tickets/112/working.SessionsByTicket"
>>> res = test_client.get(url, REMOTE_USER='robin')
>>> d = json.loads(res.content.decode())
>>> print(d['data'])
<div><p>...</p></div>