lino 25.5.1__py3-none-any.whl → 25.5.3__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- lino/__init__.py +1 -1
- lino/api/dd.py +5 -3
- lino/api/doctest.py +2 -2
- lino/core/__init__.py +3 -3
- lino/core/actions.py +60 -582
- lino/core/actors.py +66 -32
- lino/core/atomizer.py +355 -0
- lino/core/boundaction.py +8 -4
- lino/core/constants.py +3 -1
- lino/core/dbtables.py +4 -3
- lino/core/elems.py +33 -21
- lino/core/fields.py +40 -210
- lino/core/kernel.py +18 -13
- lino/core/layouts.py +30 -57
- lino/core/model.py +6 -4
- lino/core/permissions.py +18 -0
- lino/core/renderer.py +5 -1
- lino/core/requests.py +13 -7
- lino/core/signals.py +1 -1
- lino/core/site.py +7 -8
- lino/core/store.py +13 -156
- lino/core/tables.py +10 -1
- lino/core/utils.py +124 -1
- lino/locale/bn/LC_MESSAGES/django.po +1034 -868
- lino/locale/de/LC_MESSAGES/django.mo +0 -0
- lino/locale/de/LC_MESSAGES/django.po +996 -892
- lino/locale/django.pot +968 -869
- lino/locale/es/LC_MESSAGES/django.po +1032 -869
- lino/locale/et/LC_MESSAGES/django.po +1032 -866
- lino/locale/fr/LC_MESSAGES/django.po +1034 -866
- lino/locale/nl/LC_MESSAGES/django.po +1040 -868
- lino/locale/pt_BR/LC_MESSAGES/django.po +1029 -868
- lino/locale/zh_Hant/LC_MESSAGES/django.po +1029 -868
- lino/mixins/duplicable.py +8 -2
- lino/mixins/registrable.py +1 -1
- lino/modlib/changes/utils.py +4 -3
- lino/modlib/export_excel/models.py +7 -3
- lino/modlib/extjs/ext_renderer.py +1 -1
- lino/modlib/extjs/views.py +5 -0
- lino/modlib/linod/mixins.py +10 -11
- lino/modlib/memo/mixins.py +1 -3
- lino/modlib/summaries/__init__.py +2 -2
- lino/modlib/uploads/ui.py +6 -8
- lino/modlib/users/fixtures/demo_users.py +16 -13
- lino/utils/choosers.py +11 -1
- lino/utils/diag.py +6 -4
- lino/utils/fieldutils.py +14 -11
- lino/utils/instantiator.py +4 -2
- lino/utils/report.py +5 -3
- {lino-25.5.1.dist-info → lino-25.5.3.dist-info}/METADATA +1 -1
- {lino-25.5.1.dist-info → lino-25.5.3.dist-info}/RECORD +54 -53
- {lino-25.5.1.dist-info → lino-25.5.3.dist-info}/WHEEL +0 -0
- {lino-25.5.1.dist-info → lino-25.5.3.dist-info}/licenses/AUTHORS.rst +0 -0
- {lino-25.5.1.dist-info → lino-25.5.3.dist-info}/licenses/COPYING +0 -0
lino/core/elems.py
CHANGED
@@ -32,10 +32,11 @@ from lino import logger
|
|
32
32
|
|
33
33
|
from lino.core import layouts
|
34
34
|
from lino.core import fields
|
35
|
-
from lino.core.actions import Action, Permittable
|
36
35
|
from lino.core import constants
|
37
|
-
from lino.core.gfks import GenericRelation, GenericRel
|
38
36
|
from lino.core import choicelists
|
37
|
+
from lino.core import actions
|
38
|
+
from lino.core.gfks import GenericRelation, GenericRel
|
39
|
+
from lino.core.permissions import Permittable
|
39
40
|
from lino.modlib.bootstrap3.views import table2html
|
40
41
|
|
41
42
|
from lino.utils.jsgen import VisibleComponent
|
@@ -50,12 +51,10 @@ from lino.core.actors import qs2summary
|
|
50
51
|
|
51
52
|
from lino.core.layouts import (
|
52
53
|
FormLayout,
|
53
|
-
ParamsLayout,
|
54
54
|
ColumnsLayout,
|
55
|
-
ActionParamsLayout,
|
56
55
|
DummyPanel,
|
57
56
|
)
|
58
|
-
|
57
|
+
from lino.core.layouts import ParamsLayout, ActionParamsLayout
|
59
58
|
from lino.utils.mldbc.fields import BabelCharField, BabelTextField
|
60
59
|
from lino.core import tables
|
61
60
|
from lino.core.gfks import GenericForeignKey
|
@@ -1801,13 +1800,12 @@ class LightWeightContainer(HtmlBoxElement):
|
|
1801
1800
|
|
1802
1801
|
"""
|
1803
1802
|
|
1804
|
-
def __init__(self, lh, slave, name,
|
1803
|
+
def __init__(self, lh, slave, name, meth, **kwargs):
|
1805
1804
|
box = fields.HtmlBox(
|
1806
|
-
slave.
|
1805
|
+
slave.get_label(), name=name, help_text=slave.help_text, delayed_value=True
|
1807
1806
|
)
|
1808
|
-
|
1809
|
-
box
|
1810
|
-
fld = fields.VirtualField(box, return_type)
|
1807
|
+
box._return_type_for_method = meth
|
1808
|
+
fld = fields.VirtualField(box, meth, verbose_name=slave.get_label())
|
1811
1809
|
# self.value = dict(value=dict(data="")) # compare react.views.DelayedValue
|
1812
1810
|
# self.value = dict(data="") # compare react.views.DelayedValue
|
1813
1811
|
# assert box.delayed_value == True
|
@@ -1844,7 +1842,6 @@ class SlaveSummaryPanel(LightWeightContainer):
|
|
1844
1842
|
|
1845
1843
|
class StoryElement(LightWeightContainer):
|
1846
1844
|
"""
|
1847
|
-
|
1848
1845
|
The panel used to display objects as plain html generated by
|
1849
1846
|
:meth:`as_summary_row <lino.core.fields.TableRow.as_summary_row>` when
|
1850
1847
|
`display_mode` is `DISPLAY_MODE_STORY`.
|
@@ -1860,6 +1857,11 @@ class ListElement(LightWeightContainer):
|
|
1860
1857
|
super().__init__(lh, slave, name, slave.get_table_as_list, **kw)
|
1861
1858
|
|
1862
1859
|
|
1860
|
+
class TilesElement(LightWeightContainer):
|
1861
|
+
def __init__(self, lh, slave, name, **kw):
|
1862
|
+
super().__init__(lh, slave, name, slave.get_table_as_tiles, **kw)
|
1863
|
+
|
1864
|
+
|
1863
1865
|
class ManyRelatedObjectElement(HtmlBoxElement):
|
1864
1866
|
def __init__(self, lh, relobj, **kw):
|
1865
1867
|
name = relobj.field.remote_field.related_name
|
@@ -2448,6 +2450,8 @@ class SlaveContainer(GridElement):
|
|
2448
2450
|
slaves = dict()
|
2449
2451
|
if constants.DISPLAY_MODE_STORY in rpt.extra_display_modes:
|
2450
2452
|
slaves["story"] = get_story_element(layout_handle, rpt, name, **kw)
|
2453
|
+
if constants.DISPLAY_MODE_TILES in rpt.extra_display_modes:
|
2454
|
+
slaves["tiles"] = get_tiles_element(layout_handle, rpt, name, **kw)
|
2451
2455
|
if constants.DISPLAY_MODE_LIST in rpt.extra_display_modes:
|
2452
2456
|
slaves["list"] = get_list_element(layout_handle, rpt, name, **kw)
|
2453
2457
|
if constants.DISPLAY_MODE_SUMMARY in rpt.extra_display_modes:
|
@@ -2721,18 +2725,23 @@ def create_layout_panel(lh, name, vertical, elems, **kwargs):
|
|
2721
2725
|
return Panel(lh, name, vertical, *elems, **pkw)
|
2722
2726
|
|
2723
2727
|
|
2724
|
-
def
|
2725
|
-
e =
|
2728
|
+
def get_display_element(lh, de, name, cls, **kwargs):
|
2729
|
+
e = cls(lh, de, name, **kwargs)
|
2726
2730
|
e.add_requirements(*de.required_roles)
|
2727
2731
|
lh.add_data_elem(e.field)
|
2728
2732
|
return e
|
2729
2733
|
|
2730
2734
|
|
2735
|
+
def get_story_element(lh, de, name, **kw):
|
2736
|
+
return get_display_element(lh, de, name, StoryElement, **kw)
|
2737
|
+
|
2738
|
+
|
2739
|
+
def get_tiles_element(lh, de, name, **kw):
|
2740
|
+
return get_display_element(lh, de, name, TilesElement, **kw)
|
2741
|
+
|
2742
|
+
|
2731
2743
|
def get_list_element(lh, de, name, **kw):
|
2732
|
-
|
2733
|
-
e.add_requirements(*de.required_roles)
|
2734
|
-
lh.add_data_elem(e.field)
|
2735
|
-
return e
|
2744
|
+
return get_display_element(lh, de, name, ListElement, **kw)
|
2736
2745
|
|
2737
2746
|
|
2738
2747
|
def get_htmlbox_element(lh, de, name, **kw):
|
@@ -2908,15 +2917,18 @@ def create_layout_element(lh, name, **kw):
|
|
2908
2917
|
elif dm == constants.DISPLAY_MODE_HTML:
|
2909
2918
|
return get_htmlbox_element(lh, de, name, **kw)
|
2910
2919
|
|
2911
|
-
elif dm == constants.DISPLAY_MODE_STORY:
|
2912
|
-
return get_story_element(lh, de, name, **kw)
|
2913
|
-
|
2914
2920
|
elif dm == constants.DISPLAY_MODE_SUMMARY:
|
2915
2921
|
return get_summary_element(lh, de, name, **kw)
|
2916
2922
|
|
2917
2923
|
elif dm == constants.DISPLAY_MODE_LIST:
|
2918
2924
|
return get_list_element(lh, de, name, **kw)
|
2919
2925
|
|
2926
|
+
elif dm == constants.DISPLAY_MODE_STORY:
|
2927
|
+
return get_story_element(lh, de, name, **kw)
|
2928
|
+
|
2929
|
+
elif dm == constants.DISPLAY_MODE_TILES:
|
2930
|
+
return get_tiles_element(lh, de, name, **kw)
|
2931
|
+
|
2920
2932
|
# elif dm == 'reactive': # TODO: is this still being used?
|
2921
2933
|
# e = ReactiveElement(lh, de, **kw)
|
2922
2934
|
# e.add_requirements(*de.required_roles)
|
@@ -2932,7 +2944,7 @@ def create_layout_element(lh, name, **kw):
|
|
2932
2944
|
# lh.add_data_elem(e.field)
|
2933
2945
|
# return e
|
2934
2946
|
|
2935
|
-
if isinstance(de, Action):
|
2947
|
+
if isinstance(de, actions.Action):
|
2936
2948
|
return ButtonElement(lh, name, de)
|
2937
2949
|
|
2938
2950
|
if isinstance(de, fields.VirtualField):
|
lino/core/fields.py
CHANGED
@@ -33,13 +33,15 @@ from lino.core.utils import (
|
|
33
33
|
from lino.core.exceptions import ChangedAPI
|
34
34
|
from lino.core.diff import ChangeWatcher
|
35
35
|
from lino.core import constants
|
36
|
+
from lino.core import atomizer
|
36
37
|
|
37
38
|
from lino.utils import isiterable
|
38
|
-
from lino.utils import
|
39
|
+
from lino.utils import choosers
|
40
|
+
# from lino.utils import get_class_attr
|
39
41
|
from lino.utils import IncompleteDate
|
40
42
|
from lino.utils import quantities
|
41
43
|
from lino.utils.quantities import Duration
|
42
|
-
from lino.modlib.gfks.fields import GenericForeignKeyIdField
|
44
|
+
# from lino.modlib.gfks.fields import GenericForeignKeyIdField
|
43
45
|
|
44
46
|
from .signals import pre_ui_save
|
45
47
|
|
@@ -369,8 +371,9 @@ class RemoteField(FakeField):
|
|
369
371
|
"""
|
370
372
|
A field on a related object.
|
371
373
|
|
372
|
-
Remote fields are created by
|
373
|
-
:meth:`lino.core.model.Model.get_data_elem` when
|
374
|
+
Remote fields are created by :func:`lino.core.atomizer.create_atomizer`
|
375
|
+
(which itself is called by :meth:`lino.core.model.Model.get_data_elem`) when
|
376
|
+
needed.
|
374
377
|
|
375
378
|
.. attribute:: field
|
376
379
|
|
@@ -382,6 +385,7 @@ class RemoteField(FakeField):
|
|
382
385
|
# ~ editable = False
|
383
386
|
|
384
387
|
def __init__(self, getter, name, fld, setter=None, **kwargs):
|
388
|
+
# from lino.core import choicelists
|
385
389
|
self.func = getter
|
386
390
|
self.name = name
|
387
391
|
self.attname = name
|
@@ -405,7 +409,7 @@ class RemoteField(FakeField):
|
|
405
409
|
if setter is not None:
|
406
410
|
self.editable = True
|
407
411
|
self.choices = getattr(fld, "choices", None)
|
408
|
-
super(
|
412
|
+
super().__init__(**kwargs)
|
409
413
|
# ~ print 20120424, self.name
|
410
414
|
# ~ settings.SITE.register_virtual_field(self)
|
411
415
|
|
@@ -417,6 +421,9 @@ class RemoteField(FakeField):
|
|
417
421
|
):
|
418
422
|
fld.lino_resolve_type() # 20200425
|
419
423
|
fk = fld.return_type
|
424
|
+
# elif isinstance(fld, choicelists.ChoiceListField):
|
425
|
+
# self.choicelist = fld.choicelist
|
426
|
+
# fk = None
|
420
427
|
elif isinstance(fld, models.ForeignKey):
|
421
428
|
fk = fld
|
422
429
|
else:
|
@@ -425,9 +432,7 @@ class RemoteField(FakeField):
|
|
425
432
|
# if not fk.remote_field:
|
426
433
|
# raise Exception("20200425 {} has no remote_field".format(fk))
|
427
434
|
self.remote_field = fk.remote_field
|
428
|
-
|
429
|
-
|
430
|
-
store.get_atomizer(self.remote_field, self, name)
|
435
|
+
atomizer.get_atomizer(self.remote_field, self, name)
|
431
436
|
|
432
437
|
def __str__(self):
|
433
438
|
# return "<RemoteField({})>".format(self.name)
|
@@ -539,12 +544,12 @@ class VirtualModel:
|
|
539
544
|
self._meta = model._meta
|
540
545
|
|
541
546
|
|
542
|
-
VFIELD_ATTRIBS = frozenset(
|
543
|
-
"""
|
544
|
-
|
545
|
-
|
546
|
-
|
547
|
-
)
|
547
|
+
VFIELD_ATTRIBS = frozenset([
|
548
|
+
"to_python", "choices", "save_form_data",
|
549
|
+
"value_to_string", "max_length", "remote_field",
|
550
|
+
"max_digits", "verbose_name", "decimal_places",
|
551
|
+
"wildcard_data_elem", "blank"
|
552
|
+
])
|
548
553
|
|
549
554
|
|
550
555
|
def return_none(obj, ar):
|
@@ -657,9 +662,10 @@ class VirtualField(FakeField):
|
|
657
662
|
# logger.info('20170905 resolve_type done %s %s',
|
658
663
|
# self.name, self.verbose_name)
|
659
664
|
|
660
|
-
|
665
|
+
# if self.name is None or self.model is None:
|
666
|
+
# return
|
661
667
|
|
662
|
-
|
668
|
+
atomizer.get_atomizer(self.model, self, self.name)
|
663
669
|
|
664
670
|
# print("20181023 Done: lino_resolve_type() for {}".format(self))
|
665
671
|
|
@@ -1247,7 +1253,7 @@ class ImportedFields(object):
|
|
1247
1253
|
@classmethod
|
1248
1254
|
def declare_imported_fields(cls, names):
|
1249
1255
|
cls._imported_fields = cls._imported_fields | set(
|
1250
|
-
fields_list(cls, names))
|
1256
|
+
atomizer.fields_list(cls, names))
|
1251
1257
|
# ~ logger.info('20120801 %s.declare_imported_fields() --> %s' % (
|
1252
1258
|
# ~ cls,cls._imported_fields))
|
1253
1259
|
|
@@ -1277,7 +1283,7 @@ class TableRow(object):
|
|
1277
1283
|
def get_chooser_for_field(cls, fieldname):
|
1278
1284
|
d = getattr(cls, "_choosers_dict", {})
|
1279
1285
|
# if fieldname.endswith("__municipality"):
|
1280
|
-
#
|
1286
|
+
# print("20200425 Model.get_chooser_for_field", cls, fieldname, d)
|
1281
1287
|
return d.get(fieldname, None)
|
1282
1288
|
|
1283
1289
|
@classmethod
|
@@ -1457,6 +1463,9 @@ class TableRow(object):
|
|
1457
1463
|
return escape(str(self))
|
1458
1464
|
return tostring(self.as_summary_item(ar, **kwargs))
|
1459
1465
|
|
1466
|
+
def as_tile(self, ar, **kwargs):
|
1467
|
+
return self.as_paragraph(ar, **kwargs)
|
1468
|
+
|
1460
1469
|
def as_story_item(self, ar, **kwargs):
|
1461
1470
|
kwargs.update(display_mode=constants.DISPLAY_MODE_STORY)
|
1462
1471
|
return mark_safe("".join(self.as_page(ar, **kwargs)))
|
@@ -1533,57 +1542,6 @@ def use_as_wildcard(de):
|
|
1533
1542
|
return True
|
1534
1543
|
|
1535
1544
|
|
1536
|
-
def fields_list(model, field_names):
|
1537
|
-
"""
|
1538
|
-
Return a set with the names of the specified fields, checking
|
1539
|
-
whether each of them exists.
|
1540
|
-
|
1541
|
-
Arguments: `model` is any subclass of `django.db.models.Model`. It
|
1542
|
-
may be a string with the full name of a model
|
1543
|
-
(e.g. ``"myapp.MyModel"``). `field_names` is a single string with
|
1544
|
-
a space-separated list of field names.
|
1545
|
-
|
1546
|
-
If one of the names refers to a dummy field, this name will be ignored
|
1547
|
-
silently.
|
1548
|
-
|
1549
|
-
For example if you have a model `MyModel` with two fields `foo` and
|
1550
|
-
`bar`, then ``dd.fields_list(MyModel,"foo bar")`` will return
|
1551
|
-
``['foo','bar']`` and ``dd.fields_list(MyModel,"foo baz")`` will raise
|
1552
|
-
an exception.
|
1553
|
-
|
1554
|
-
TODO: either rename this to `fields_set` or change it to return an
|
1555
|
-
iterable on the fields.
|
1556
|
-
"""
|
1557
|
-
lst = set()
|
1558
|
-
names_list = field_names.split()
|
1559
|
-
|
1560
|
-
for name in names_list:
|
1561
|
-
if name == "*":
|
1562
|
-
explicit_names = set()
|
1563
|
-
for name in names_list:
|
1564
|
-
if name != "*":
|
1565
|
-
explicit_names.add(name)
|
1566
|
-
for de in wildcard_data_elems(model):
|
1567
|
-
if not isinstance(de, DummyField):
|
1568
|
-
if de.name not in explicit_names:
|
1569
|
-
if use_as_wildcard(de):
|
1570
|
-
lst.add(de.name)
|
1571
|
-
else:
|
1572
|
-
e = model.get_data_elem(name)
|
1573
|
-
if e is None:
|
1574
|
-
raise FieldDoesNotExist(
|
1575
|
-
"No data element %r in %s" % (name, model))
|
1576
|
-
if not hasattr(e, "name"):
|
1577
|
-
raise FieldDoesNotExist(
|
1578
|
-
"%s %r in %s has no name" % (e.__class__, name, model)
|
1579
|
-
)
|
1580
|
-
if isinstance(e, DummyField):
|
1581
|
-
pass
|
1582
|
-
else:
|
1583
|
-
lst.add(e.name)
|
1584
|
-
return lst
|
1585
|
-
|
1586
|
-
|
1587
1545
|
def pointer_factory(cls, othermodel, *args, **kw):
|
1588
1546
|
"""
|
1589
1547
|
Instantiate a `ForeignKey` or `OneToOneField` with some subtle
|
@@ -1610,147 +1568,6 @@ def pointer_factory(cls, othermodel, *args, **kw):
|
|
1610
1568
|
return cls(othermodel, *args, **kw)
|
1611
1569
|
|
1612
1570
|
|
1613
|
-
def make_remote_field(model, name):
|
1614
|
-
from lino.utils import choosers
|
1615
|
-
parts = name.split("__")
|
1616
|
-
if len(parts) == 1:
|
1617
|
-
return
|
1618
|
-
# It's going to be a RemoteField
|
1619
|
-
# logger.warning("20151203 RemoteField %s in %s", name, cls)
|
1620
|
-
|
1621
|
-
from lino.core import store
|
1622
|
-
|
1623
|
-
cls = model
|
1624
|
-
field_chain = []
|
1625
|
-
editable = False
|
1626
|
-
gettable = True
|
1627
|
-
leaf_chooser = None
|
1628
|
-
for n in parts:
|
1629
|
-
if model is None:
|
1630
|
-
return
|
1631
|
-
# raise Exception(
|
1632
|
-
# "Invalid remote field {0} for {1}".format(name, cls))
|
1633
|
-
|
1634
|
-
if isinstance(model, str):
|
1635
|
-
# Django 1.9 no longer resolves the
|
1636
|
-
# rel.model of ForeignKeys on abstract
|
1637
|
-
# models, so we do it here.
|
1638
|
-
model = resolve_model(model)
|
1639
|
-
# logger.warning("20151203 %s", model)
|
1640
|
-
|
1641
|
-
fld = model.get_data_elem(n)
|
1642
|
-
if fld is None:
|
1643
|
-
return
|
1644
|
-
# raise Exception(
|
1645
|
-
# "Invalid RemoteField %s.%s (no field %s in %s)" %
|
1646
|
-
# (full_model_name(model), name, n, full_model_name(model)))
|
1647
|
-
|
1648
|
-
if isinstance(fld, DummyField):
|
1649
|
-
# a remote field containing at least one dummy field is itself a
|
1650
|
-
# dummy field
|
1651
|
-
return fld
|
1652
|
-
|
1653
|
-
# Why was this? it caused docs/specs/avanti/courses.rst to fail
|
1654
|
-
# if isinstance(fld, models.ManyToOneRel):
|
1655
|
-
# gettable = False
|
1656
|
-
|
1657
|
-
# make sure that the atomizer gets created.
|
1658
|
-
store.get_atomizer(model, fld, fld.name)
|
1659
|
-
|
1660
|
-
if isinstance(fld, VirtualField):
|
1661
|
-
fld.lino_resolve_type()
|
1662
|
-
leaf_chooser = choosers.check_for_chooser(model, fld)
|
1663
|
-
|
1664
|
-
field_chain.append(fld)
|
1665
|
-
if isinstance(
|
1666
|
-
fld, (models.OneToOneRel, models.OneToOneField, models.ForeignKey)
|
1667
|
-
):
|
1668
|
-
editable = True
|
1669
|
-
if getattr(fld, "remote_field", None):
|
1670
|
-
model = fld.remote_field.model
|
1671
|
-
else:
|
1672
|
-
model = None
|
1673
|
-
|
1674
|
-
# if not gettable:
|
1675
|
-
# # raise Exception("20231112")
|
1676
|
-
# return RemoteField(none_getter, name, fld)
|
1677
|
-
|
1678
|
-
if leaf_chooser is not None:
|
1679
|
-
d = choosers.get_choosers_dict(cls)
|
1680
|
-
d[name] = leaf_chooser
|
1681
|
-
|
1682
|
-
def getter(obj, ar=None):
|
1683
|
-
try:
|
1684
|
-
for fld in field_chain:
|
1685
|
-
if obj is None:
|
1686
|
-
return None
|
1687
|
-
obj = fld._lino_atomizer.full_value_from_object(obj, ar)
|
1688
|
-
return obj
|
1689
|
-
except Exception as e:
|
1690
|
-
# raise
|
1691
|
-
msg = "Error while computing {}: {} ({} in {})"
|
1692
|
-
raise Exception(msg.format(name, e, fld, field_chain))
|
1693
|
-
# ~ if False: # only for debugging
|
1694
|
-
if True: # see 20130802
|
1695
|
-
logger.exception(e)
|
1696
|
-
return str(e)
|
1697
|
-
return None
|
1698
|
-
|
1699
|
-
if not editable:
|
1700
|
-
rf = RemoteField(getter, name, fld)
|
1701
|
-
# choosers.check_for_chooser(model, rf)
|
1702
|
-
return rf
|
1703
|
-
|
1704
|
-
def setter(obj, value):
|
1705
|
-
# logger.info("20180712 %s setter() %s", name, value)
|
1706
|
-
# all intermediate fields are OneToOneRel
|
1707
|
-
target = obj
|
1708
|
-
try:
|
1709
|
-
for i, fld in enumerate(field_chain):
|
1710
|
-
# print("20180712a %s" % fld)
|
1711
|
-
if isinstance(fld, (models.OneToOneRel, models.ForeignKey)):
|
1712
|
-
reltarget = getattr(target, fld.name, None)
|
1713
|
-
if reltarget is None:
|
1714
|
-
rkw = {fld.field.name: target}
|
1715
|
-
# print(
|
1716
|
-
# "20180712 create {}({})".format(
|
1717
|
-
# fld.related_model, rkw))
|
1718
|
-
reltarget = fld.related_model(**rkw)
|
1719
|
-
reltarget.save_new_instance(
|
1720
|
-
fld.related_model.get_default_table().create_request()
|
1721
|
-
)
|
1722
|
-
|
1723
|
-
setattr(target, fld.name, reltarget)
|
1724
|
-
|
1725
|
-
if target == obj and target.id is None:
|
1726
|
-
# Model.save_new_instance will be called do not insert this record.
|
1727
|
-
target = reltarget
|
1728
|
-
continue
|
1729
|
-
target.full_clean()
|
1730
|
-
target.save()
|
1731
|
-
# print("20180712b {}.{} = {}".format(
|
1732
|
-
# target, fld.name, reltarget))
|
1733
|
-
target = reltarget
|
1734
|
-
else:
|
1735
|
-
setattr(target, fld.name, value)
|
1736
|
-
target.full_clean()
|
1737
|
-
target.save()
|
1738
|
-
# print(
|
1739
|
-
# "20180712c setattr({},{},{}".format(
|
1740
|
-
# target, fld.name, value))
|
1741
|
-
return True
|
1742
|
-
except Exception as e:
|
1743
|
-
if False: # only for debugging
|
1744
|
-
logger.exception(e)
|
1745
|
-
return str(e)
|
1746
|
-
raise e.__class__("Error while setting %s: %s" % (name, e))
|
1747
|
-
return False
|
1748
|
-
|
1749
|
-
rf = RemoteField(getter, name, fld, setter)
|
1750
|
-
# choosers.check_for_chooser(model, rf)
|
1751
|
-
return rf
|
1752
|
-
|
1753
|
-
|
1754
1571
|
# # would be nice for lino_xl.lib.vat.VatItemBase.item_total
|
1755
1572
|
# class FieldAlias(VirtualField):
|
1756
1573
|
# def __init__(self, orig_name):
|
@@ -1852,3 +1669,16 @@ def choices_for_field(ar, holder, field):
|
|
1852
1669
|
else:
|
1853
1670
|
raise http.Http404("No choices for %s" % field)
|
1854
1671
|
return (qs, row2dict)
|
1672
|
+
|
1673
|
+
|
1674
|
+
def setup_params_choosers(self):
|
1675
|
+
if self.parameters:
|
1676
|
+
for k, fld in self.parameters.items():
|
1677
|
+
if isinstance(fld, models.ForeignKey):
|
1678
|
+
msg = "Invalid target %s in parameter {} of {}".format(k, self)
|
1679
|
+
fld.remote_field.model = resolve_model(
|
1680
|
+
fld.remote_field.model, strict=msg
|
1681
|
+
)
|
1682
|
+
set_default_verbose_name(fld)
|
1683
|
+
|
1684
|
+
choosers.check_for_chooser(self, fld)
|
lino/core/kernel.py
CHANGED
@@ -50,22 +50,22 @@ from lino.utils.html import E
|
|
50
50
|
# from lino.utils import isiterable
|
51
51
|
from lino.core import layouts
|
52
52
|
from lino.core import actors
|
53
|
-
from lino.core import actions
|
54
53
|
from lino.core import frames
|
55
|
-
from lino.core import fields
|
56
54
|
from lino.core import dbtables
|
55
|
+
from lino.core import atomizer
|
57
56
|
from lino.core import choicelists
|
58
57
|
from lino.core import workflows
|
59
58
|
from lino.core import tables
|
60
59
|
from lino.core import constants
|
61
60
|
from lino.core.model import Model
|
62
|
-
from lino.core.roles import UserRole
|
61
|
+
# from lino.core.roles import UserRole
|
62
|
+
from lino.utils.choosers import discover_choosers
|
63
63
|
from lino.core.store import Store
|
64
64
|
from lino.core.renderer import HtmlRenderer, TextRenderer
|
65
65
|
from lino.core.gfks import ContentType, GenericForeignKey
|
66
66
|
from lino.core.signals import (
|
67
67
|
pre_ui_build,
|
68
|
-
post_ui_build,
|
68
|
+
# post_ui_build,
|
69
69
|
pre_startup,
|
70
70
|
post_startup,
|
71
71
|
pre_analyze,
|
@@ -83,9 +83,9 @@ from .utils import get_models
|
|
83
83
|
from .utils import resolve_fields_list
|
84
84
|
|
85
85
|
# from .utils import djangoname
|
86
|
-
from .utils import class_dict_items
|
86
|
+
# from .utils import class_dict_items
|
87
87
|
|
88
|
-
from .fields import set_default_verbose_name
|
88
|
+
from lino.core.fields import set_default_verbose_name
|
89
89
|
# from lino.core.requests import ActorRequest
|
90
90
|
|
91
91
|
startup_rlock = threading.RLock() # Lock() or RLock()?
|
@@ -155,6 +155,8 @@ class Kernel(object):
|
|
155
155
|
# # self._code_mtime = codetime(settings.SETTINGS_MODULE)
|
156
156
|
# return self._code_mtime
|
157
157
|
|
158
|
+
editing_front_end = None
|
159
|
+
|
158
160
|
def kernel_startup(self, site):
|
159
161
|
"""This is a part of a Lino site startup. The Django Model
|
160
162
|
definitions are done, now Lino analyzes them and does certain
|
@@ -226,22 +228,22 @@ class Kernel(object):
|
|
226
228
|
|
227
229
|
if isinstance(model.hidden_columns, str):
|
228
230
|
model.hidden_columns = frozenset(
|
229
|
-
|
231
|
+
atomizer.fields_list(model, model.hidden_columns)
|
230
232
|
)
|
231
233
|
|
232
234
|
if isinstance(model.active_fields, str):
|
233
235
|
model.active_fields = frozenset(
|
234
|
-
|
236
|
+
atomizer.fields_list(model, model.active_fields)
|
235
237
|
)
|
236
238
|
|
237
239
|
if isinstance(model.allow_cascaded_delete, str):
|
238
240
|
model.allow_cascaded_delete = frozenset(
|
239
|
-
|
241
|
+
atomizer.fields_list(model, model.allow_cascaded_delete)
|
240
242
|
)
|
241
243
|
|
242
244
|
if isinstance(model.allow_cascaded_copy, str):
|
243
245
|
model.allow_cascaded_copy = frozenset(
|
244
|
-
|
246
|
+
atomizer.fields_list(model, model.allow_cascaded_copy)
|
245
247
|
)
|
246
248
|
|
247
249
|
# Note how to inherit this from from parent model.
|
@@ -469,7 +471,7 @@ class Kernel(object):
|
|
469
471
|
model._lino_default_table = rpt
|
470
472
|
|
471
473
|
# ~ choosers.discover()
|
472
|
-
|
474
|
+
discover_choosers()
|
473
475
|
|
474
476
|
for a in actors.actors_list:
|
475
477
|
for name, field in a.virtual_fields.items():
|
@@ -675,13 +677,16 @@ class Kernel(object):
|
|
675
677
|
# must_remove.add(r)
|
676
678
|
# site.user_roles -= must_remove
|
677
679
|
|
678
|
-
post_ui_build.send(self)
|
680
|
+
# post_ui_build.send(self)
|
679
681
|
|
680
|
-
# trigger creation of params_layout.params_store
|
682
|
+
# trigger creation of params_layout.params_store and
|
683
|
+
# virtual fields in LightWeightContainer
|
681
684
|
for res in actors.actors_list:
|
682
685
|
for ba in res.get_actions():
|
683
686
|
if ba.action.params_layout is not None:
|
684
687
|
ba.action.params_layout.get_layout_handle()
|
688
|
+
if ba.action.is_window_action():
|
689
|
+
ba.get_layout_handel()
|
685
690
|
|
686
691
|
# logger.info("20161219 kernel_startup done")
|
687
692
|
|