Welcome | Get started | Dive | Contribute | Topics | Reference | Changes | More
Content Management System (CMS)¶
The noi2 demo project shows Lino as a Content Management System.
It includes a page with usage examples of the [file]
and [gallery]
commands. To see it, say go noi2
followed by pm runserver
and then
point your browser to http://127.0.0.1:8000/p/9
>>> from lino_book.projects.noi2.startup import *
>>> mp = settings.SITE.plugins.memo.parser
>>> rt.models.uploads.Upload.objects.get(description__startswith="Murder")
Upload #13 ('Murder on the orient express cover')
>>> print(mp.parse("[file 13] Some text."))
...
<a href="/admin/#/api/uploads/Uploads/13" target="_blank"><img
src="/media/thumbs/uploads/2024/05/MurderontheOrientExpress.jpg"
title="Murder on the orient express cover"/></a> Some text.
>>> print(mp.parse('[file 13 title="My caption"] Some text.'))
...
<a href="/admin/#/api/uploads/Uploads/13" target="_blank"><img
src="/media/thumbs/uploads/2024/05/MurderontheOrientExpress.jpg"
title="My caption"/></a> Some text.
>>> print(mp.parse('[file 13 style="max-height: 20ex; max-width: 100%; float: right; padding: 4px;" title="My caption"] Some text.'))
...
<a href="/admin/#/api/uploads/Uploads/13" target="_blank"><img
src="/media/thumbs/uploads/2024/05/MurderontheOrientExpress.jpg"
style="max-height: 20ex; max-width: 100%; float: right; padding: 4px;" title="My
caption"/></a> Some text.
>>> print(mp.parse('[file 13 style="max-height: 20ex; max-width: 100%; float: right; padding: 4px;" title="My caption"] Some text.'))
...
<a href="/admin/#/api/uploads/Uploads/13" target="_blank"><img
src="/media/thumbs/uploads/2024/05/MurderontheOrientExpress.jpg"
style="max-height: 20ex; max-width: 100%; float: right; padding: 4px;" title="My
caption"/></a> Some text.
>>> print(mp.parse("[file 13 right|thumb|My caption] Some text."))
...
[ERROR Invalid format name 'right' (allowed names are ('thumb', 'tiny', 'wide',
'solo', 'duo', 'trio')). in '[file 13 right|thumb|My caption]' at position
0-32] Some text.
>>> print(mp.parse('[file 13 style="max-height: 20ex; max-width: 100%; float: right; padding: 4px;"] Some text.'))
...
<a href="/admin/#/api/uploads/Uploads/13" target="_blank"><img
src="/media/thumbs/uploads/2024/05/MurderontheOrientExpress.jpg"
style="max-height: 20ex; max-width: 100%; float: right; padding: 4px;" title="Murder
on the orient express cover"/></a> Some text.
The only difference between thumb
and tiny
is the size of the image. For
thumb
it has a height of 10em and for tiny
the height is 5em.
We don’t specify the width in order to let the browser compute it. We specify the height and not the width because we don’t care about whether the image is landscape or portrait.
>>> print(mp.parse('[file 13 style="max-height: 15ex; max-width: 100%; padding: 4px;" title="My caption"] Some text.'))
...
<a href="/admin/#/api/uploads/Uploads/13" target="_blank"><img
src="/media/thumbs/uploads/2024/05/MurderontheOrientExpress.jpg"
style="max-height: 15ex; max-width: 100%; padding: 4px;" title="My caption"/></a>
Some text.
>>> print(mp.parse('[file 13 style="max-height: 30ex; max-width: 100%; padding: 4px;" title="A wide image"] Some text.'))
...
<a href="/admin/#/api/uploads/Uploads/13" target="_blank"><img
src="/media/thumbs/uploads/2024/05/MurderontheOrientExpress.jpg"
style="max-height: 30ex; max-width: 100%; padding: 4px;" title="A wide image"/></a>
Some text.
Spaces around the pipe character don’t count:
>>> print(mp.parse('[file 13 style="max-height: 30ex; max-width: 100%; padding: 4px;" title="A wide image"] Some text.'))
...
<a href="/admin/#/api/uploads/Uploads/13" target="_blank"><img
src="/media/thumbs/uploads/2024/05/MurderontheOrientExpress.jpg"
style="max-height: 30ex; max-width: 100%; padding: 4px;" title="A wide image"/></a>
Some text.
The syntax is given by the
rstgen.sphinxconf.sigal_image.parse_image_spec()
function.
“image URL” versus “download URL”¶
>>> obj = uploads.Upload.objects.get(pk=13)
>>> mf = obj.get_media_file()
>>> print(mf.get_download_url())
/media/uploads/2024/05/MurderontheOrientExpress.jpg
>>> print(mf.get_image_url())
/media/thumbs/uploads/2024/05/MurderontheOrientExpress.jpg
>>> # obj = uploads.Upload.objects.get(pk=18)
>>> obj = uploads.Upload.objects.get(description__startswith="History")
>>> obj
Upload #20 ('History of PDF')
>>> mf = obj.get_media_file()
>>> print(mf.get_download_url())
/media/uploads/2024/05/History_of_PDF.pdf
>>> print(mf.get_image_url())
/media/thumbs/uploads/2024/05/History_of_PDF.pdf.png
Don’t read me¶
The following request had caused a traceback:
>>> res = test_client.get("/s/1")
>>> txt = beautiful_soup(res.content.decode()).text
>>> "Private collection by Luc Saffre" in txt
True
>>> res = test_client.get("/b/1")
But let’s extend above test to systematically loop over all publisher locations and GET each item:
>>> for loc, dv in dd.plugins.publisher.locations:
... for obj in dv.model.objects.all():
... url = "/{}/{}".format(loc, obj.pk)
... # print(dv, url)
... if obj.is_public():
... res = test_client.get(url)
... if res.status_code not in {200, 302}:
... print(f"{url} failed with {res.status_code}")
... # print(f"({res.content.decode()})")
... # elif res.status_code != 404:
... # print(f"{url} should return 404 but returned {res.status_code}")
>>> [obj.pk for obj in blogs.LatestEntries.create_request()]
[2, 3, 4, 5, 1]
>>> obj = blogs.Entry.objects.get(id=2)
>>> obj.publisher_tree
Tree #1 ('index')
>>> obj.publisher_tree.private
False