lino 24.11.1__py3-none-any.whl → 25.1.0__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/core/actors.py +33 -12
- lino/core/fields.py +26 -18
- lino/core/kernel.py +4 -6
- lino/core/model.py +5 -16
- lino/core/renderer.py +1 -2
- lino/core/requests.py +70 -47
- lino/core/site.py +1 -1
- lino/core/tables.py +0 -16
- lino/help_texts.py +4 -3
- lino/locale/bn/LC_MESSAGES/django.po +58 -45
- lino/locale/de/LC_MESSAGES/django.mo +0 -0
- lino/locale/de/LC_MESSAGES/django.po +79 -108
- lino/locale/django.pot +55 -44
- lino/locale/es/LC_MESSAGES/django.po +56 -44
- lino/locale/et/LC_MESSAGES/django.po +58 -45
- lino/locale/fr/LC_MESSAGES/django.mo +0 -0
- lino/locale/fr/LC_MESSAGES/django.po +60 -48
- lino/locale/nl/LC_MESSAGES/django.po +59 -45
- lino/locale/pt_BR/LC_MESSAGES/django.po +55 -44
- lino/locale/zh_Hant/LC_MESSAGES/django.po +55 -44
- lino/mixins/dupable.py +8 -7
- lino/mixins/periods.py +4 -4
- lino/modlib/checkdata/__init__.py +1 -1
- lino/modlib/comments/ui.py +7 -3
- lino/modlib/dupable/models.py +10 -14
- lino/modlib/gfks/mixins.py +8 -1
- lino/modlib/jinja/choicelists.py +3 -3
- lino/modlib/jinja/renderer.py +2 -0
- lino/modlib/languages/fixtures/all_languages.py +4 -6
- lino/modlib/memo/mixins.py +7 -7
- lino/modlib/memo/models.py +41 -12
- lino/modlib/memo/parser.py +7 -3
- lino/modlib/notify/mixins.py +8 -8
- lino/modlib/periods/choicelists.py +46 -0
- lino/modlib/periods/mixins.py +26 -0
- lino/modlib/periods/models.py +17 -45
- lino/modlib/publisher/choicelists.py +1 -4
- lino/modlib/uploads/mixins.py +37 -37
- lino/modlib/uploads/models.py +68 -18
- lino/modlib/uploads/utils.py +6 -0
- lino/modlib/users/mixins.py +9 -6
- lino/modlib/weasyprint/choicelists.py +17 -7
- lino/utils/choosers.py +21 -8
- lino/utils/instantiator.py +9 -0
- lino/utils/soup.py +5 -5
- {lino-24.11.1.dist-info → lino-25.1.0.dist-info}/METADATA +4 -2
- {lino-24.11.1.dist-info → lino-25.1.0.dist-info}/RECORD +51 -50
- {lino-24.11.1.dist-info → lino-25.1.0.dist-info}/WHEEL +1 -1
- {lino-24.11.1.dist-info → lino-25.1.0.dist-info}/licenses/AUTHORS.rst +0 -0
- {lino-24.11.1.dist-info → lino-25.1.0.dist-info}/licenses/COPYING +0 -0
lino/__init__.py
CHANGED
lino/core/actors.py
CHANGED
@@ -261,6 +261,9 @@ class Actor(actions.Parametrizable, Permittable, metaclass=ActorMetaClass):
|
|
261
261
|
|
262
262
|
_detail_action_class = actions.ShowDetail
|
263
263
|
|
264
|
+
obvious_fields = set()
|
265
|
+
"""A set of names of fields that are considered :term:`obvious field`. """
|
266
|
+
|
264
267
|
required_roles = set([SiteUser])
|
265
268
|
"""See :doc:`/dev/perms`."""
|
266
269
|
|
@@ -443,8 +446,7 @@ class Actor(actions.Parametrizable, Permittable, metaclass=ActorMetaClass):
|
|
443
446
|
|
444
447
|
detail_template = None # deprecated: use insert_layout instead
|
445
448
|
insert_template = None # deprecated: use detail_layout instead
|
446
|
-
|
447
|
-
row_template = "{row}"
|
449
|
+
row_template = None # "{row}"
|
448
450
|
|
449
451
|
help_text = None
|
450
452
|
detail_action = None
|
@@ -722,12 +724,6 @@ class Actor(actions.Parametrizable, Permittable, metaclass=ActorMetaClass):
|
|
722
724
|
def on_analyze(self, site):
|
723
725
|
pass
|
724
726
|
|
725
|
-
@classmethod
|
726
|
-
def row_as_summary(cls, ar, obj, text=None, **kwargs):
|
727
|
-
if ar is None:
|
728
|
-
return text or str(obj)
|
729
|
-
return obj.as_summary_item(ar, text, **kwargs)
|
730
|
-
|
731
727
|
@classmethod
|
732
728
|
def do_setup(self):
|
733
729
|
pass
|
@@ -1014,11 +1010,14 @@ class Actor(actions.Parametrizable, Permittable, metaclass=ActorMetaClass):
|
|
1014
1010
|
An example is described in :ref:`avanti.specs.get_request_detail_action`
|
1015
1011
|
|
1016
1012
|
"""
|
1013
|
+
if (ba := cls.detail_action) is None:
|
1014
|
+
return None
|
1015
|
+
if ar is None:
|
1016
|
+
return ba
|
1017
1017
|
ut = ar.get_user().user_type
|
1018
|
-
ba = cls.detail_action
|
1019
1018
|
if (
|
1020
|
-
ar.actor
|
1021
|
-
and ar.actor
|
1019
|
+
ar.actor is not None
|
1020
|
+
and ar.actor.detail_action is not None
|
1022
1021
|
and ba.action is ar.actor.detail_action.action
|
1023
1022
|
):
|
1024
1023
|
# 20210223 When this actor uses the same action, don't return
|
@@ -1243,7 +1242,7 @@ class Actor(actions.Parametrizable, Permittable, metaclass=ActorMetaClass):
|
|
1243
1242
|
window on a given row of this actor.
|
1244
1243
|
|
1245
1244
|
"""
|
1246
|
-
return
|
1245
|
+
return obj.as_str(ar)
|
1247
1246
|
|
1248
1247
|
@classmethod
|
1249
1248
|
def get_card_title(self, ar, obj):
|
@@ -1256,6 +1255,28 @@ class Actor(actions.Parametrizable, Permittable, metaclass=ActorMetaClass):
|
|
1256
1255
|
):
|
1257
1256
|
return None
|
1258
1257
|
|
1258
|
+
@classmethod
|
1259
|
+
def row_as_summary(cls, ar, obj, text=None, **kwargs):
|
1260
|
+
if ar is None:
|
1261
|
+
return text or str(obj)
|
1262
|
+
return obj.as_summary_item(ar, text, **kwargs)
|
1263
|
+
|
1264
|
+
@classmethod
|
1265
|
+
def row_as_paragraph(cls, ar, row):
|
1266
|
+
"""Return an HTML string that represents the given row as a single
|
1267
|
+
paragraph.
|
1268
|
+
|
1269
|
+
See :ref:`dev.as_paragraph`.
|
1270
|
+
"""
|
1271
|
+
return row.as_paragraph(ar)
|
1272
|
+
|
1273
|
+
@classmethod
|
1274
|
+
def row_as_page(cls, ar, row, **kwargs):
|
1275
|
+
"""
|
1276
|
+
Return an HTML string that represent the given row as a plain page.
|
1277
|
+
"""
|
1278
|
+
return row.as_page(ar, **kwargs)
|
1279
|
+
|
1259
1280
|
@classmethod
|
1260
1281
|
def get_choices_text(self, obj, ar, field):
|
1261
1282
|
"""
|
lino/core/fields.py
CHANGED
@@ -69,10 +69,8 @@ def set_default_verbose_name(f):
|
|
69
69
|
later. These fields don't have a name.
|
70
70
|
|
71
71
|
"""
|
72
|
-
if f.
|
73
|
-
|
74
|
-
f.verbose_name = f.remote_field.model._meta.verbose_name
|
75
|
-
elif f.verbose_name == f.name.replace("_", " "):
|
72
|
+
if f.verbose_name is None or (
|
73
|
+
f.name is not None and f.verbose_name == f.name.replace("_", " ")):
|
76
74
|
f.verbose_name = f.remote_field.model._meta.verbose_name
|
77
75
|
|
78
76
|
|
@@ -294,6 +292,7 @@ class FakeField(object):
|
|
294
292
|
wildcard_data_elem = False
|
295
293
|
"""Whether to consider this field as wildcard data element.
|
296
294
|
"""
|
295
|
+
|
297
296
|
sortable_by = None
|
298
297
|
"""
|
299
298
|
A list of names of real fields to be used for sorting when this
|
@@ -658,6 +657,7 @@ class VirtualField(FakeField):
|
|
658
657
|
return
|
659
658
|
self.return_type.model = VirtualModel(model)
|
660
659
|
self.return_type.column = None
|
660
|
+
self.return_type.name = name
|
661
661
|
|
662
662
|
# if name == "overview":
|
663
663
|
# print("20181022", self, self.verbose_name)
|
@@ -811,7 +811,7 @@ class VirtualBooleanField(VirtualField):
|
|
811
811
|
|
812
812
|
def virtualfield(return_type, **kwargs):
|
813
813
|
"""
|
814
|
-
Decorator to turn a method into a :class:`VirtualField`.
|
814
|
+
Decorator to turn a model method into a :class:`VirtualField`.
|
815
815
|
"""
|
816
816
|
|
817
817
|
def decorator(fn):
|
@@ -1334,8 +1334,8 @@ class TableRow(object):
|
|
1334
1334
|
# ar.actor, self.__class__, ar.actor.model))
|
1335
1335
|
dt = self.__class__.get_default_table()
|
1336
1336
|
if dt is not None:
|
1337
|
-
|
1338
|
-
a = dt.detail_action
|
1337
|
+
a = dt.get_request_detail_action(ar)
|
1338
|
+
# a = dt.detail_action
|
1339
1339
|
if a is None or ar is None:
|
1340
1340
|
return a
|
1341
1341
|
if a.get_view_permission(ar.get_user().user_type):
|
@@ -1343,7 +1343,8 @@ class TableRow(object):
|
|
1343
1343
|
return a
|
1344
1344
|
|
1345
1345
|
def get_choices_text(self, ar, actor, field):
|
1346
|
-
return
|
1346
|
+
return self.as_str(ar)
|
1347
|
+
# return str(self)
|
1347
1348
|
|
1348
1349
|
# @fields.displayfield(_("Description"))
|
1349
1350
|
# @htmlbox(_("Overview"))
|
@@ -1365,13 +1366,24 @@ class TableRow(object):
|
|
1365
1366
|
# return [ar.obj2html(self)]
|
1366
1367
|
return [self.as_summary_item(ar)]
|
1367
1368
|
|
1369
|
+
def as_str(self, ar):
|
1370
|
+
# must return a str
|
1371
|
+
if ar.actor is None:
|
1372
|
+
return str(self)
|
1373
|
+
elif ar.actor.row_template is None or not isinstance(self, ar.actor.model):
|
1374
|
+
return " ".join(self.get_str_words(ar))
|
1375
|
+
return ar.actor.row_template.format(row=self)
|
1376
|
+
|
1377
|
+
def get_str_words(self, ar):
|
1378
|
+
# must yield a sequence of str (or Promise)
|
1379
|
+
yield str(self)
|
1380
|
+
|
1368
1381
|
def as_summary_item(self, ar, text=None, **kwargs):
|
1369
1382
|
# must return an ET element
|
1370
1383
|
if ar is None:
|
1371
1384
|
return text or str(self)
|
1372
|
-
if text is None
|
1373
|
-
text =
|
1374
|
-
# raise Exception("20241029")
|
1385
|
+
if text is None:
|
1386
|
+
text = self.as_str(ar)
|
1375
1387
|
return ar.obj2html(self, text, **kwargs)
|
1376
1388
|
|
1377
1389
|
def as_paragraph(self, ar, **kwargs):
|
@@ -1710,12 +1722,10 @@ def choices_for_field(ar, holder, field):
|
|
1710
1722
|
# same code as for ForeignKey
|
1711
1723
|
def row2dict(obj, d):
|
1712
1724
|
d[constants.CHOICES_TEXT_FIELD] = holder.get_choices_text(
|
1713
|
-
obj, ar
|
1714
|
-
)
|
1725
|
+
obj, ar, field)
|
1715
1726
|
d[constants.CHOICES_VALUE_FIELD] = obj.pk
|
1716
1727
|
return d
|
1717
1728
|
else: # values are (value, text) tuples
|
1718
|
-
|
1719
1729
|
def row2dict(obj, d):
|
1720
1730
|
d[constants.CHOICES_TEXT_FIELD] = str(obj[1])
|
1721
1731
|
d[constants.CHOICES_VALUE_FIELD] = obj[0]
|
@@ -1732,8 +1742,7 @@ def choices_for_field(ar, holder, field):
|
|
1732
1742
|
d[constants.CHOICES_VALUE_FIELD] = obj[0]
|
1733
1743
|
else:
|
1734
1744
|
d[constants.CHOICES_TEXT_FIELD] = holder.get_choices_text(
|
1735
|
-
obj, ar
|
1736
|
-
)
|
1745
|
+
obj, ar, field)
|
1737
1746
|
d[constants.CHOICES_VALUE_FIELD] = str(obj)
|
1738
1747
|
return d
|
1739
1748
|
|
@@ -1757,8 +1766,7 @@ def choices_for_field(ar, holder, field):
|
|
1757
1766
|
|
1758
1767
|
def row2dict(obj, d):
|
1759
1768
|
d[constants.CHOICES_TEXT_FIELD] = holder.get_choices_text(
|
1760
|
-
obj, ar
|
1761
|
-
)
|
1769
|
+
obj, ar, field)
|
1762
1770
|
d[constants.CHOICES_VALUE_FIELD] = obj.pk
|
1763
1771
|
return d
|
1764
1772
|
else:
|
lino/core/kernel.py
CHANGED
@@ -21,8 +21,6 @@ application.
|
|
21
21
|
"""
|
22
22
|
|
23
23
|
import os
|
24
|
-
from os.path import join, dirname
|
25
|
-
|
26
24
|
import sys
|
27
25
|
import time
|
28
26
|
import codecs
|
@@ -49,6 +47,7 @@ from django.db import models
|
|
49
47
|
from lino import logger
|
50
48
|
from lino.utils import codetime
|
51
49
|
from lino.utils.html import E
|
50
|
+
from lino.core.utils import format_request
|
52
51
|
# from lino.utils import isiterable
|
53
52
|
from lino.core import layouts
|
54
53
|
from lino.core import actors
|
@@ -166,6 +165,7 @@ class Kernel(object):
|
|
166
165
|
|
167
166
|
def h(signum, frame):
|
168
167
|
site.shutdown()
|
168
|
+
sys.exit()
|
169
169
|
|
170
170
|
signal.signal(sig, h)
|
171
171
|
|
@@ -827,7 +827,7 @@ class Kernel(object):
|
|
827
827
|
A(ar.bound_action.full_name())
|
828
828
|
A(obj2str(ar.master_instance))
|
829
829
|
A(obj2str(ar.selected_rows))
|
830
|
-
|
830
|
+
A(format_request(ar.request))
|
831
831
|
ar.logger.info("run_action {0}".format(" ".join(flds)))
|
832
832
|
# logger.info("run_action {0}".format(ar))
|
833
833
|
# if str(a) != 'grid_put':
|
@@ -910,8 +910,6 @@ class Kernel(object):
|
|
910
910
|
# logger.info("STATIC_ROOT does not exist: %s", settings.STATIC_ROOT)
|
911
911
|
# return 0
|
912
912
|
fn = self.site.media_root / fn
|
913
|
-
# fn = join(settings.STATIC_ROOT, fn)
|
914
|
-
# fn = join(self.site.site_dir, fn)
|
915
913
|
if not force and not self._must_build and fn.exists():
|
916
914
|
mtime = os.stat(fn).st_mtime
|
917
915
|
if mtime > self.code_mtime:
|
@@ -931,7 +929,7 @@ class Kernel(object):
|
|
931
929
|
if verbosity > 1:
|
932
930
|
logger.info("Building %s ...", fn)
|
933
931
|
|
934
|
-
self.site.makedirs_if_missing(
|
932
|
+
self.site.makedirs_if_missing(fn.parent)
|
935
933
|
f = codecs.open(fn, "w", encoding="utf-8")
|
936
934
|
try:
|
937
935
|
write(f)
|
lino/core/model.py
CHANGED
@@ -1,5 +1,5 @@
|
|
1
1
|
# -*- coding: UTF-8 -*-
|
2
|
-
# Copyright 2009-
|
2
|
+
# Copyright 2009-2024 Rumma & Ko Ltd
|
3
3
|
# License: GNU Affero General Public License v3 (see file COPYING for details)
|
4
4
|
"""Defines the :class:`Model` class.
|
5
5
|
|
@@ -37,30 +37,20 @@ from .workflows import ChangeStateAction
|
|
37
37
|
from .requests import ActionRequest, sliced_data_iterator
|
38
38
|
from .tables import AbstractTable
|
39
39
|
|
40
|
-
# try:
|
41
|
-
# import bleach
|
42
|
-
# except ImportError:
|
43
|
-
# bleach = None
|
44
|
-
|
45
40
|
|
46
41
|
class Model(models.Model, fields.TableRow):
|
42
|
+
|
47
43
|
class Meta(object):
|
48
44
|
abstract = True
|
49
45
|
|
50
46
|
allow_cascaded_copy = frozenset()
|
51
47
|
allow_cascaded_delete = frozenset()
|
52
|
-
|
53
48
|
grid_post = actions.CreateRow()
|
54
49
|
submit_insert = actions.SubmitInsert()
|
55
|
-
|
56
50
|
allow_merge_action = False
|
57
|
-
|
58
51
|
master_data_fields = None
|
59
|
-
|
60
52
|
show_in_site_search = True
|
61
|
-
|
62
53
|
quick_search_fields = None
|
63
|
-
|
64
54
|
quick_search_fields_digit = None
|
65
55
|
|
66
56
|
active_fields = frozenset()
|
@@ -88,10 +78,6 @@ class Model(models.Model, fields.TableRow):
|
|
88
78
|
Internally used by :mod:`lino.modlib.changes`.
|
89
79
|
"""
|
90
80
|
|
91
|
-
# disable_create_choice = False
|
92
|
-
# """Whether to disable any automatic creation by learning choosers.
|
93
|
-
# """
|
94
|
-
|
95
81
|
_lino_tables = []
|
96
82
|
_bleached_fields = []
|
97
83
|
|
@@ -956,11 +942,14 @@ LINO_MODEL_ATTRIBS = (
|
|
956
942
|
"hidden_elements",
|
957
943
|
"get_simple_parameters",
|
958
944
|
"get_request_queryset",
|
945
|
+
"get_request_words",
|
959
946
|
"get_title_tags",
|
960
947
|
"get_default_table",
|
961
948
|
"get_default_table",
|
962
949
|
"get_layout_aliases",
|
963
950
|
"edge_ngram_field",
|
951
|
+
"as_str",
|
952
|
+
"get_str_words",
|
964
953
|
"as_summary_item",
|
965
954
|
"as_paragraph",
|
966
955
|
"as_page",
|
lino/core/renderer.py
CHANGED
lino/core/requests.py
CHANGED
@@ -81,6 +81,26 @@ Subject: {subject}
|
|
81
81
|
def noop(ar):
|
82
82
|
return ar.success(gettext("Aborted"))
|
83
83
|
|
84
|
+
def mi2bp(master_instance, bp):
|
85
|
+
if master_instance is not None:
|
86
|
+
if isinstance(master_instance, (models.Model, TableRow)):
|
87
|
+
bp[constants.URL_PARAM_MASTER_PK] = master_instance.pk
|
88
|
+
if ContentType is not None and isinstance(
|
89
|
+
master_instance, models.Model
|
90
|
+
):
|
91
|
+
assert not master_instance._meta.abstract
|
92
|
+
mt = ContentType.objects.get_for_model(
|
93
|
+
master_instance.__class__).pk
|
94
|
+
bp[constants.URL_PARAM_MASTER_TYPE] = mt
|
95
|
+
# else:
|
96
|
+
# logger.warning("20141205 %s %s",
|
97
|
+
# self.master_instance,
|
98
|
+
# ContentType)
|
99
|
+
else: # if self.master is None:
|
100
|
+
# e.g. in accounting.MovementsByMatch the master is a `str`
|
101
|
+
bp[constants.URL_PARAM_MASTER_PK] = master_instance
|
102
|
+
# raise Exception("No master key for {} {!r}".format(
|
103
|
+
# self.master_instance.__class__, self.master_instance))
|
84
104
|
|
85
105
|
class StringLogger(logging.Logger):
|
86
106
|
# Instantiated by BaseRequest.capture_logger()
|
@@ -152,7 +172,7 @@ class ValidActionResponses(object):
|
|
152
172
|
|
153
173
|
no_data_text = None
|
154
174
|
title = None
|
155
|
-
"""The dynamic title to give to the window or component
|
175
|
+
"""The dynamic title to give to the window or component that shows this response.
|
156
176
|
TODO: is this still being used?
|
157
177
|
"""
|
158
178
|
|
@@ -308,7 +328,7 @@ class BaseRequest:
|
|
308
328
|
action_param_values = None
|
309
329
|
param_values = None
|
310
330
|
bound_action = None
|
311
|
-
known_values =
|
331
|
+
known_values = None
|
312
332
|
no_data_text = _("No data to display")
|
313
333
|
is_on_main_actor = True
|
314
334
|
permalink_uris = False
|
@@ -317,6 +337,7 @@ class BaseRequest:
|
|
317
337
|
master_instance = None
|
318
338
|
request = None
|
319
339
|
selected_rows = []
|
340
|
+
obvious_fields = None
|
320
341
|
order_by = None
|
321
342
|
filter = None
|
322
343
|
gridfilters = None,
|
@@ -336,11 +357,19 @@ class BaseRequest:
|
|
336
357
|
parent=None,
|
337
358
|
is_on_main_actor=True,
|
338
359
|
permalink_uris=None,
|
360
|
+
known_values=None,
|
361
|
+
obvious_fields=None,
|
339
362
|
**kw
|
340
363
|
):
|
341
364
|
self.response = dict()
|
365
|
+
self.obvious_fields = set()
|
366
|
+
if obvious_fields is not None:
|
367
|
+
self.obvious_fields |= obvious_fields
|
342
368
|
# if str(kw.get('actor', None)) == "cal.EntriesByController":
|
343
369
|
# if kw.get('actor', None):
|
370
|
+
|
371
|
+
self.known_values = dict()
|
372
|
+
|
344
373
|
if request is not None:
|
345
374
|
assert parent is None
|
346
375
|
self.request = request
|
@@ -361,9 +390,11 @@ class BaseRequest:
|
|
361
390
|
raise Exception("%s : %s is None" % (kw, k))
|
362
391
|
else:
|
363
392
|
kw[k] = getattr(parent, k)
|
364
|
-
kv = kw.setdefault("known_values", {})
|
365
|
-
if parent.actor is self.actor:
|
366
|
-
|
393
|
+
# kv = kw.setdefault("known_values", {})
|
394
|
+
if parent.actor is not None and parent.actor is self.actor:
|
395
|
+
kw['param_values'] = parent.param_values
|
396
|
+
if parent.known_values is not None:
|
397
|
+
self.known_values.update(parent.known_values)
|
367
398
|
# kw.setdefault('user', parent.user)
|
368
399
|
# kw.setdefault('subst_user', parent.subst_user)
|
369
400
|
# kw.setdefault('renderer', parent.renderer)
|
@@ -382,10 +413,27 @@ class BaseRequest:
|
|
382
413
|
self.is_on_main_actor = is_on_main_actor
|
383
414
|
self.permalink_uris = permalink_uris
|
384
415
|
|
416
|
+
if known_values is not None:
|
417
|
+
self.known_values.update(known_values)
|
418
|
+
|
385
419
|
self.setup(**kw)
|
386
420
|
|
387
421
|
# print("20241101", self.__class__.__name__, self.show_urls)
|
388
422
|
|
423
|
+
self.obvious_fields |= set(self.known_values.keys())
|
424
|
+
|
425
|
+
if self.actor is not None:
|
426
|
+
|
427
|
+
for k, v in self.actor.known_values.items():
|
428
|
+
self.known_values.setdefault(k, v)
|
429
|
+
|
430
|
+
self.obvious_fields |= self.actor.obvious_fields
|
431
|
+
# self.obvious_fields.update(obvious_fields.split())
|
432
|
+
# if parent.obvious_fields is not None:
|
433
|
+
if parent is not None and parent.actor is self.actor and parent.obvious_fields:
|
434
|
+
self.obvious_fields |= parent.obvious_fields
|
435
|
+
self.obvious_fields.add(self.actor.master_key)
|
436
|
+
|
389
437
|
if self.master is not None and settings.SITE.strict_master_check:
|
390
438
|
if self.master_instance is None:
|
391
439
|
raise exceptions.BadRequest(
|
@@ -414,7 +462,6 @@ class BaseRequest:
|
|
414
462
|
requesting_panel=None,
|
415
463
|
renderer=None,
|
416
464
|
xcallback_answers=None,
|
417
|
-
known_values={},
|
418
465
|
show_urls=None,
|
419
466
|
quick_search=None,
|
420
467
|
order_by=None,
|
@@ -1118,14 +1165,17 @@ class BaseRequest:
|
|
1118
1165
|
an obvious value.
|
1119
1166
|
|
1120
1167
|
"""
|
1121
|
-
|
1122
|
-
|
1123
|
-
# if self.param_values is not None and name in self.param_values:
|
1168
|
+
return name in self.obvious_fields
|
1169
|
+
# if name in self.known_values:
|
1124
1170
|
# return True
|
1125
|
-
if self.
|
1126
|
-
|
1127
|
-
|
1128
|
-
|
1171
|
+
# # if self.param_values is not None and name in self.param_values:
|
1172
|
+
# # return True
|
1173
|
+
# if self.actor is not None:
|
1174
|
+
# if self.actor.master_key == name:
|
1175
|
+
# return True
|
1176
|
+
# if name in self.actor.obvious_fields:
|
1177
|
+
# return True
|
1178
|
+
# return False
|
1129
1179
|
|
1130
1180
|
def get_user(self):
|
1131
1181
|
"""
|
@@ -1328,10 +1378,8 @@ class BaseRequest:
|
|
1328
1378
|
return self.renderer.obj2url(self, *args, **kwargs)
|
1329
1379
|
|
1330
1380
|
def obj2html(self, obj, text=None, **kwargs):
|
1331
|
-
|
1332
|
-
|
1333
|
-
given database object.
|
1334
|
-
"""
|
1381
|
+
# Return a clickable HTML element that points to a detail view of the
|
1382
|
+
# given database object.
|
1335
1383
|
if obj is None:
|
1336
1384
|
return ""
|
1337
1385
|
return self.renderer.obj2html(self, obj, text, **kwargs)
|
@@ -1690,7 +1738,6 @@ class ActionRequest(BaseRequest):
|
|
1690
1738
|
|
1691
1739
|
def setup(
|
1692
1740
|
self,
|
1693
|
-
known_values=None,
|
1694
1741
|
param_values=None,
|
1695
1742
|
action_param_values={},
|
1696
1743
|
offset=None,
|
@@ -1719,12 +1766,7 @@ class ActionRequest(BaseRequest):
|
|
1719
1766
|
assert self.actor is not None
|
1720
1767
|
request = self.request
|
1721
1768
|
|
1722
|
-
|
1723
|
-
for k, v in self.actor.known_values.items():
|
1724
|
-
kv.setdefault(k, v)
|
1725
|
-
if known_values:
|
1726
|
-
kv.update(known_values)
|
1727
|
-
self.known_values = kv
|
1769
|
+
self.actor.setup_request(self)
|
1728
1770
|
|
1729
1771
|
if self.actor.parameters is not None:
|
1730
1772
|
pv = self.actor.param_defaults(self)
|
@@ -1802,8 +1844,6 @@ class ActionRequest(BaseRequest):
|
|
1802
1844
|
self.set_action_param_values(**action_param_values)
|
1803
1845
|
self.bound_action.setup_action_request(self)
|
1804
1846
|
|
1805
|
-
self.actor.setup_request(self)
|
1806
|
-
|
1807
1847
|
# if str(self.actor) == 'outbox.MyOutbox':
|
1808
1848
|
# if self.master_instance is None:
|
1809
1849
|
# raise Exception("20230426 b {}".format(self.master))
|
@@ -1875,6 +1915,8 @@ class ActionRequest(BaseRequest):
|
|
1875
1915
|
if target is None:
|
1876
1916
|
target = self.actor
|
1877
1917
|
if self._insert_sar is None:
|
1918
|
+
if target.insert_action is None:
|
1919
|
+
raise Exception(f"20241212 {target} has no insert_action")
|
1878
1920
|
self._insert_sar = target.insert_action.request_from(self)
|
1879
1921
|
else:
|
1880
1922
|
assert self._insert_sar.actor is target
|
@@ -2108,26 +2150,7 @@ class ActionRequest(BaseRequest):
|
|
2108
2150
|
for k, v in self.known_values.items():
|
2109
2151
|
if self.actor.known_values.get(k, None) != v:
|
2110
2152
|
bp[k] = v
|
2111
|
-
|
2112
|
-
if isinstance(self.master_instance, (models.Model, TableRow)):
|
2113
|
-
bp[constants.URL_PARAM_MASTER_PK] = self.master_instance.pk
|
2114
|
-
if ContentType is not None and isinstance(
|
2115
|
-
self.master_instance, models.Model
|
2116
|
-
):
|
2117
|
-
assert not self.master_instance._meta.abstract
|
2118
|
-
mt = ContentType.objects.get_for_model(
|
2119
|
-
self.master_instance.__class__
|
2120
|
-
).pk
|
2121
|
-
bp[constants.URL_PARAM_MASTER_TYPE] = mt
|
2122
|
-
# else:
|
2123
|
-
# logger.warning("20141205 %s %s",
|
2124
|
-
# self.master_instance,
|
2125
|
-
# ContentType)
|
2126
|
-
else: # if self.master is None:
|
2127
|
-
# e.g. in accounting.MovementsByMatch the master is a `str`
|
2128
|
-
bp[constants.URL_PARAM_MASTER_PK] = self.master_instance
|
2129
|
-
# raise Exception("No master key for {} {!r}".format(
|
2130
|
-
# self.master_instance.__class__, self.master_instance))
|
2153
|
+
mi2bp(self.master_instance, bp)
|
2131
2154
|
self._status = kw
|
2132
2155
|
return kw
|
2133
2156
|
|
@@ -2421,7 +2444,7 @@ class ActionRequest(BaseRequest):
|
|
2421
2444
|
oh = ar.actor.override_column_headers(ar)
|
2422
2445
|
if oh:
|
2423
2446
|
for i, e in enumerate(columns):
|
2424
|
-
header = oh.get(e
|
2447
|
+
header = oh.get(e, None)
|
2425
2448
|
if header is not None:
|
2426
2449
|
headers[i] = header
|
2427
2450
|
# ~ print 20120507, oh, headers
|
lino/core/site.py
CHANGED
@@ -2165,7 +2165,7 @@ class Site(object):
|
|
2165
2165
|
site_prefix = "/"
|
2166
2166
|
"""The string to prefix to every URL of the Lino web interface.
|
2167
2167
|
|
2168
|
-
This must *start and end with a *slash*. Default value is
|
2168
|
+
This must *start and end* with a *slash*. Default value is
|
2169
2169
|
``'/'``.
|
2170
2170
|
|
2171
2171
|
This must be set if your project is not being served at the "root"
|
lino/core/tables.py
CHANGED
@@ -521,22 +521,6 @@ method in order to sort the rows of the queryset.
|
|
521
521
|
return cls.detail_action
|
522
522
|
return actions.ShowTable()
|
523
523
|
|
524
|
-
@classmethod
|
525
|
-
def row_as_paragraph(cls, ar, row):
|
526
|
-
"""Return an HTML string that represents the given row as a single
|
527
|
-
paragraph.
|
528
|
-
|
529
|
-
See :ref:`dev.as_paragraph`.
|
530
|
-
"""
|
531
|
-
return row.as_paragraph(ar)
|
532
|
-
|
533
|
-
@classmethod
|
534
|
-
def row_as_page(cls, ar, row, **kwargs):
|
535
|
-
"""
|
536
|
-
Return an HTML string that represent the given row as a plain page.
|
537
|
-
"""
|
538
|
-
return row.as_page(ar, **kwargs)
|
539
|
-
|
540
524
|
@classmethod
|
541
525
|
def get_actor_editable(self):
|
542
526
|
if self._editable is None:
|
lino/help_texts.py
CHANGED
@@ -323,8 +323,10 @@ help_texts = {
|
|
323
323
|
'lino.core.model.Model.allow_cascaded_delete' : _("""A set of names of ForeignKey or GenericForeignKey fields of this model that allow for cascaded delete."""),
|
324
324
|
'lino.core.model.Model.disabled_fields' : _("""Return a set of field names that should be disabled (i.e. not editable) for this database object."""),
|
325
325
|
'lino.core.model.Model.__str__' : _("""Return a translatable text that describes this database row."""),
|
326
|
-
'lino.core.model.Model.
|
326
|
+
'lino.core.model.Model.as_str' : _("""Return a translatable text that describes this database row. Unlike __str__() this method gets an action request when it is called, so it knows the context."""),
|
327
|
+
'lino.core.model.Model.get_str_words' : _("""Yield a series of words that describe this database row in plain text."""),
|
327
328
|
'lino.core.model.Model.as_summary_item' : _("""Return a HTML element that represents this database row in a data window in display mode “summary”."""),
|
329
|
+
'lino.core.model.Model.as_paragraph' : _("""Return a safe HTML string that represents this database row as a paragraph."""),
|
328
330
|
'lino.core.model.Model.set_widget_options' : _("""Set default values for the widget options of a given element."""),
|
329
331
|
'lino.core.model.Model.get_overview_elems' : _("""Return a list of HTML elements to be shown in overview field."""),
|
330
332
|
'lino.core.model.Model.merge_row' : _("""Merge this object into another object of same class."""),
|
@@ -377,7 +379,7 @@ help_texts = {
|
|
377
379
|
'lino.modlib.linod.SystemTask.log_level' : _("""The logging level to apply when running this task."""),
|
378
380
|
'lino.modlib.linod.SystemTask.run' : _("""Performs a routine job."""),
|
379
381
|
'lino.modlib.linod.SystemTasks' : _("""The default actor for the SystemTask model."""),
|
380
|
-
'lino.modlib.periods.StoredYear' : _("""The Django model used to store
|
382
|
+
'lino.modlib.periods.StoredYear' : _("""The Django model used to store a fiscal year."""),
|
381
383
|
'lino.modlib.periods.StoredPeriod' : _("""The Django model used to store an accounting period."""),
|
382
384
|
'lino.modlib.periods.StoredYears' : _("""The fiscal years defined in this database."""),
|
383
385
|
'lino.modlib.periods.StoredPeriods' : _("""The accounting periods defined in this database."""),
|
@@ -689,7 +691,6 @@ help_texts = {
|
|
689
691
|
'lino.modlib.uploads.UploadController.show_uploads' : _("""Opens a data window with the uploaded files associated to this database object."""),
|
690
692
|
'lino.modlib.uploads.UploadsByController' : _("""Shows the uploaded files associated to this database object."""),
|
691
693
|
'lino.modlib.uploads.Shortcuts' : _("""The list of available upload shortcut fields in this application."""),
|
692
|
-
'lino.modlib.uploads.Previewers' : _("""An abstract choicelist of the previewers that are available on this site."""),
|
693
694
|
'lino.modlib.uploads.UploadsFolderChecker' : _("""Find orphaned files in uploads folder."""),
|
694
695
|
'lino.modlib.weasyprint.WeasyBuildMethod' : _("""The base class for both build methods."""),
|
695
696
|
'lino.modlib.weasyprint.WeasyHtmlBuildMethod' : _("""Renders the input template and returns the unmodified output as plain HTML."""),
|