Welcome | Get started | Dive | Contribute | Topics | Reference | Changes | More

Content Management System (CMS)

The noi2 demo project shows Lino as a Content Management System.

>>> from lino_book.projects.noi2.startup import *
>>> mp = settings.SITE.plugins.memo.parser
>>> rt.show(uploads.ImageSizes)
========= ========= =========
 value     name      text
--------- --------- ---------
 tiny      tiny      Tiny
 small     small     Small
 default   default   Default
 big       big       Big
 huge      huge      Huge
 solo      solo      Solo
 duo       duo       Duo
 trio      trio      Trio
 quartet   quartet   Quartet
========= ========= =========
>>> rt.show(uploads.ImageFormats)
========== ========== ===============
 value      name       text
---------- ---------- ---------------
 inline     inline     Normal
 cool       cool       Cool
 right      right      Right-aligned
 left       left       Left-aligned
 wide       wide       Wide
 full       full       Full
 carousel   carousel   Carousel
 square     square     Square
========== ========== ===============
>>> rt.models.uploads.Upload.objects.get(description__startswith="Murder")
Upload #13 ('Murder on the orient express cover')
>>> print(mp.parse("[include upload:13] Some text."))
...
<img
src="/media/thumbs/uploads/2024/05/MurderontheOrientExpress.jpg"  title="Murder
on the orient express cover"
style="max-height:10em;max-width:10em;width:auto;height:auto;padding:1pt;"/>
Some text.
>>> print(mp.parse('[include upload:13 My caption] Some text.'))
...
<img
src="/media/thumbs/uploads/2024/05/MurderontheOrientExpress.jpg"  title="My
caption"
style="max-height:10em;max-width:10em;width:auto;height:auto;padding:1pt;"/>
Some text.
>>> print(mp.parse('[include upload:13 wide|] Some text.'))
...
<img
src="/media/thumbs/uploads/2024/05/MurderontheOrientExpress.jpg"  title="Murder
on the orient express cover"
style="max-width:100%;height:auto;width:auto;max-height:15em;padding:2pt;"/>
Some text.
>>> print(mp.parse('[include upload:13 wide|My caption] Some text.'))
...
<img
src="/media/thumbs/uploads/2024/05/MurderontheOrientExpress.jpg"  title="My
caption"
style="max-width:100%;height:auto;width:auto;max-height:15em;padding:2pt;"/>
Some text.

Spaces around the pipe character don’t count:

>>> print(mp.parse('[include upload:13 wide | My caption] Some text.'))
...
<img
src="/media/thumbs/uploads/2024/05/MurderontheOrientExpress.jpg"  title="My
caption"
style="max-width:100%;height:auto;width:auto;max-height:15em;padding:2pt;"/>
Some text.

“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("/src/1")
>>> txt = beautiful_soup(res.content.decode()).text
>>> "Private collection by Luc Saffre" in txt
True
>>> res = test_client.get("/b/1")

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.create_request():
...         url = "/{}/{}".format(loc, obj.pk)
...         # print(dv, url)
...         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()})")
>>> [obj.pk for obj in blogs.LatestEntries.create_request()]
[2, 3, 4, 5, 1]
>>> obj = blogs.Entry.objects.get(id=2)
>>> obj.get_root_page()
Page #1 ('-Home')

Looking up upload files

You usually refer to database row by its primary key, which usually is an integer number. But for upload files you can optionally specify their filename or their volume_name:library_filename.

For example:

>>> ar= rt.login("robin")
>>> ar = uploads.Uploads.create_request(parent=ar)
>>> obj = ar.get_row_by_pk("1")
>>> obj
Upload #1 ('2021 IMG 20210330 151858.jpg')
>>> obj.volume
Volume #2 ('photos')
>>> obj.library_file
'2021/IMG_20210330_151858.jpg'
>>> ar.get_row_by_pk("photos:2021/IMG_20210330_151858.jpg")
Upload #1 ('2021 IMG 20210330 151858.jpg')
>>> obj = ar.get_row_by_pk("15")
>>> obj
Upload #15 ('And then there were none')
>>> obj.file
<FieldFile: uploads/2024/05/AndThenThereWereNone.jpg>
>>> ar.get_row_by_pk("uploads/2024/05/AndThenThereWereNone.jpg")
Upload #15 ('And then there were none')