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/mixins/duplicable.py
CHANGED
@@ -34,16 +34,18 @@ class Duplicate(actions.Action):
|
|
34
34
|
|
35
35
|
# required_roles = set([Expert])
|
36
36
|
|
37
|
-
def
|
37
|
+
def get_action_view_permission(self, actor, user_type):
|
38
38
|
# the action is readonly because it doesn't write to the
|
39
39
|
# current object, but since it does modify the database we
|
40
40
|
# want to hide it for readonly users.
|
41
|
+
if not actor.allow_create:
|
42
|
+
return False
|
41
43
|
if user_type:
|
42
44
|
if user_type.readonly:
|
43
45
|
return False
|
44
46
|
# if not user_type.has_required_roles([Expert]):
|
45
47
|
# return False
|
46
|
-
return super().
|
48
|
+
return super().get_action_view_permission(actor, user_type)
|
47
49
|
|
48
50
|
def run_from_code(self, ar, **known_values):
|
49
51
|
obj = ar.selected_rows[0]
|
@@ -98,6 +100,10 @@ class Duplicate(actions.Action):
|
|
98
100
|
def run_from_ui(self, ar, **kw):
|
99
101
|
"""This actually runs the action."""
|
100
102
|
|
103
|
+
if (msg := ar.actor.model.disable_create(ar)) is not None:
|
104
|
+
ar.error(msg)
|
105
|
+
return
|
106
|
+
|
101
107
|
def ok(ar2):
|
102
108
|
new = self.run_from_code(ar)
|
103
109
|
kw = dict()
|
lino/mixins/registrable.py
CHANGED
@@ -109,7 +109,7 @@ class Registrable(model.Model):
|
|
109
109
|
|
110
110
|
@classmethod
|
111
111
|
def get_registrable_fields(self, site):
|
112
|
-
for f in super(
|
112
|
+
for f in super().get_registrable_fields(site):
|
113
113
|
yield f
|
114
114
|
yield 'user'
|
115
115
|
yield 'date'
|
lino/modlib/changes/utils.py
CHANGED
@@ -4,7 +4,8 @@
|
|
4
4
|
Defines the :func:`watch_changes` function and :class:`WatcherSpec` class.
|
5
5
|
|
6
6
|
"""
|
7
|
-
from lino.core import
|
7
|
+
from lino.core.fields import RemoteField
|
8
|
+
from lino.core.atomizer import fields_list
|
8
9
|
|
9
10
|
|
10
11
|
class WatcherSpec:
|
@@ -40,13 +41,13 @@ def return_self(obj):
|
|
40
41
|
|
41
42
|
def watch_changes(model, ignore=[], master_key=None, **options):
|
42
43
|
if isinstance(ignore, str):
|
43
|
-
ignore =
|
44
|
+
ignore = fields_list(model, ignore)
|
44
45
|
if isinstance(master_key, str):
|
45
46
|
fld = model.get_data_elem(master_key)
|
46
47
|
if fld is None:
|
47
48
|
raise Exception("No field %r in %s" % (master_key, model))
|
48
49
|
master_key = fld
|
49
|
-
if isinstance(master_key,
|
50
|
+
if isinstance(master_key, RemoteField):
|
50
51
|
get_master = master_key.func
|
51
52
|
elif master_key is None:
|
52
53
|
get_master = return_self
|
@@ -2,12 +2,11 @@
|
|
2
2
|
# Copyright 2014-2025 Rumma & Ko Ltd
|
3
3
|
# License: GNU Affero General Public License v3 (see file COPYING for details)
|
4
4
|
|
5
|
-
import os
|
6
|
-
|
7
5
|
from django.conf import settings
|
8
6
|
from django.db.models import Model
|
9
7
|
from django.utils.functional import Promise
|
10
8
|
from django.utils.html import SafeString
|
9
|
+
from django.utils.timezone import make_naive, is_aware
|
11
10
|
from lino.utils.html import iselement, to_rst
|
12
11
|
|
13
12
|
from lino.core import actions
|
@@ -100,6 +99,11 @@ def ar2workbook(ar, column_names=None):
|
|
100
99
|
value = str(value)
|
101
100
|
elif isinstance(value, Model):
|
102
101
|
value = str(value)
|
102
|
+
elif isinstance(value, datetime.datetime):
|
103
|
+
# Excel does not support timezones in datetimes. The tzinfo in
|
104
|
+
# the datetime/time object must be set to None.
|
105
|
+
if is_aware(value):
|
106
|
+
value = make_naive()
|
103
107
|
elif isinstance(value, str):
|
104
108
|
# if it is a future.newstr, change it to a real string to avoid
|
105
109
|
# ValueError: Cannot convert 'Hans Altenberg' to Excel
|
@@ -109,7 +113,7 @@ def ar2workbook(ar, column_names=None):
|
|
109
113
|
if style is not None:
|
110
114
|
cell.style = style
|
111
115
|
cell.value = value
|
112
|
-
except ValueError
|
116
|
+
except ValueError:
|
113
117
|
raise Exception("20190222 {} {}".format(
|
114
118
|
value.__class__, value))
|
115
119
|
|
@@ -23,6 +23,7 @@ from lino.core import constants
|
|
23
23
|
# from lino.core.renderer import JsRenderer
|
24
24
|
from lino.core.renderer import JsCacheRenderer
|
25
25
|
from lino.core.gfks import ContentType
|
26
|
+
from lino.core.permissions import get_view_permission
|
26
27
|
|
27
28
|
from lino.core.actions import (
|
28
29
|
ShowEmptyTable,
|
@@ -576,7 +577,6 @@ class ExtRenderer(JsCacheRenderer):
|
|
576
577
|
)
|
577
578
|
|
578
579
|
def before_row_edit(self, panel):
|
579
|
-
from lino.core.actions import get_view_permission
|
580
580
|
|
581
581
|
# ~ l.append("console.log('before_row_edit',record);")
|
582
582
|
for e in panel.active_children:
|
lino/modlib/extjs/views.py
CHANGED
@@ -49,6 +49,7 @@ from lino.utils import ucsv
|
|
49
49
|
from lino import logger
|
50
50
|
# from lino.utils import dblogger
|
51
51
|
from lino.core import constants
|
52
|
+
from lino.core import actions
|
52
53
|
from lino.core.fields import choices_for_field
|
53
54
|
from lino.core.views import requested_actor, action_request
|
54
55
|
from lino.core.views import json_response
|
@@ -440,6 +441,7 @@ class ApiElement(View):
|
|
440
441
|
|
441
442
|
if ba.action.opens_a_window:
|
442
443
|
if fmt == constants.URL_FORMAT_JSON:
|
444
|
+
# datarec = ba.action.get_datarec(pk)
|
443
445
|
if pk == "-99999":
|
444
446
|
elem = ar.create_instance()
|
445
447
|
datarec = ar.elem2rec_insert(ar.ah, elem)
|
@@ -449,6 +451,9 @@ class ApiElement(View):
|
|
449
451
|
elif elem is None:
|
450
452
|
datarec = dict(
|
451
453
|
success=False, message=NOT_FOUND % (rpt, pk))
|
454
|
+
elif isinstance(ba.action, actions.ShowInsert):
|
455
|
+
elem = ar.create_instance()
|
456
|
+
datarec = ar.elem2rec_insert(ar.ah, elem)
|
452
457
|
else:
|
453
458
|
datarec = ar.elem2rec_detailed(elem)
|
454
459
|
datarec.update(**vm)
|
lino/modlib/linod/mixins.py
CHANGED
@@ -3,18 +3,14 @@
|
|
3
3
|
# License: GNU Affero General Public License v3 (see file COPYING for details)
|
4
4
|
# See https://dev.lino-framework.org/plugins/linod.html
|
5
5
|
|
6
|
-
import logging
|
7
6
|
import traceback
|
8
7
|
import asyncio
|
9
|
-
import pickle
|
10
8
|
from datetime import timedelta
|
11
|
-
from django.conf import settings
|
12
9
|
from django.db import models
|
13
10
|
from django.utils import timezone
|
14
11
|
# from django.core.exceptions import ValidationError
|
15
12
|
from asgiref.sync import sync_to_async, async_to_sync
|
16
13
|
|
17
|
-
from lino import logger
|
18
14
|
from lino.api import dd, _
|
19
15
|
from lino.mixins import Sequenced
|
20
16
|
from lino.modlib.system.mixins import RecurrenceSet
|
@@ -45,7 +41,8 @@ class RunNow(dd.Action):
|
|
45
41
|
|
46
42
|
def run_from_ui(self, ar, **kwargs):
|
47
43
|
# print("20231102 RunNow", ar.selected_rows)
|
48
|
-
now = dd.now()
|
44
|
+
# now = dd.now()
|
45
|
+
now = timezone.now()
|
49
46
|
for obj in ar.selected_rows:
|
50
47
|
assert issubclass(obj.__class__, Runnable)
|
51
48
|
if True: # dd.plugins.linod.use_channels:
|
@@ -155,7 +152,8 @@ class Runnable(Sequenced, RecurrenceSet):
|
|
155
152
|
await ar.adebug("Start %s with logging level %s", self, self.log_level)
|
156
153
|
# ar.info("Start %s with logging level %s", astr(self), self.log_level)
|
157
154
|
# forget about any previous run:
|
158
|
-
now = await sync_to_async(dd.now)()
|
155
|
+
# now = await sync_to_async(dd.now)()
|
156
|
+
now = timezone.now()
|
159
157
|
self.last_start_time = now
|
160
158
|
self.requested_at = None
|
161
159
|
self.last_end_time = None
|
@@ -186,8 +184,8 @@ class Runnable(Sequenced, RecurrenceSet):
|
|
186
184
|
self.disabled = True
|
187
185
|
await ar.awarning("Disabled %s after exception %s", self, e)
|
188
186
|
# ar.warning("Disabled %s after exception %s", astr(self), e)
|
189
|
-
now = await sync_to_async(dd.now)()
|
190
|
-
self.last_end_time = now
|
187
|
+
# now = await sync_to_async(dd.now)()
|
188
|
+
self.last_end_time = timezone.now()
|
191
189
|
self.message = "<pre>" + self.message + "</pre>"
|
192
190
|
await sync_to_async(self.full_clean)()
|
193
191
|
# self.full_clean()
|
@@ -222,8 +220,8 @@ async def start_task_runner(ar=None, max_count=None):
|
|
222
220
|
count = 0
|
223
221
|
while True:
|
224
222
|
await ar.adebug("Start next task runner loop.")
|
225
|
-
|
226
|
-
now =
|
223
|
+
# now = await sync_to_async(dd.now)()
|
224
|
+
now = timezone.now()
|
227
225
|
next_time = now + \
|
228
226
|
timedelta(seconds=dd.plugins.linod.background_sleep_time)
|
229
227
|
|
@@ -286,7 +284,8 @@ async def start_task_runner(ar=None, max_count=None):
|
|
286
284
|
if max_count is not None and count >= max_count:
|
287
285
|
await ar.ainfo("Stop after %s loops.", max_count)
|
288
286
|
return next_time
|
289
|
-
now = await sync_to_async(dd.now)()
|
287
|
+
# now = await sync_to_async(dd.now)()
|
288
|
+
now = timezone.now()
|
290
289
|
if (to_sleep := (next_time - now).total_seconds()) <= 0:
|
291
290
|
continue
|
292
291
|
await ar.adebug("Let task runner sleep for %s seconds.", to_sleep)
|
lino/modlib/memo/mixins.py
CHANGED
@@ -16,13 +16,11 @@ from django.utils.text import Truncator
|
|
16
16
|
from django.utils.html import format_html
|
17
17
|
|
18
18
|
from lino.core.gfks import gfk2lookup
|
19
|
-
from lino.core.
|
20
|
-
from lino.core.fields import fields_list, RichTextField, PreviewTextField
|
19
|
+
from lino.core.fields import RichTextField, PreviewTextField
|
21
20
|
from lino.utils.html import E, tostring, mark_safe
|
22
21
|
from lino.utils.restify import restify
|
23
22
|
from lino.utils.soup import truncate_comment
|
24
23
|
from lino.utils.mldbc.fields import BabelTextField
|
25
|
-
from lino.core.exceptions import ChangedAPI
|
26
24
|
from lino.modlib.checkdata.choicelists import Checker
|
27
25
|
from lino.api import rt, dd, _
|
28
26
|
|
@@ -11,8 +11,8 @@ class Plugin(ad.Plugin):
|
|
11
11
|
end_year = None
|
12
12
|
duration_max_length = 6
|
13
13
|
|
14
|
-
def
|
14
|
+
def pre_site_startup(self, site):
|
15
15
|
if self.end_year is None:
|
16
|
-
self.end_year =
|
16
|
+
self.end_year = site.today().year
|
17
17
|
if self.start_year is None:
|
18
18
|
self.start_year = self.end_year - 2
|
lino/modlib/uploads/ui.py
CHANGED
@@ -148,6 +148,11 @@ class MyUploads(My, Uploads):
|
|
148
148
|
# return kw
|
149
149
|
|
150
150
|
|
151
|
+
def format_row_in_slave_summary(obj):
|
152
|
+
"""almost as str(), but without the type"""
|
153
|
+
return obj.description or filename_leaf(obj.file.name) or str(obj.id)
|
154
|
+
|
155
|
+
|
151
156
|
class AreaUploads(Uploads):
|
152
157
|
# required_roles = dd.login_required((OfficeUser, OfficeOperator))
|
153
158
|
required_roles = dd.login_required(UploadsReader)
|
@@ -165,11 +170,6 @@ class AreaUploads(Uploads):
|
|
165
170
|
# return self._upload_area.text
|
166
171
|
# return self._label or self.__name__
|
167
172
|
|
168
|
-
@classmethod
|
169
|
-
def format_row_in_slave_summary(self, ar, obj):
|
170
|
-
"""almost as str(), but without the type"""
|
171
|
-
return obj.description or filename_leaf(obj.file.name) or str(obj.id)
|
172
|
-
|
173
173
|
@classmethod
|
174
174
|
def get_table_summary(self, ar):
|
175
175
|
obj = ar.master_instance
|
@@ -198,9 +198,7 @@ class AreaUploads(Uploads):
|
|
198
198
|
# logger.info("20140430 %s", sar.data_iterator.query)
|
199
199
|
files = []
|
200
200
|
for m in sar:
|
201
|
-
text =
|
202
|
-
if text is None:
|
203
|
-
continue
|
201
|
+
text = format_row_in_slave_summary(m)
|
204
202
|
edit = ar.obj2html(
|
205
203
|
m,
|
206
204
|
text, # _("Edit"),
|
@@ -16,14 +16,14 @@ def root_user(lang, **kw):
|
|
16
16
|
lang = lang.django_code
|
17
17
|
kw.update(language=lang)
|
18
18
|
lang = lang[:2]
|
19
|
-
if lang == "
|
19
|
+
if lang == "en":
|
20
|
+
kw.update(first_name="Robin", last_name="Rood")
|
21
|
+
elif lang == "de":
|
20
22
|
kw.update(first_name="Rolf", last_name="Rompen")
|
21
23
|
elif lang == "fr":
|
22
24
|
kw.update(first_name="Romain", last_name="Raffault")
|
23
25
|
elif lang == "et":
|
24
26
|
kw.update(first_name="Rando", last_name="Roosi")
|
25
|
-
elif lang == "en":
|
26
|
-
kw.update(first_name="Robin", last_name="Rood")
|
27
27
|
elif lang == "pt":
|
28
28
|
kw.update(first_name="Ronaldo", last_name="Rosa")
|
29
29
|
elif lang == "es":
|
@@ -41,13 +41,16 @@ def root_user(lang, **kw):
|
|
41
41
|
|
42
42
|
def objects():
|
43
43
|
# logger.info("20150323 %s", settings.SITE.languages)
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
44
|
+
SITE = settings.SITE
|
45
|
+
User = SITE.user_model
|
46
|
+
if User is None:
|
47
|
+
return
|
48
|
+
for lang in SITE.languages:
|
49
|
+
if (SITE.hidden_languages is None
|
50
|
+
or lang.django_code not in SITE.hidden_languages):
|
51
|
+
kw = root_user(lang)
|
52
|
+
if kw:
|
53
|
+
u = User(**kw)
|
54
|
+
if SITE.is_demo_site:
|
55
|
+
u.set_password(SITE.plugins.users.demo_password)
|
56
|
+
yield u
|
lino/utils/choosers.py
CHANGED
@@ -21,7 +21,8 @@ from dateutil import parser as dateparser
|
|
21
21
|
from django.core.exceptions import BadRequest
|
22
22
|
from django.conf import settings
|
23
23
|
from django.db import models
|
24
|
-
|
24
|
+
from django.apps import apps
|
25
|
+
from lino import logger
|
25
26
|
from lino.core.utils import getrqdata
|
26
27
|
from lino.core import fields
|
27
28
|
from lino.core import constants
|
@@ -520,6 +521,8 @@ def check_for_chooser(holder, field):
|
|
520
521
|
# raise Exception("20200425 {} is not {}".format(holder, ch.model))
|
521
522
|
return ch
|
522
523
|
|
524
|
+
# print("20250518", holder, ch, d)
|
525
|
+
|
523
526
|
methname = field.name + "_choices"
|
524
527
|
m = getattr(holder, methname, None)
|
525
528
|
if m is not None:
|
@@ -536,3 +539,10 @@ def check_for_chooser(holder, field):
|
|
536
539
|
return ch
|
537
540
|
# if field.name == 'city':
|
538
541
|
# logger.info("20140822 chooser for %s.%s", holder, field.name)
|
542
|
+
|
543
|
+
|
544
|
+
def discover_choosers():
|
545
|
+
logger.debug("Discovering choosers for database fields...")
|
546
|
+
for model in apps.get_models():
|
547
|
+
for field in model._meta.fields:
|
548
|
+
check_for_chooser(model, field)
|
lino/utils/diag.py
CHANGED
@@ -13,7 +13,6 @@ from django.utils.encoding import force_str
|
|
13
13
|
|
14
14
|
from lino.modlib.system.choicelists import PeriodEvents
|
15
15
|
from lino.core.layouts import BaseLayout
|
16
|
-
from lino.core.layouts import ParamsLayout
|
17
16
|
from lino.core.fields import DummyField
|
18
17
|
from lino.core.elems import Container, Wrapper, FieldElement
|
19
18
|
from lino.modlib.users.choicelists import UserTypes
|
@@ -21,6 +20,7 @@ from lino.core import actors
|
|
21
20
|
from lino.core import actions
|
22
21
|
from lino.core.utils import get_models, sorted_models_list
|
23
22
|
from lino.core.utils import full_model_name as fmn
|
23
|
+
from lino.core.atomizer import get_atomizer
|
24
24
|
from lino.api import dd
|
25
25
|
|
26
26
|
|
@@ -40,12 +40,15 @@ class Analyzer(object):
|
|
40
40
|
if a.abstract:
|
41
41
|
continue
|
42
42
|
for ba in a.get_actions():
|
43
|
+
# if ba.actor.abstract:
|
44
|
+
# raise Exception(f"20250523 {repr(a)} {repr(ba.actor)}")
|
43
45
|
if ba.action.is_window_action():
|
44
46
|
# We call ba.get_layout_handel() just to increase test
|
45
47
|
# coverage. For example #5608 (presto says Invalid data
|
46
48
|
# element 'topics.InterestsByPartner') by the following
|
47
49
|
# line:
|
48
|
-
ba.get_layout_handel()
|
50
|
+
# ba.get_layout_handel()
|
51
|
+
# 20250523 this is now done by the kernel
|
49
52
|
|
50
53
|
wl = ba.get_window_layout() or ba.action.params_layout
|
51
54
|
if wl is not None:
|
@@ -395,7 +398,7 @@ def visible_for(ba):
|
|
395
398
|
return "nobody"
|
396
399
|
# if len(hidden) < len(visible):
|
397
400
|
# if len(hidden) <= 3:
|
398
|
-
# return "all except %s" % '
|
401
|
+
# return "all except %s" % ' '.join(hidden)
|
399
402
|
return " ".join(visible)
|
400
403
|
|
401
404
|
|
@@ -440,7 +443,6 @@ def py2rst(self, doctestfmt=False, fmt=None):
|
|
440
443
|
something that reflects better what it does.
|
441
444
|
|
442
445
|
"""
|
443
|
-
from lino.core.store import get_atomizer
|
444
446
|
|
445
447
|
if isinstance(self, models.Model) and fmt is None:
|
446
448
|
ar = self.get_default_table().create_request()
|
lino/utils/fieldutils.py
CHANGED
@@ -2,24 +2,27 @@
|
|
2
2
|
# Copyright 2009-2025 Rumma & Ko Ltd
|
3
3
|
# License: GNU Affero General Public License v3 (see file COPYING for details)
|
4
4
|
|
5
|
-
from lino.core.boundaction import BoundAction
|
6
|
-
from lino.core.actions import Action
|
7
|
-
from django.db.models import Model
|
8
|
-
from lino.core.tables import AbstractTable
|
9
|
-
from lino.core.layouts import BaseLayout
|
10
|
-
from lino.core.actions import register_params
|
11
|
-
from rstgen.utils import unindent
|
12
5
|
import rstgen
|
6
|
+
from rstgen.utils import unindent
|
7
|
+
from django.db.models import Model
|
8
|
+
from django.db import models
|
9
|
+
from lino import logger
|
10
|
+
from lino.core.boundaction import BoundAction
|
11
|
+
from lino.core.utils import register_params
|
12
|
+
# from lino.core.utils import full_model_name
|
13
|
+
from lino.core import actions
|
14
|
+
from lino.core import tables
|
15
|
+
from lino.core import layouts
|
13
16
|
|
14
17
|
|
15
18
|
def get_fields(model, fieldnames=None, columns=None):
|
16
|
-
"""Return a list of field in the given database model, action or table.
|
19
|
+
"""Return a list of field in the given database model, action or table.
|
17
20
|
"""
|
18
21
|
if isinstance(model, BoundAction):
|
19
22
|
get_field = model.action.parameters.get
|
20
23
|
if fieldnames is None:
|
21
24
|
fieldnames = model.action.params_layout
|
22
|
-
elif isinstance(model, Action):
|
25
|
+
elif isinstance(model, actions.Action):
|
23
26
|
get_field = model.parameters.get
|
24
27
|
if fieldnames is None:
|
25
28
|
fieldnames = model.params_layout.main
|
@@ -28,7 +31,7 @@ def get_fields(model, fieldnames=None, columns=None):
|
|
28
31
|
# get_field = model.get_data_elem
|
29
32
|
if fieldnames is None:
|
30
33
|
fieldnames = [f.name for f in model._meta.get_fields()]
|
31
|
-
elif issubclass(model, AbstractTable):
|
34
|
+
elif issubclass(model, tables.AbstractTable):
|
32
35
|
if columns:
|
33
36
|
get_field = model.get_data_elem
|
34
37
|
if fieldnames is None:
|
@@ -37,7 +40,7 @@ def get_fields(model, fieldnames=None, columns=None):
|
|
37
40
|
else:
|
38
41
|
get_field = model.parameters.get
|
39
42
|
if fieldnames is None:
|
40
|
-
if not isinstance(model.params_layout, BaseLayout):
|
43
|
+
if not isinstance(model.params_layout, layouts.BaseLayout):
|
41
44
|
register_params(model)
|
42
45
|
fieldnames = model.params_layout.main
|
43
46
|
if fieldnames is None:
|
lino/utils/instantiator.py
CHANGED
@@ -8,7 +8,8 @@ used for generating database objects in :ref:`python fixtures <dpy>`.
|
|
8
8
|
from lino.core.utils import resolve_model, UnresolvedModel
|
9
9
|
from lino.core.utils import obj2str
|
10
10
|
from lino.utils import i2d # for backward compatibility of .py fixtures
|
11
|
-
from lino.core.fields import
|
11
|
+
from lino.core.fields import RemoteField
|
12
|
+
from lino.core.atomizer import make_remote_field
|
12
13
|
from lino.utils.choosers import make_converter
|
13
14
|
|
14
15
|
|
@@ -210,10 +211,11 @@ def create_and_get(model, **kw):
|
|
210
211
|
o = create(model, **kw)
|
211
212
|
return model.objects.get(pk=o.pk)
|
212
213
|
|
214
|
+
|
213
215
|
def make_if_needed(model, **values):
|
214
216
|
qs = model.objects.filter(**values)
|
215
217
|
if qs.count() == 1:
|
216
|
-
pass
|
218
|
+
pass # ok, nothing to do
|
217
219
|
elif qs.count() == 0:
|
218
220
|
return model(**values)
|
219
221
|
else:
|
lino/utils/report.py
CHANGED
@@ -10,8 +10,9 @@ from django.conf import settings
|
|
10
10
|
|
11
11
|
from lino.core.frames import Frame
|
12
12
|
from lino.core.utils import InstanceAction, VirtualRow
|
13
|
-
from lino.core.actions import ShowEmptyTable, Action
|
14
13
|
from lino.core import fields
|
14
|
+
from lino.core import layouts
|
15
|
+
from lino.core import actions
|
15
16
|
from lino.modlib.printing.mixins import Printable
|
16
17
|
from lino.modlib.printing.mixins import DirectPrintAction
|
17
18
|
from lino.utils import curry
|
@@ -83,7 +84,7 @@ class EmptyTableRow(VirtualRow, Printable):
|
|
83
84
|
# if name not in ('get_story'):
|
84
85
|
# raise Exception("20170910 %s" % name)
|
85
86
|
v = getattr(self._table, name)
|
86
|
-
if isinstance(v, Action):
|
87
|
+
if isinstance(v, actions.Action):
|
87
88
|
return InstanceAction(v, self._table, self, None)
|
88
89
|
# 20130525 dd.Report calls `get_story` on `self`, not on the `cls`
|
89
90
|
if callable(v):
|
@@ -105,7 +106,7 @@ class EmptyTable(Frame):
|
|
105
106
|
:class:`Report`.
|
106
107
|
"""
|
107
108
|
|
108
|
-
_detail_action_class = ShowEmptyTable
|
109
|
+
_detail_action_class = actions.ShowEmptyTable
|
109
110
|
|
110
111
|
# ~ debug_permissions = True
|
111
112
|
# ~ has_navigator = False
|
@@ -187,6 +188,7 @@ class Report(EmptyTable):
|
|
187
188
|
|
188
189
|
detail_layout = "body"
|
189
190
|
abstract = True
|
191
|
+
_params_layout_class = layouts.ParamsLayout
|
190
192
|
|
191
193
|
do_print = DirectPrintAction()
|
192
194
|
# go_button = ExplicitRefresh()
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.4
|
2
2
|
Name: lino
|
3
|
-
Version: 25.5.
|
3
|
+
Version: 25.5.3
|
4
4
|
Summary: A framework for writing desktop-like web applications using Django and ExtJS or React
|
5
5
|
Project-URL: Homepage, https://www.lino-framework.org
|
6
6
|
Project-URL: Repository, https://gitlab.com/lino-framework/lino
|