{"version":"https://jsonfeed.org/version/1.1","title":"Blog  Fundor333","description":"  Blog  Fundor333","home_page_url":"https://fundor333.com/","feed_url":"https://fundor333.com/post/index.json","language":"en","icon":"https://fundor333.com/apple-touch-icon.png","favicon":"https://fundor333.com/apple-touch-icon.png","authors":[{"name":"Fundor333","url":"https://fundor333.com","avatar":"https://fundor333.com/img/logo.png"}],"items":[{"title":"Who Knows That I Blog ","date_published":"2026-05-23T12:50:49+02:00","date_modified":"2026-07-16T22:49:21+02:00","id":"https://fundor333.com/post/2026/who-knows-that-i-blog-/","url":"https://fundor333.com/post/2026/who-knows-that-i-blog-/","tags":["blog","blogging","rant"],"content_html":"\u003cblockquote\u003e\n\u003cp\u003eQuestion for the audience: Do you tell people you blog?\u003c/p\u003e\n\u003c/blockquote\u003e\n\u003cp\u003eYes\u0026hellip; No\u0026hellip; It depend.\nIt is not a thing I talk about my blog in my every day life. And I have more than one blog so\u0026hellip;\u003c/p\u003e\n\u003ch2 id=\"so-i-tell-people-about-my-blog\" class=\"no-underline \"\u003e\n  \u003ca href=\"#so-i-tell-people-about-my-blog\"\u003e\n    \u003ci class=\"fa-whiteboard fa-semibold fa-angle-right\"\u003e\u003c/i\u003e\n    So I tell people about my blog?\n  \u003c/a\u003e\n  \u003c/h2\u003e\n\u003cp\u003eYes I tell but not unprompted. I told people while talking about the argument of my blog, like if I have a post about what we are talking or if the topic of the blog can be usefull for the discussion.\u003c/p\u003e\n\u003ch2 id=\"am-i-anonymous-when-blogging\" class=\"no-underline \"\u003e\n  \u003ca href=\"#am-i-anonymous-when-blogging\"\u003e\n    \u003ci class=\"fa-whiteboard fa-semibold fa-angle-right\"\u003e\u003c/i\u003e\n    Am I anonymous when blogging?\n  \u003c/a\u003e\n  \u003c/h2\u003e\n\u003cblockquote\u003e\n\u003cp\u003eI appreciate some people like to be anonymous when blogging. That\u0026rsquo;s their choice. I am an open book. You can ask me anything and I will reply honestly, as long as it conforms to my town-square rule.\u003c/p\u003e\n\u003c/blockquote\u003e\n\u003cp\u003eIn my case is not so black and white. This blog url and title is Fundor333. This is my online alias. If you find somewhere fundor333 you find one of my account. So I am well know as Fundor333. So I am \u0026ldquo;anonymous\u0026rdquo; when I blog (as I don\u0026rsquo;t use my real name) but I don\u0026rsquo;t hide my alias.\u003c/p\u003e\n\u003ch2 id=\"conclusion\" class=\"no-underline \"\u003e\n  \u003ca href=\"#conclusion\"\u003e\n    \u003ci class=\"fa-whiteboard fa-semibold fa-angle-right\"\u003e\u003c/i\u003e\n    Conclusion\n  \u003c/a\u003e\n  \u003c/h2\u003e\n\u003cp\u003eSo I tell people I blog but not at random and I don\u0026rsquo;t hide my blog. But is not one of my opening line when talking with someone.\u003c/p\u003e\n","content_text":" Question for the audience: Do you tell people you blog?\nYes\u0026hellip; No\u0026hellip; It depend. It is not a thing I talk about my blog in my every day life. And I have more than one blog so\u0026hellip;\nSo I tell people about my blog? Yes I tell but not unprompted. I told people while talking about the argument of my blog, like if I have a post about what we are talking or if the topic of the blog can be usefull for the discussion.\nAm I anonymous when blogging? I appreciate some people like to be anonymous when blogging. That\u0026rsquo;s their choice. I am an open book. You can ask me anything and I will reply honestly, as long as it conforms to my town-square rule.\nIn my case is not so black and white. This blog url and title is Fundor333. This is my online alias. If you find somewhere fundor333 you find one of my account. So I am well know as Fundor333. So I am \u0026ldquo;anonymous\u0026rdquo; when I blog (as I don\u0026rsquo;t use my real name) but I don\u0026rsquo;t hide my alias.\nConclusion So I tell people I blog but not at random and I don\u0026rsquo;t hide my blog. But is not one of my opening line when talking with someone.\n","image":"https://fundor333.com/post/2026/who-knows-that-i-blog-/cover.jpg","banner_image":"https://fundor333.com/post/2026/who-knows-that-i-blog-/cover.jpg"},{"title":"Hacking My Kobo with KOReader","date_published":"2026-04-13T12:10:12+02:00","date_modified":"2026-07-16T22:49:21+02:00","id":"https://fundor333.com/post/2026/hacking-my-kobo/","url":"https://fundor333.com/post/2026/hacking-my-kobo/","tags":["kobo","koreader","ebook","ereader","kindle","tinkering","Hacking stuffs"],"content_html":"\u003cp\u003eA long long time ago I start using a EBook Reader, the first Kindle PaperWhite (2012) and I never stop using EReader.\u003c/p\u003e\n\u003cp\u003eThe last one I own is a Kobo Clara Colour, this one.\u003c/p\u003e\n\u003cp\u003e\u003cimg  class=\"center-img u-photo \"  src=\"kobo.jpg\" alt=\"Kobo Clara Colour\"\u003e\u003c/p\u003e\n\u003cp\u003eI love it and the fact I can read in color comics, manga, web comics and graphic novel everywhere is a plus.\u003c/p\u003e\n\u003cp\u003eBut more and more I use Ebook Readers more and more I want to customize it. Like I have in the pic.\u003c/p\u003e\n\u003ch2 id=\"what-can-i-do-what-do-i-want-to-do-with-my-kobo\" class=\"no-underline \"\u003e\n  \u003ca href=\"#what-can-i-do-what-do-i-want-to-do-with-my-kobo\"\u003e\n    \u003ci class=\"fa-whiteboard fa-semibold fa-angle-right\"\u003e\u003c/i\u003e\n    What can I do? What do I want to do with my Kobo?\n  \u003c/a\u003e\n  \u003c/h2\u003e\n\u003cp\u003eI have some task and prerequisite for my Ebook Reader so I check an Hack which resolve all:\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e\u003cem\u003eI need to sync with Calibre\u003c/em\u003e: I have an huge Calibre Library and I want to keep it\u003c/li\u003e\n\u003cli\u003e\u003cem\u003eChange the default cover\u003c/em\u003e: I want my cover, not the default covers\u003c/li\u003e\n\u003cli\u003e\u003cem\u003eIntegration with GoodRead or Hardcover\u003c/em\u003e: I want to sync with GoodRead or Hardover the data from my ebook reader.\u003c/li\u003e\n\u003cli\u003e\u003cem\u003eOpen Source software\u003c/em\u003e: I want to use an Open Source project because I can code so if i need something I can code it.\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eSo I did some research on the web and find KoReader\u003csup id=\"fnref:1\"\u003e\u003ca href=\"#fn:1\" class=\"footnote-ref\" role=\"doc-noteref\"\u003e1\u003c/a\u003e\u003c/sup\u003e.\u003c/p\u003e\n\u003cp\u003eIt is a software which, after installing on the ereader, it add support for plugins and custom covers\u0026hellip; So I start with it.\u003c/p\u003e\n\u003ch2 id=\"how-to-install-it\" class=\"no-underline \"\u003e\n  \u003ca href=\"#how-to-install-it\"\u003e\n    \u003ci class=\"fa-whiteboard fa-semibold fa-angle-right\"\u003e\u003c/i\u003e\n    How to install it?\n  \u003c/a\u003e\n  \u003c/h2\u003e\n\u003cp\u003eSearching for the wiki page for starting/installing I found some tread about the installation\u003csup id=\"fnref:2\"\u003e\u003ca href=\"#fn:2\" class=\"footnote-ref\" role=\"doc-noteref\"\u003e2\u003c/a\u003e\u003c/sup\u003e and I follow them. Here I rewrite all the steps with newer link for the stuff needed and rewrote some step because the two treads aren\u0026rsquo;t clear enough for me.\u003c/p\u003e\n\u003col start=\"0\"\u003e\n\u003cli\u003eCheck if your device support the software\u003c/li\u003e\n\u003cli\u003eDownload the last version of what you want to install. In this case \u003ca class=\"a-post interlink-script\" href=\"https://github.com/koreader/koreader/releases\"   target=\"_blank\"\u003eLast version of KoReader\u0026nbsp;\u0026nbsp;\u003ci class=\"fa-whiteboard fa-semibold fa-link\"\u003e\u003c/i\u003e\u003c/a\u003e\n is what I want and support on my device\u003c/li\u003e\n\u003cli\u003ePut all the zip/archive you download in a new directory without unarchive anything\u003c/li\u003e\n\u003cli\u003eDownload the installer script (\u003ca class=\"a-post interlink-script\" href=\"https://raw.githubusercontent.com/NiLuJe/kfmon/refs/heads/master/tools/install.ps1\"   target=\"_blank\"\u003eWindows version\u0026nbsp;\u0026nbsp;\u003ci class=\"fa-whiteboard fa-semibold fa-link\"\u003e\u003c/i\u003e\u003c/a\u003e\n, \u003ca class=\"a-post interlink-script\" href=\"https://raw.githubusercontent.com/NiLuJe/kfmon/refs/heads/master/tools/install.sh\"   target=\"_blank\"\u003eMac version\u0026nbsp;\u0026nbsp;\u003ci class=\"fa-whiteboard fa-semibold fa-link\"\u003e\u003c/i\u003e\u003c/a\u003e\n, \u003ca class=\"a-post interlink-script\" href=\"https://raw.githubusercontent.com/NiLuJe/kfmon/refs/heads/master/tools/install.sh\"   target=\"_blank\"\u003eLinux version\u0026nbsp;\u0026nbsp;\u003ci class=\"fa-whiteboard fa-semibold fa-link\"\u003e\u003c/i\u003e\u003c/a\u003e\n) and put in the same directory as all the other stuff downloaded in 2\u003c/li\u003e\n\u003cli\u003ePlug in the Kobo and check if you can read and write file inside it\u003c/li\u003e\n\u003cli\u003eIf needed fix the permission for execute the installer download at step 3\u003c/li\u003e\n\u003cli\u003eFollow the on-screen instruction and close the terminal when done\u003c/li\u003e\n\u003cli\u003eSafely eject your Kobo, watch it process (it look like in some way a glitching and crashing device but it need to look like that) and waite for the end of the reboot.\u003c/li\u003e\n\u003c/ol\u003e\n\u003cp\u003eIf you have doubt, here is a screenshot of what the terminal look like in step 6 if you did all in the right way.\u003c/p\u003e\n\u003cp\u003e\u003cimg  class=\"center-img u-photo \"  src=\"terminal.png\" alt=\"teminal code\"\u003e\u003c/p\u003e\n\u003cp\u003eAfter the reboot of the device I start to add the plugins for some customization\u003c/p\u003e\n\u003ch2 id=\"adding-stuff\" class=\"no-underline \"\u003e\n  \u003ca href=\"#adding-stuff\"\u003e\n    \u003ci class=\"fa-whiteboard fa-semibold fa-angle-right\"\u003e\u003c/i\u003e\n    Adding stuff\n  \u003c/a\u003e\n  \u003c/h2\u003e\n\u003cp\u003eI add some KoReader Plugin, which you need to install.\u003c/p\u003e\n\u003cp\u003eAll the plugin are installed in the same way:\u003c/p\u003e\n\u003col\u003e\n\u003cli\u003eYou need to download the plugin\u003c/li\u003e\n\u003cli\u003eYou need to extract the \u003cem\u003eplugin_name\u003c/em\u003e.koplugin\u003c/li\u003e\n\u003cli\u003eEdit any config file for the plugin (only some plugin required this)\u003c/li\u003e\n\u003cli\u003ePut the koplugin folder in the path for the device (in Kobo case is \u003cstrong\u003e.adds/koreader/plugins\u003c/strong\u003e)\u003c/li\u003e\n\u003cli\u003eRestart KOReader\u003c/li\u003e\n\u003c/ol\u003e\n\u003cul\u003e\n\u003cli\u003e\u003ca class=\"a-post interlink-script\" href=\"https://github.com/joshuacant/ProjectTitle\"   target=\"_blank\"\u003eProjectTitle KOReader\u0026nbsp;\u0026nbsp;\u003ci class=\"fa-whiteboard fa-semibold fa-link\"\u003e\u003c/i\u003e\u003c/a\u003e\n for a better looking homepage for KOReader (needed)\u003c/li\u003e\n\u003cli\u003e\u003ca class=\"a-post interlink-script\" href=\"https://github.com/pxlflux/customisablesleepscreen.koplugin\"   target=\"_blank\"\u003eCustomisable Sleep Screen\u0026nbsp;\u0026nbsp;\u003ci class=\"fa-whiteboard fa-semibold fa-link\"\u003e\u003c/i\u003e\u003c/a\u003e\n for having a customisable sleep screen (as the name of the plugin say)\u003c/li\u003e\n\u003cli\u003e\u003ca class=\"a-post interlink-script\" href=\"https://github.com/Billiam/hardcoverapp.koplugin\"   target=\"_blank\"\u003eHardcover.app for KOReader\u0026nbsp;\u0026nbsp;\u003ci class=\"fa-whiteboard fa-semibold fa-link\"\u003e\u003c/i\u003e\u003c/a\u003e\n for sync the data with my \u003ca class=\"a-post interlink-script\" href=\"https://hardcover.app/\"   target=\"_blank\"\u003eHardCover\u0026nbsp;\u0026nbsp;\u003ci class=\"fa-whiteboard fa-semibold fa-link\"\u003e\u003c/i\u003e\u003c/a\u003e\n account\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e\u003cimg  class=\"center-img u-photo \"  src=\"kobo-complete.jpg\" alt=\"Kobo Clara Colour\"\u003e\u003c/p\u003e\n\u003cp\u003eI also create some image with trasparent background for having this type of cover, where you can see under the sleep-screen what are you reading.\u003c/p\u003e\n\u003ch2 id=\"and-i-did-more\" class=\"no-underline \"\u003e\n  \u003ca href=\"#and-i-did-more\"\u003e\n    \u003ci class=\"fa-whiteboard fa-semibold fa-angle-right\"\u003e\u003c/i\u003e\n    And I did more\n  \u003c/a\u003e\n  \u003c/h2\u003e\n\u003cp\u003eI did a lot of configuration inside of KOReader for this or that component and I don\u0026rsquo;t want to lose all. So, after asking Reddit \u003ca class=\"a-post interlink-script\" href=\"https://www.reddit.com/r/koreader/comments/1sgk3zc/comment/of5k8qe/\"   target=\"_blank\"\u003eHow can I make a backup?\u0026nbsp;\u0026nbsp;\u003ci class=\"fa-whiteboard fa-semibold fa-link\"\u003e\u003c/i\u003e\u003c/a\u003e\n and make this script.\u003c/p\u003e\n\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;\"\u003e\u003ccode class=\"language-python\" data-lang=\"python\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e#!/usr/bin/env python3\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#f92672\"\u003eimport\u003c/span\u003e os\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#f92672\"\u003eimport\u003c/span\u003e sys\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#f92672\"\u003eimport\u003c/span\u003e shutil\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#f92672\"\u003efrom\u003c/span\u003e datetime \u003cspan style=\"color:#f92672\"\u003eimport\u003c/span\u003e datetime\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eKOREADER_DIR \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;.adds\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eBACKUP_DESTINATION \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;~/BackUp/KoReader\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eBACKUP_FILENAME \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;koreader_backup_\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e{date}\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e.zip\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#66d9ef\"\u003edef\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003efind_kobo_device\u003c/span\u003e():\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;\u0026#34;\u0026#34;Find the path to the Kobo\u0026#34;\u0026#34;\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    volumes_path \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;/Volumes\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003eif\u003c/span\u003e os\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003epath\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003eexists(volumes_path):\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#66d9ef\"\u003efor\u003c/span\u003e entry \u003cspan style=\"color:#f92672\"\u003ein\u003c/span\u003e os\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003elistdir(volumes_path):\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            full_path \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e os\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003epath\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003ejoin(volumes_path, entry)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#66d9ef\"\u003eif\u003c/span\u003e os\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003epath\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003eisdir(full_path):\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                \u003cspan style=\"color:#66d9ef\"\u003etry\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                    contents \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e os\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003elistdir(full_path)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                    \u003cspan style=\"color:#66d9ef\"\u003eif\u003c/span\u003e \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;.kobo\u0026#34;\u003c/span\u003e \u003cspan style=\"color:#f92672\"\u003ein\u003c/span\u003e contents:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                        \u003cspan style=\"color:#66d9ef\"\u003ereturn\u003c/span\u003e full_path\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                \u003cspan style=\"color:#66d9ef\"\u003eexcept\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003ePermissionError\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                    \u003cspan style=\"color:#66d9ef\"\u003econtinue\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003ereturn\u003c/span\u003e \u003cspan style=\"color:#66d9ef\"\u003eNone\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#66d9ef\"\u003edef\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003eget_koreader_path\u003c/span\u003e(kobo_path):\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;\u0026#34;\u0026#34;Returns the path to KoReader on the Kobo.\u0026#34;\u0026#34;\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003ereturn\u003c/span\u003e os\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003epath\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003ejoin(kobo_path, KOREADER_DIR)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#66d9ef\"\u003edef\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003ecreate_backup\u003c/span\u003e(source_path, backup_destination):\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;\u0026#34;\u0026#34;Creates a zip backup of KoReader.\u0026#34;\u0026#34;\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003eif\u003c/span\u003e \u003cspan style=\"color:#f92672\"\u003enot\u003c/span\u003e os\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003epath\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003eexists(source_path):\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        print(\u003cspan style=\"color:#e6db74\"\u003ef\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;Error: KoReader not found in \u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e{\u003c/span\u003esource_path\u003cspan style=\"color:#e6db74\"\u003e}\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#66d9ef\"\u003ereturn\u003c/span\u003e \u003cspan style=\"color:#66d9ef\"\u003eFalse\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    print(\u003cspan style=\"color:#e6db74\"\u003ef\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;Creating backup from: \u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e{\u003c/span\u003esource_path\u003cspan style=\"color:#e6db74\"\u003e}\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    date_str \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e datetime\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003enow()\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003estrftime(\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;%Y%m\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e%d\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e_%H%M%S\u0026#34;\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    backup_filename \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e BACKUP_FILENAME\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003eformat(date\u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003edate_str)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    backup_path \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e os\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003epath\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003ejoin(backup_destination, backup_filename)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    print(\u003cspan style=\"color:#e6db74\"\u003ef\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;Backup to: \u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e{\u003c/span\u003ebackup_path\u003cspan style=\"color:#e6db74\"\u003e}\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003etry\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        shutil\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003emake_archive(\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            backup_path\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003ereplace(\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;.zip\u0026#34;\u003c/span\u003e, \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;\u0026#34;\u003c/span\u003e), \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;zip\u0026#34;\u003c/span\u003e, root_dir\u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003esource_path, base_dir\u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;.\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        )\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        print(\u003cspan style=\"color:#e6db74\"\u003ef\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;Backup created: \u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e{\u003c/span\u003ebackup_path\u003cspan style=\"color:#e6db74\"\u003e}\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#66d9ef\"\u003ereturn\u003c/span\u003e \u003cspan style=\"color:#66d9ef\"\u003eTrue\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003eexcept\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003eException\u003c/span\u003e \u003cspan style=\"color:#66d9ef\"\u003eas\u003c/span\u003e e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        print(\u003cspan style=\"color:#e6db74\"\u003ef\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;Error during backup creation: \u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e{\u003c/span\u003ee\u003cspan style=\"color:#e6db74\"\u003e}\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#66d9ef\"\u003ereturn\u003c/span\u003e \u003cspan style=\"color:#66d9ef\"\u003eFalse\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#66d9ef\"\u003edef\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003emain\u003c/span\u003e():\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    kobo_path \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e find_kobo_device()\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003eif\u003c/span\u003e \u003cspan style=\"color:#f92672\"\u003enot\u003c/span\u003e kobo_path:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        print(\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;Kobo not found. Connect the device and try again.\u0026#34;\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        sys\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003eexit(\u003cspan style=\"color:#ae81ff\"\u003e1\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    print(\u003cspan style=\"color:#e6db74\"\u003ef\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;Kobo found at: \u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e{\u003c/span\u003ekobo_path\u003cspan style=\"color:#e6db74\"\u003e}\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    koreader_path \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e get_koreader_path(kobo_path)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    backup_destination \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e os\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003epath\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003eexpanduser(BACKUP_DESTINATION)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    os\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003emakedirs(backup_destination, exist_ok\u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#66d9ef\"\u003eTrue\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    success \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e create_backup(koreader_path, backup_destination)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003eif\u003c/span\u003e success:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        print(\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;Backup completed successfully!\u0026#34;\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003eelse\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        print(\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;Backup failed.\u0026#34;\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        sys\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003eexit(\u003cspan style=\"color:#ae81ff\"\u003e1\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#66d9ef\"\u003eif\u003c/span\u003e __name__ \u003cspan style=\"color:#f92672\"\u003e==\u003c/span\u003e \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;__main__\u0026#34;\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    main()\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003eThis Python script is run every time I connect to my computer with the Kobo and copy the \u003cstrong\u003e.adds\u003c/strong\u003e in a specific path with a new folder tagged with the timestamp.\u003c/p\u003e\n\u003cp\u003eSo if I break my KOReader config, I can reset all and copy the \u003cstrong\u003e.adds\u003c/strong\u003e for restore the KOReader.\u003c/p\u003e\n\u003ch2 id=\"conclusion\" class=\"no-underline \"\u003e\n  \u003ca href=\"#conclusion\"\u003e\n    \u003ci class=\"fa-whiteboard fa-semibold fa-angle-right\"\u003e\u003c/i\u003e\n    Conclusion\n  \u003c/a\u003e\n  \u003c/h2\u003e\n\u003cp\u003eFor now this is what I did with my Kobo but I am thinking new stuff so if I will do something new I will write about it.\u003c/p\u003e\n\u003cdiv class=\"footnotes\" role=\"doc-endnotes\"\u003e\n\u003chr\u003e\n\u003col\u003e\n\u003cli id=\"fn:1\"\u003e\n\u003cp\u003e\u003ca class=\"a-post interlink-script\" href=\"https://github.com/koreader/koreader\"   target=\"_blank\"\u003eKoReader\u0026nbsp;\u0026nbsp;\u003ci class=\"fa-whiteboard fa-semibold fa-link\"\u003e\u003c/i\u003e\u003c/a\u003e\n Github official page\u0026#160;\u003ca href=\"#fnref:1\" class=\"footnote-backref\" role=\"doc-backlink\"\u003e\u0026#x21a9;\u0026#xfe0e;\u003c/a\u003e\u003c/p\u003e\n\u003c/li\u003e\n\u003cli id=\"fn:2\"\u003e\n\u003cp\u003e\u003ca class=\"a-post interlink-script\" href=\"https://www.mobileread.com/forums/showpost.php?p=3797095\u0026amp;postcount=1\"   target=\"_blank\"\u003eInstall Tread part1\u0026nbsp;\u0026nbsp;\u003ci class=\"fa-whiteboard fa-semibold fa-link\"\u003e\u003c/i\u003e\u003c/a\u003e\n and \u003ca class=\"a-post interlink-script\" href=\"https://www.mobileread.com/forums/showpost.php?p=3797096\u0026amp;postcount=2\"   target=\"_blank\"\u003eInstall Tread part2\u0026nbsp;\u0026nbsp;\u003ci class=\"fa-whiteboard fa-semibold fa-link\"\u003e\u003c/i\u003e\u003c/a\u003e\n\u0026#160;\u003ca href=\"#fnref:2\" class=\"footnote-backref\" role=\"doc-backlink\"\u003e\u0026#x21a9;\u0026#xfe0e;\u003c/a\u003e\u003c/p\u003e\n\u003c/li\u003e\n\u003c/ol\u003e\n\u003c/div\u003e\n","content_text":"A long long time ago I start using a EBook Reader, the first Kindle PaperWhite (2012) and I never stop using EReader.\nThe last one I own is a Kobo Clara Colour, this one.\nI love it and the fact I can read in color comics, manga, web comics and graphic novel everywhere is a plus.\nBut more and more I use Ebook Readers more and more I want to customize it. Like I have in the pic.\nWhat can I do? What do I want to do with my Kobo? I have some task and prerequisite for my Ebook Reader so I check an Hack which resolve all:\nI need to sync with Calibre: I have an huge Calibre Library and I want to keep it Change the default cover: I want my cover, not the default covers Integration with GoodRead or Hardcover: I want to sync with GoodRead or Hardover the data from my ebook reader. Open Source software: I want to use an Open Source project because I can code so if i need something I can code it. So I did some research on the web and find KoReader1.\nIt is a software which, after installing on the ereader, it add support for plugins and custom covers\u0026hellip; So I start with it.\nHow to install it? Searching for the wiki page for starting/installing I found some tread about the installation2 and I follow them. Here I rewrite all the steps with newer link for the stuff needed and rewrote some step because the two treads aren\u0026rsquo;t clear enough for me.\nCheck if your device support the software Download the last version of what you want to install. In this case Last version of KoReader\u0026nbsp;\u0026nbsp; is what I want and support on my device Put all the zip/archive you download in a new directory without unarchive anything Download the installer script (Windows version\u0026nbsp;\u0026nbsp; , Mac version\u0026nbsp;\u0026nbsp; , Linux version\u0026nbsp;\u0026nbsp; ) and put in the same directory as all the other stuff downloaded in 2 Plug in the Kobo and check if you can read and write file inside it If needed fix the permission for execute the installer download at step 3 Follow the on-screen instruction and close the terminal when done Safely eject your Kobo, watch it process (it look like in some way a glitching and crashing device but it need to look like that) and waite for the end of the reboot. If you have doubt, here is a screenshot of what the terminal look like in step 6 if you did all in the right way.\nAfter the reboot of the device I start to add the plugins for some customization\nAdding stuff I add some KoReader Plugin, which you need to install.\nAll the plugin are installed in the same way:\nYou need to download the plugin You need to extract the plugin_name.koplugin Edit any config file for the plugin (only some plugin required this) Put the koplugin folder in the path for the device (in Kobo case is .adds/koreader/plugins) Restart KOReader ProjectTitle KOReader\u0026nbsp;\u0026nbsp; for a better looking homepage for KOReader (needed) Customisable Sleep Screen\u0026nbsp;\u0026nbsp; for having a customisable sleep screen (as the name of the plugin say) Hardcover.app for KOReader\u0026nbsp;\u0026nbsp; for sync the data with my HardCover\u0026nbsp;\u0026nbsp; account I also create some image with trasparent background for having this type of cover, where you can see under the sleep-screen what are you reading.\nAnd I did more I did a lot of configuration inside of KOReader for this or that component and I don\u0026rsquo;t want to lose all. So, after asking Reddit How can I make a backup?\u0026nbsp;\u0026nbsp; and make this script.\n#!/usr/bin/env python3 import os import sys import shutil from datetime import datetime KOREADER_DIR = \u0026#34;.adds\u0026#34; BACKUP_DESTINATION = \u0026#34;~/BackUp/KoReader\u0026#34; BACKUP_FILENAME = \u0026#34;koreader_backup_{date}.zip\u0026#34; def find_kobo_device(): \u0026#34;\u0026#34;\u0026#34;Find the path to the Kobo\u0026#34;\u0026#34;\u0026#34; volumes_path = \u0026#34;/Volumes\u0026#34; if os.path.exists(volumes_path): for entry in os.listdir(volumes_path): full_path = os.path.join(volumes_path, entry) if os.path.isdir(full_path): try: contents = os.listdir(full_path) if \u0026#34;.kobo\u0026#34; in contents: return full_path except PermissionError: continue return None def get_koreader_path(kobo_path): \u0026#34;\u0026#34;\u0026#34;Returns the path to KoReader on the Kobo.\u0026#34;\u0026#34;\u0026#34; return os.path.join(kobo_path, KOREADER_DIR) def create_backup(source_path, backup_destination): \u0026#34;\u0026#34;\u0026#34;Creates a zip backup of KoReader.\u0026#34;\u0026#34;\u0026#34; if not os.path.exists(source_path): print(f\u0026#34;Error: KoReader not found in {source_path}\u0026#34;) return False print(f\u0026#34;Creating backup from: {source_path}\u0026#34;) date_str = datetime.now().strftime(\u0026#34;%Y%m%d_%H%M%S\u0026#34;) backup_filename = BACKUP_FILENAME.format(date=date_str) backup_path = os.path.join(backup_destination, backup_filename) print(f\u0026#34;Backup to: {backup_path}\u0026#34;) try: shutil.make_archive( backup_path.replace(\u0026#34;.zip\u0026#34;, \u0026#34;\u0026#34;), \u0026#34;zip\u0026#34;, root_dir=source_path, base_dir=\u0026#34;.\u0026#34; ) print(f\u0026#34;Backup created: {backup_path}\u0026#34;) return True except Exception as e: print(f\u0026#34;Error during backup creation: {e}\u0026#34;) return False def main(): kobo_path = find_kobo_device() if not kobo_path: print(\u0026#34;Kobo not found. Connect the device and try again.\u0026#34;) sys.exit(1) print(f\u0026#34;Kobo found at: {kobo_path}\u0026#34;) koreader_path = get_koreader_path(kobo_path) backup_destination = os.path.expanduser(BACKUP_DESTINATION) os.makedirs(backup_destination, exist_ok=True) success = create_backup(koreader_path, backup_destination) if success: print(\u0026#34;Backup completed successfully!\u0026#34;) else: print(\u0026#34;Backup failed.\u0026#34;) sys.exit(1) if __name__ == \u0026#34;__main__\u0026#34;: main()This Python script is run every time I connect to my computer with the Kobo and copy the .adds in a specific path with a new folder tagged with the timestamp.\nSo if I break my KOReader config, I can reset all and copy the .adds for restore the KOReader.\nConclusion For now this is what I did with my Kobo but I am thinking new stuff so if I will do something new I will write about it.\nKoReader\u0026nbsp;\u0026nbsp; Github official page\u0026#160;\u0026#x21a9;\u0026#xfe0e;\nInstall Tread part1\u0026nbsp;\u0026nbsp; and Install Tread part2\u0026nbsp;\u0026nbsp; \u0026#160;\u0026#x21a9;\u0026#xfe0e;\n","image":"https://fundor333.com/post/2026/hacking-my-kobo/cover.png","banner_image":"https://fundor333.com/post/2026/hacking-my-kobo/cover.png"},{"title":"Django Table, Filter and Export With Htmx","date_published":"2026-04-03T08:21:34+02:00","date_modified":"2026-07-16T22:49:21+02:00","id":"https://fundor333.com/post/2026/django-table-filter-export-with-htmx/","url":"https://fundor333.com/post/2026/django-table-filter-export-with-htmx/","tags":["django","export","htmx","django-table2","django-filters","django-filters","dev","fingerfood"],"content_html":"\u003cp\u003eSome time ago I wrote a \u003ca class=\"a-post interlink-script\" href=\"/post/2026/htmx-django-and-django-table2/\"  \u003eblog post\u003c/a\u003e\n about Htmx and Django-table2 and all went well\u0026hellip;\u003c/p\u003e\n\u003cp\u003e\u003cimg  class=\"center-img u-photo \"  src=\"soso.gif\" alt=\"So So\"\u003e\u003c/p\u003e\n\u003cp\u003eNo he didn\u0026rsquo;t work as I wanted so I did some editing of the code here and there.\u003c/p\u003e\n\u003ch2 id=\"the-old-one\" class=\"no-underline \"\u003e\n  \u003ca href=\"#the-old-one\"\u003e\n    \u003ci class=\"fa-whiteboard fa-semibold fa-angle-right\"\u003e\u003c/i\u003e\n    The old one\n  \u003c/a\u003e\n  \u003c/h2\u003e\n\u003cp\u003eWe start with the code I didn\u0026rsquo;t change:\u003c/p\u003e\n\u003cp\u003eFirst the model\u003c/p\u003e\n\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;\"\u003e\u003ccode class=\"language-python\" data-lang=\"python\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# blog/model.py\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#66d9ef\"\u003eclass\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003ePost\u003c/span\u003e(models\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003eModel):\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    title \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e models\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003eCharField(max_length\u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#ae81ff\"\u003e400\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    slug \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e models\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003eSlugField(max_length\u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#ae81ff\"\u003e400\u003c/span\u003e, unique\u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#66d9ef\"\u003eTrue\u003c/span\u003e, blank\u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#66d9ef\"\u003eTrue\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    content \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e models\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003eTextAreaField()\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    date \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e models\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003eDateTimeField(auto_now_add\u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#66d9ef\"\u003eTrue\u003c/span\u003e)\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003eThe table\u003c/p\u003e\n\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;\"\u003e\u003ccode class=\"language-python\" data-lang=\"python\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# blog/tables.py\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#f92672\"\u003eimport\u003c/span\u003e django_tables2 \u003cspan style=\"color:#66d9ef\"\u003eas\u003c/span\u003e tables\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#f92672\"\u003efrom\u003c/span\u003e blog.models \u003cspan style=\"color:#f92672\"\u003eimport\u003c/span\u003e Post\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#66d9ef\"\u003eclass\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003ePostTable\u003c/span\u003e(tables\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003eTable):\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003eclass\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003eMeta\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        model \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e Post\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        order_by \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e (\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;-date\u0026#34;\u003c/span\u003e, \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;title\u0026#34;\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        fields \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e [\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;date\u0026#34;\u003c/span\u003e, \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;title\u0026#34;\u003c/span\u003e, \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;slug\u0026#34;\u003c/span\u003e]\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003eThis two fragment are perfect as is so I didn\u0026rsquo;t touch them. But all the other part I reworked as I needed.\u003c/p\u003e\n\u003ch2 id=\"the-new-parts\" class=\"no-underline \"\u003e\n  \u003ca href=\"#the-new-parts\"\u003e\n    \u003ci class=\"fa-whiteboard fa-semibold fa-angle-right\"\u003e\u003c/i\u003e\n    The new parts\n  \u003c/a\u003e\n  \u003c/h2\u003e\n\u003cp\u003eI need to have a \u0026ldquo;universal table\u0026rdquo; for show data, with filter and export the data.\nAnd I need to have an \u0026ldquo;universal template\u0026rdquo; for all the combination Table-Export-Filter\u0026hellip;\u003c/p\u003e\n\u003cp\u003eSo I wrote one\u003c/p\u003e\n\u003cp\u003e\u003cimg  class=\"center-img u-photo \"  src=\"typing.gif\" alt=\"Typing\"\u003e\u003c/p\u003e\n\u003cp\u003eFirst thing (after the model and the table) I need view with filter and exporter support. And using \u003cem\u003edjango-table2\u003c/em\u003e\u003csup id=\"fnref:1\"\u003e\u003ca href=\"#fn:1\" class=\"footnote-ref\" role=\"doc-noteref\"\u003e1\u003c/a\u003e\u003c/sup\u003e all was easy.\u003csup id=\"fnref:2\"\u003e\u003ca href=\"#fn:2\" class=\"footnote-ref\" role=\"doc-noteref\"\u003e2\u003c/a\u003e\u003c/sup\u003e\u003c/p\u003e\n\u003cp\u003eSo I wrote this class which support all I need for using it as Htmx endpoint.\u003c/p\u003e\n\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;\"\u003e\u003ccode class=\"language-python\" data-lang=\"python\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# blog/views.py\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#f92672\"\u003efrom\u003c/span\u003e django_tables2 \u003cspan style=\"color:#f92672\"\u003eimport\u003c/span\u003e SingleTableMixin\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#f92672\"\u003efrom\u003c/span\u003e django_tables2.export \u003cspan style=\"color:#f92672\"\u003eimport\u003c/span\u003e ExportMixin, TableExport\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#f92672\"\u003efrom\u003c/span\u003e django_filters.views \u003cspan style=\"color:#f92672\"\u003eimport\u003c/span\u003e FilterView\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#f92672\"\u003efrom\u003c/span\u003e blog.model \u003cspan style=\"color:#f92672\"\u003eimport\u003c/span\u003e Post\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#66d9ef\"\u003eclass\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003eDataHtmx\u003c/span\u003e(ExportMixin, SingleTableMixin, FilterView):\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    model \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e Post\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    template_name \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;generic/table2.html\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    table_class \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e PostTable\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    filterset_fields \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e [\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;title\u0026#34;\u003c/span\u003e,\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;slug\u0026#34;\u003c/span\u003e, \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;date\u0026#34;\u003c/span\u003e]\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    export_formats \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e (\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        TableExport\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003eCSV,\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        TableExport\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003eXLS,\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        TableExport\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003eXLSX,\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        TableExport\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003eODS,\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    )\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003edef\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003eget_export_filename\u003c/span\u003e(self, export_format):\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#66d9ef\"\u003ereturn\u003c/span\u003e \u003cspan style=\"color:#e6db74\"\u003ef\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;Export Data.\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e{\u003c/span\u003eexport_format\u003cspan style=\"color:#e6db74\"\u003e}\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cul\u003e\n\u003cli\u003e\u003cem\u003eExportMixin\u003c/em\u003e, with the \u003cem\u003eexport_formats\u003c/em\u003e are the the export part of the view\u003c/li\u003e\n\u003cli\u003e\u003cem\u003eSingleTableMixin\u003c/em\u003e is the table part of the view\u003c/li\u003e\n\u003cli\u003e\u003cem\u003eFilterView\u003c/em\u003e is the filter part of the view, with \u003cem\u003efilterset_fields\u003c/em\u003e as the field you can filter. You can also haave a filterset_class if you need\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eDone this I need a template. More generic template because I don\u0026rsquo;t want to rewrite the same code every time\u0026hellip;\u003c/p\u003e\n\u003cp\u003eSo here is it!\u003c/p\u003e\n\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;\"\u003e\u003ccode class=\"language-django\" data-lang=\"django\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e# templates/generic/table.html\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e{%\u003c/span\u003e \u003cspan style=\"color:#66d9ef\"\u003eload\u003c/span\u003e render_table from django_tables2 \u003cspan style=\"color:#75715e\"\u003e%}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e{%\u003c/span\u003e \u003cspan style=\"color:#66d9ef\"\u003eload\u003c/span\u003e export_url from django_tables2 \u003cspan style=\"color:#75715e\"\u003e%}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e{%\u003c/span\u003e \u003cspan style=\"color:#66d9ef\"\u003eload\u003c/span\u003e django_bootstrap5 \u003cspan style=\"color:#75715e\"\u003e%}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e{%\u003c/span\u003e \u003cspan style=\"color:#66d9ef\"\u003eif\u003c/span\u003e filter  \u003cspan style=\"color:#75715e\"\u003e%}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#75715e\"\u003e{%\u003c/span\u003e \u003cspan style=\"color:#66d9ef\"\u003eif\u003c/span\u003e \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;hide_filter\u0026#39;\u003c/span\u003e \u003cspan style=\"color:#66d9ef\"\u003enot\u003c/span\u003e \u003cspan style=\"color:#66d9ef\"\u003ein\u003c/span\u003e request.GET \u003cspan style=\"color:#75715e\"\u003e%}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u0026lt;div class=\u0026#34;col-12 col-md-9\u0026#34;\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u0026lt;div class=\u0026#34;card mb-4\u0026#34;\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e          \u0026lt;div class=\u0026#34;card-header\u0026#34;\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u0026lt;button class=\u0026#34;btn btn-section\u0026#34; type=\u0026#34;button\u0026#34; data-bs-toggle=\u0026#34;collapse\u0026#34; data-bs-target=\u0026#34;#filterCollapse\u0026#34;\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e              \u0026lt;i class=\u0026#34;fa-solid fa-filter\u0026#34;\u0026gt;\u0026lt;/i\u0026gt; Filtri \u0026lt;i class=\u0026#34;fa-solid fa-chevron-down\u0026#34;\u0026gt;\u0026lt;/i\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u0026lt;/button\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e          \u0026lt;/div\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e          \u0026lt;div id=\u0026#34;filterCollapse\u0026#34; class=\u0026#34;collapse\u0026#34;\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u0026lt;div class=\u0026#34;card-body\u0026#34;\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e              \u0026lt;form method=\u0026#34;get\u0026#34; class=\u0026#34;row\u0026#34;\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                \u003cspan style=\"color:#75715e\"\u003e{%\u003c/span\u003e \u003cspan style=\"color:#66d9ef\"\u003eload\u003c/span\u003e django_bootstrap5 \u003cspan style=\"color:#75715e\"\u003e%}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                \u003cspan style=\"color:#75715e\"\u003e{%\u003c/span\u003e \u003cspan style=\"color:#66d9ef\"\u003ebootstrap_form\u003c/span\u003e filter.form layout\u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;floating\u0026#39;\u003c/span\u003e \u003cspan style=\"color:#75715e\"\u003e%}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                  \u003cspan style=\"color:#75715e\"\u003e{%\u003c/span\u003e \u003cspan style=\"color:#66d9ef\"\u003einclude\u003c/span\u003e \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;generic/_btn_search.html\u0026#39;\u003c/span\u003e \u003cspan style=\"color:#75715e\"\u003e%}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e              \u0026lt;/form\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u0026lt;/div\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e          \u0026lt;/div\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u0026lt;/div\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u0026lt;/div\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e{%\u003c/span\u003e \u003cspan style=\"color:#66d9ef\"\u003eendif\u003c/span\u003e \u003cspan style=\"color:#75715e\"\u003e%}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e{%\u003c/span\u003e \u003cspan style=\"color:#66d9ef\"\u003eendif\u003c/span\u003e \u003cspan style=\"color:#75715e\"\u003e%}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u0026lt;div class=\u0026#34;row\u0026#34;\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#75715e\"\u003e{%\u003c/span\u003e \u003cspan style=\"color:#66d9ef\"\u003eif\u003c/span\u003e \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;hide_export\u0026#39;\u003c/span\u003e \u003cspan style=\"color:#66d9ef\"\u003enot\u003c/span\u003e \u003cspan style=\"color:#66d9ef\"\u003ein\u003c/span\u003e request.GET \u003cspan style=\"color:#75715e\"\u003e%}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#75715e\"\u003e{%\u003c/span\u003e \u003cspan style=\"color:#66d9ef\"\u003efor\u003c/span\u003e format \u003cspan style=\"color:#66d9ef\"\u003ein\u003c/span\u003e view.export_formats \u003cspan style=\"color:#75715e\"\u003e%}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u0026lt;a  class=\u0026#34;btn col col-sm\u0026#34; href=\u0026#34;\u003cspan style=\"color:#75715e\"\u003e{{\u003c/span\u003e request.path \u003cspan style=\"color:#75715e\"\u003e}}{%\u003c/span\u003e \u003cspan style=\"color:#66d9ef\"\u003eexport_url\u003c/span\u003e format \u003cspan style=\"color:#75715e\"\u003e%}\u003c/span\u003e\u0026#34; target=\u0026#34;_blank\u0026#34;\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u0026lt;i class=\u0026#34;fa-duotone fa-regular fa-download\u0026#34;\u0026gt;\u0026lt;/i\u0026gt; \u0026lt;code\u0026gt;\u003cspan style=\"color:#75715e\"\u003e{{\u003c/span\u003e format \u003cspan style=\"color:#75715e\"\u003e}}\u003c/span\u003e\u0026lt;/code\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u0026lt;/a\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#75715e\"\u003e{%\u003c/span\u003e \u003cspan style=\"color:#66d9ef\"\u003eendfor\u003c/span\u003e \u003cspan style=\"color:#75715e\"\u003e%}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#75715e\"\u003e{%\u003c/span\u003e \u003cspan style=\"color:#66d9ef\"\u003eendif\u003c/span\u003e \u003cspan style=\"color:#75715e\"\u003e%}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u0026lt;hr\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#75715e\"\u003e{%\u003c/span\u003e \u003cspan style=\"color:#66d9ef\"\u003erender_table\u003c/span\u003e table \u003cspan style=\"color:#75715e\"\u003e%}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u0026lt;/div\u0026gt;\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003eThis template work if you have filters, export or not.\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003ethe load are for django-table2 and boostrap (the last is for me, is not needed for the code)\u003c/li\u003e\n\u003cli\u003e\u003cem\u003e\u0026lsquo;hide_filter\u0026rsquo; not in request.GET\u003c/em\u003e check if the url has the params for \u003cem\u003ehide_filter\u003c/em\u003e. If it is present, the template hides the filters\u003c/li\u003e\n\u003cli\u003e\u003cem\u003e\u0026lsquo;hide_export\u0026rsquo; not in request.GET\u003c/em\u003e check if the url has the params for \u003cem\u003ehide_export\u003c/em\u003e. If it is present, the template hides the exports\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eOne example for the Htmx code is the following.\u003c/p\u003e\n\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;\"\u003e\u003ccode class=\"language-django\" data-lang=\"django\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u0026lt;div hx-get=\u0026#34;\u003cspan style=\"color:#75715e\"\u003e{%\u003c/span\u003e \u003cspan style=\"color:#66d9ef\"\u003eurl\u003c/span\u003e \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;blog:post_htmx\u0026#39;\u003c/span\u003e \u003cspan style=\"color:#75715e\"\u003e%}\u003c/span\u003e?date_at=\u003cspan style=\"color:#75715e\"\u003e{{\u003c/span\u003e query_date \u003cspan style=\"color:#f92672\"\u003e|\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003edate\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e:\u0026#34;Y-m-d\u0026#34;\u003c/span\u003e  \u003cspan style=\"color:#75715e\"\u003e}}\u003c/span\u003e\u0026amp;hide_filter\u0026#34; hx-trigger=\u0026#34;load\u0026#34;\u0026gt;\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003eIn this example I had the filter set (with data form the template) and with \u003cem\u003ehide_filter\u003c/em\u003e which hide the filters but not the exports button.\u003c/p\u003e\n\u003cp\u003eI thing this will be a stable of my django code and it can be move in a custom module for share and easy import.\u003c/p\u003e\n\u003cdiv class=\"footnotes\" role=\"doc-endnotes\"\u003e\n\u003chr\u003e\n\u003col\u003e\n\u003cli id=\"fn:1\"\u003e\n\u003cp\u003e\u003ca class=\"a-post interlink-script\" href=\"https://django-tables2.readthedocs.io/en/latest/\"   target=\"_blank\"\u003eDjango-table2\u0026nbsp;\u0026nbsp;\u003ci class=\"fa-whiteboard fa-semibold fa-link\"\u003e\u003c/i\u003e\u003c/a\u003e\n\u0026#160;\u003ca href=\"#fnref:1\" class=\"footnote-backref\" role=\"doc-backlink\"\u003e\u0026#x21a9;\u0026#xfe0e;\u003c/a\u003e\u003c/p\u003e\n\u003c/li\u003e\n\u003cli id=\"fn:2\"\u003e\n\u003cp\u003eI also use \u003ca class=\"a-post interlink-script\" href=\"https://tablib.readthedocs.io/en/stable/\"   target=\"_blank\"\u003etablib\u0026nbsp;\u0026nbsp;\u003ci class=\"fa-whiteboard fa-semibold fa-link\"\u003e\u003c/i\u003e\u003c/a\u003e\n for the export and \u003ca class=\"a-post interlink-script\" href=\"https://django-filter.readthedocs.io/en/stable/\"   target=\"_blank\"\u003edjango-filter\u0026nbsp;\u0026nbsp;\u003ci class=\"fa-whiteboard fa-semibold fa-link\"\u003e\u003c/i\u003e\u003c/a\u003e\n for the filtering.\u0026#160;\u003ca href=\"#fnref:2\" class=\"footnote-backref\" role=\"doc-backlink\"\u003e\u0026#x21a9;\u0026#xfe0e;\u003c/a\u003e\u003c/p\u003e\n\u003c/li\u003e\n\u003c/ol\u003e\n\u003c/div\u003e\n","content_text":"Some time ago I wrote a blog post about Htmx and Django-table2 and all went well\u0026hellip;\nNo he didn\u0026rsquo;t work as I wanted so I did some editing of the code here and there.\nThe old one We start with the code I didn\u0026rsquo;t change:\nFirst the model\n# blog/model.py class Post(models.Model): title = models.CharField(max_length=400) slug = models.SlugField(max_length=400, unique=True, blank=True) content = models.TextAreaField() date = models.DateTimeField(auto_now_add=True)The table\n# blog/tables.py import django_tables2 as tables from blog.models import Post class PostTable(tables.Table): class Meta: model = Post order_by = (\u0026#34;-date\u0026#34;, \u0026#34;title\u0026#34;) fields = [\u0026#34;date\u0026#34;, \u0026#34;title\u0026#34;, \u0026#34;slug\u0026#34;]This two fragment are perfect as is so I didn\u0026rsquo;t touch them. But all the other part I reworked as I needed.\nThe new parts I need to have a \u0026ldquo;universal table\u0026rdquo; for show data, with filter and export the data. And I need to have an \u0026ldquo;universal template\u0026rdquo; for all the combination Table-Export-Filter\u0026hellip;\nSo I wrote one\nFirst thing (after the model and the table) I need view with filter and exporter support. And using django-table21 all was easy.2\nSo I wrote this class which support all I need for using it as Htmx endpoint.\n# blog/views.py from django_tables2 import SingleTableMixin from django_tables2.export import ExportMixin, TableExport from django_filters.views import FilterView from blog.model import Post class DataHtmx(ExportMixin, SingleTableMixin, FilterView): model = Post template_name = \u0026#34;generic/table2.html\u0026#34; table_class = PostTable filterset_fields = [\u0026#34;title\u0026#34;,\u0026#34;slug\u0026#34;, \u0026#34;date\u0026#34;] export_formats = ( TableExport.CSV, TableExport.XLS, TableExport.XLSX, TableExport.ODS, ) def get_export_filename(self, export_format): return f\u0026#34;Export Data.{export_format}\u0026#34; ExportMixin, with the export_formats are the the export part of the view SingleTableMixin is the table part of the view FilterView is the filter part of the view, with filterset_fields as the field you can filter. You can also haave a filterset_class if you need Done this I need a template. More generic template because I don\u0026rsquo;t want to rewrite the same code every time\u0026hellip;\nSo here is it!\n# templates/generic/table.html {% load render_table from django_tables2 %} {% load export_url from django_tables2 %} {% load django_bootstrap5 %} {% if filter %} {% if \u0026#39;hide_filter\u0026#39; not in request.GET %} \u0026lt;div class=\u0026#34;col-12 col-md-9\u0026#34;\u0026gt; \u0026lt;div class=\u0026#34;card mb-4\u0026#34;\u0026gt; \u0026lt;div class=\u0026#34;card-header\u0026#34;\u0026gt; \u0026lt;button class=\u0026#34;btn btn-section\u0026#34; type=\u0026#34;button\u0026#34; data-bs-toggle=\u0026#34;collapse\u0026#34; data-bs-target=\u0026#34;#filterCollapse\u0026#34;\u0026gt; \u0026lt;i class=\u0026#34;fa-solid fa-filter\u0026#34;\u0026gt;\u0026lt;/i\u0026gt; Filtri \u0026lt;i class=\u0026#34;fa-solid fa-chevron-down\u0026#34;\u0026gt;\u0026lt;/i\u0026gt; \u0026lt;/button\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;div id=\u0026#34;filterCollapse\u0026#34; class=\u0026#34;collapse\u0026#34;\u0026gt; \u0026lt;div class=\u0026#34;card-body\u0026#34;\u0026gt; \u0026lt;form method=\u0026#34;get\u0026#34; class=\u0026#34;row\u0026#34;\u0026gt; {% load django_bootstrap5 %} {% bootstrap_form filter.form layout=\u0026#39;floating\u0026#39; %} {% include \u0026#39;generic/_btn_search.html\u0026#39; %} \u0026lt;/form\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; {% endif %} {% endif %} \u0026lt;div class=\u0026#34;row\u0026#34;\u0026gt; {% if \u0026#39;hide_export\u0026#39; not in request.GET %} {% for format in view.export_formats %} \u0026lt;a class=\u0026#34;btn col col-sm\u0026#34; href=\u0026#34;{{ request.path }}{% export_url format %}\u0026#34; target=\u0026#34;_blank\u0026#34;\u0026gt; \u0026lt;i class=\u0026#34;fa-duotone fa-regular fa-download\u0026#34;\u0026gt;\u0026lt;/i\u0026gt; \u0026lt;code\u0026gt;{{ format }}\u0026lt;/code\u0026gt; \u0026lt;/a\u0026gt; {% endfor %} {% endif %} \u0026lt;hr\u0026gt; {% render_table table %} \u0026lt;/div\u0026gt;This template work if you have filters, export or not.\nthe load are for django-table2 and boostrap (the last is for me, is not needed for the code) \u0026lsquo;hide_filter\u0026rsquo; not in request.GET check if the url has the params for hide_filter. If it is present, the template hides the filters \u0026lsquo;hide_export\u0026rsquo; not in request.GET check if the url has the params for hide_export. If it is present, the template hides the exports One example for the Htmx code is the following.\n\u0026lt;div hx-get=\u0026#34;{% url \u0026#39;blog:post_htmx\u0026#39; %}?date_at={{ query_date | date:\u0026#34;Y-m-d\u0026#34; }}\u0026amp;hide_filter\u0026#34; hx-trigger=\u0026#34;load\u0026#34;\u0026gt;In this example I had the filter set (with data form the template) and with hide_filter which hide the filters but not the exports button.\nI thing this will be a stable of my django code and it can be move in a custom module for share and easy import.\nDjango-table2\u0026nbsp;\u0026nbsp; \u0026#160;\u0026#x21a9;\u0026#xfe0e;\nI also use tablib\u0026nbsp;\u0026nbsp; for the export and django-filter\u0026nbsp;\u0026nbsp; for the filtering.\u0026#160;\u0026#x21a9;\u0026#xfe0e;\n","image":"https://fundor333.com/post/2026/django-table-filter-export-with-htmx/cover.png","banner_image":"https://fundor333.com/post/2026/django-table-filter-export-with-htmx/cover.png"},{"title":"Starting My Home Automation Experiment","date_published":"2026-03-31T08:46:01+02:00","date_modified":"2026-07-16T22:49:21+02:00","id":"https://fundor333.com/post/2026/starting-my-home-automation-experiment/","url":"https://fundor333.com/post/2026/starting-my-home-automation-experiment/","tags":["home-automation","hacking","self-hosting","raspberry-pi","home-assistant","tinkering"],"content_html":"\u003cp\u003eAnd some time ago I installed the Fiber\u003csup id=\"fnref:1\"\u003e\u003ca href=\"#fn:1\" class=\"footnote-ref\" role=\"doc-noteref\"\u003e1\u003c/a\u003e\u003c/sup\u003e in my home and I want to use in the best way, so I start to rework all my local network and I think about adding some home automation.\u003c/p\u003e\n\n\n\n\n\n\u003cdiv class=\"xkcd-container\"\u003e\n  \u003ch4 class=\"xkcd-title\"\u003eXkcd - Virtual Assistant\u003c/h4\u003e\n  \u003ca href=\"https://xkcd.com/1931/\" target=\"_blank\" rel=\"noopener\"\u003e\n    \u003cimg src=\"https://imgs.xkcd.com/comics/virtual_assistant.png\" alt=\"If you ask it to please turn off that feature, it apologizes a whole bunch and promises to try to be quieter, then switches to a slightly lower-volume version of the clip with \u0026#34;sorry!\u0026#34; after the louder sounds.\" title=\"If you ask it to please turn off that feature, it apologizes a whole bunch and promises to try to be quieter, then switches to a slightly lower-volume version of the clip with \u0026#34;sorry!\u0026#34; after the louder sounds.\" class=\"xkcd-image u-photo\"\u003e\n  \u003c/a\u003e\n  \u003cp class=\"xkcd-subtitle\"\u003e\n    \u003cem\u003eIf you ask it to please turn off that feature, it apologizes a whole bunch and promises to try to be quieter, then switches to a slightly lower-volume version of the clip with \u0026#34;sorry!\u0026#34; after the louder sounds.\u003c/em\u003e\n  \u003c/p\u003e\n\u003c/div\u003e\n\n\n\u003ch2 id=\"what-do-i-need\" class=\"no-underline \"\u003e\n  \u003ca href=\"#what-do-i-need\"\u003e\n    \u003ci class=\"fa-whiteboard fa-semibold fa-angle-right\"\u003e\u003c/i\u003e\n    What do I need?\n  \u003c/a\u003e\n  \u003c/h2\u003e\n\u003cp\u003eFirst I search for understand what I need to have for build my personal home automation. So serching on the web I found I need:\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003eA brain/core/server for coordinate all the stuffs\u003c/li\u003e\n\u003cli\u003eA software for the brain, for the automation  and other stuff\u003c/li\u003e\n\u003cli\u003eA router for adding the brain to the network for update and other stuff\u003c/li\u003e\n\u003cli\u003eDongle/sensor/tech for connectivity with the sensors and smart stuff (one for protocol)\u003c/li\u003e\n\u003cli\u003eThe smart stuff (light bulb, sensor, timer, endpoint api\u0026hellip;)\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eSo I need to choose which protocol I want in my home\u0026hellip; And I don\u0026rsquo;t know\u0026hellip;\u003c/p\u003e\n\u003cp\u003eSo I change the point of view:\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003eI want to use good smart stuff but I don\u0026rsquo;t want to pay too much\u003c/li\u003e\n\u003cli\u003eI want something Open Source so I am not bind to a company\u003c/li\u003e\n\u003cli\u003eI want something offline or/and on MY HOME SERVER\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch3 id=\"the-protocols\" class=\"no-underline \"\u003e\n  \u003ca href=\"#the-protocols\"\u003e\n    \u003ci class=\"fa-whiteboard fa-semibold fa-angle-right\"\u003e\u003c/i\u003e\u003ci class=\"fa-whiteboard fa-semibold fa-angle-right\"\u003e\u003c/i\u003e\n    The protocols\n  \u003c/a\u003e\n  \u003c/h3\u003e\n\u003cp\u003eSearching for the protocols I choose Thread\u003csup id=\"fnref:2\"\u003e\u003ca href=\"#fn:2\" class=\"footnote-ref\" role=\"doc-noteref\"\u003e2\u003c/a\u003e\u003c/sup\u003e and Zigbee\u003csup id=\"fnref:3\"\u003e\u003ca href=\"#fn:3\" class=\"footnote-ref\" role=\"doc-noteref\"\u003e3\u003c/a\u003e\u003c/sup\u003e.\nOne reason is because they are the most used protocol for communication and more easy to find online (Amazon) and offline (Ikea and othe local shop).\u003c/p\u003e\n\u003cp\u003eFor starting I will implement only Thread because the more easy tech for me are all Matter over Thread so I start with Thread.\u003c/p\u003e\n\u003cp\u003eFrom the infographic I found, I need to implement Matter\u003csup id=\"fnref:4\"\u003e\u003ca href=\"#fn:4\" class=\"footnote-ref\" role=\"doc-noteref\"\u003e4\u003c/a\u003e\u003c/sup\u003e also because Matter is the top stuff for an Home Assistant.\n\u003cimg  class=\"center-img u-photo \"  src=\"matter_thread_infographic.png\" alt=\"Matter Thread Infographic \"\u003e\u003c/p\u003e\n\u003ch3 id=\"the-software\" class=\"no-underline \"\u003e\n  \u003ca href=\"#the-software\"\u003e\n    \u003ci class=\"fa-whiteboard fa-semibold fa-angle-right\"\u003e\u003c/i\u003e\u003ci class=\"fa-whiteboard fa-semibold fa-angle-right\"\u003e\u003c/i\u003e\n    The software\n  \u003c/a\u003e\n  \u003c/h3\u003e\n\u003cp\u003eNow I want a software, Open Source, which I can support Thread and Matter (and also Zigbee) and I found a software (Open Source) wich support all I need: Home Assistant\u003csup id=\"fnref:5\"\u003e\u003ca href=\"#fn:5\" class=\"footnote-ref\" role=\"doc-noteref\"\u003e5\u003c/a\u003e\u003c/sup\u003e.\u003c/p\u003e\n\u003cp\u003eIt support Matter\u003csup id=\"fnref:6\"\u003e\u003ca href=\"#fn:6\" class=\"footnote-ref\" role=\"doc-noteref\"\u003e6\u003c/a\u003e\u003c/sup\u003e, Thread\u003csup id=\"fnref:7\"\u003e\u003ca href=\"#fn:7\" class=\"footnote-ref\" role=\"doc-noteref\"\u003e7\u003c/a\u003e\u003c/sup\u003e and Zigbee\u003csup id=\"fnref:8\"\u003e\u003ca href=\"#fn:8\" class=\"footnote-ref\" role=\"doc-noteref\"\u003e8\u003c/a\u003e\u003c/sup\u003e and I can put it in a RaspberryPi or other server.\u003c/p\u003e\n\u003ch2 id=\"hardware\" class=\"no-underline \"\u003e\n  \u003ca href=\"#hardware\"\u003e\n    \u003ci class=\"fa-whiteboard fa-semibold fa-angle-right\"\u003e\u003c/i\u003e\n    Hardware\n  \u003c/a\u003e\n  \u003c/h2\u003e\n\u003cp\u003eSo I start to make a list of what I have and what I need.\nSome things I buy online, some things come from some tech market and some come form the shoes box of my old stuff\u0026hellip;\u003c/p\u003e\n\u003cp\u003eI only write about the real things but if I use cable or other \u0026ldquo;standard stuff\u0026rdquo; I don\u0026rsquo;t write about it.\nSo yes I bought some usb extention and some network cable but they aren\u0026rsquo;t important for this post.\u003c/p\u003e\n\u003ch3 id=\"corebrain-stuff\" class=\"no-underline \"\u003e\n  \u003ca href=\"#corebrain-stuff\"\u003e\n    \u003ci class=\"fa-whiteboard fa-semibold fa-angle-right\"\u003e\u003c/i\u003e\u003ci class=\"fa-whiteboard fa-semibold fa-angle-right\"\u003e\u003c/i\u003e\n    Core/Brain Stuff\n  \u003c/a\u003e\n  \u003c/h3\u003e\n\u003cp\u003eFirst I need the Brain for the project\u003c/p\u003e\n\u003cp\u003e\u003cimg  class=\"center-img u-photo \"  src=\"ABnormal_GIF.gif\" alt=\"Brain\"\u003e\u003c/p\u003e\n\u003cp\u003eFrom what I read in the Home Assistant\u003csup id=\"fnref1:5\"\u003e\u003ca href=\"#fn:5\" class=\"footnote-ref\" role=\"doc-noteref\"\u003e5\u003c/a\u003e\u003c/sup\u003e documentation I need some type of server with some gadget connected to them.\u003c/p\u003e\n\u003cp\u003eSo I search and  got a RaspberryPi 4B\u003csup id=\"fnref:9\"\u003e\u003ca href=\"#fn:9\" class=\"footnote-ref\" role=\"doc-noteref\"\u003e9\u003c/a\u003e\u003c/sup\u003e.\n\u003cimg  class=\"center-img u-photo \"  src=\"raspberry.jpg\" alt=\"Raspberry\"\u003e\u003c/p\u003e\n\u003cp\u003eI also bought a microSD with 64GB of memory (I am on a budget for this project) as an Hard Disk for the \u0026ldquo;server\u0026rdquo;.\u003c/p\u003e\n\u003cp\u003eSearching in my closet and in some shoes boxes I found a case\u003csup id=\"fnref:10\"\u003e\u003ca href=\"#fn:10\" class=\"footnote-ref\" role=\"doc-noteref\"\u003e10\u003c/a\u003e\u003c/sup\u003e for RaspberryPi with active cooling system (and LGB light)\u003c/p\u003e\n\u003cp\u003eSo I flash the microSD with the Home Assistant software. Thanks to the Raspberry Pi Software\u003csup id=\"fnref:11\"\u003e\u003ca href=\"#fn:11\" class=\"footnote-ref\" role=\"doc-noteref\"\u003e11\u003c/a\u003e\u003c/sup\u003e choosing the right iso and flash it in the SD was a walk in the park.\u003c/p\u003e\n\u003cp\u003eAfter the flashing I set it up and add to my local network and check for update.\u003c/p\u003e\n\u003cp\u003eSo the brain is ready!\u003c/p\u003e\n\u003ch3 id=\"sensor-form-ikea\" class=\"no-underline \"\u003e\n  \u003ca href=\"#sensor-form-ikea\"\u003e\n    \u003ci class=\"fa-whiteboard fa-semibold fa-angle-right\"\u003e\u003c/i\u003e\u003ci class=\"fa-whiteboard fa-semibold fa-angle-right\"\u003e\u003c/i\u003e\n    Sensor form Ikea\n  \u003c/a\u003e\n  \u003c/h3\u003e\n\u003cp\u003eI went to Ikea for some stuff and some Swedish meatballs and I came back with an Ikea Alpstuga\u003csup id=\"fnref:12\"\u003e\u003ca href=\"#fn:12\" class=\"footnote-ref\" role=\"doc-noteref\"\u003e12\u003c/a\u003e\u003c/sup\u003e.\u003c/p\u003e\n\u003cp\u003e\u003cimg  class=\"center-img u-photo \"  src=\"ikea.jpg\" alt=\"Ikea Alpstuga\"\u003e\u003c/p\u003e\n\u003cp\u003eIt is a timer, air sensor with CO2 and PM2.5 sensor and output all of them and an Air Quality value.\u003c/p\u003e\n\u003cp\u003eThe only bad thing about it is the color but for the price I don\u0026rsquo;t complain.\u003c/p\u003e\n\u003cp\u003eSo after coming home I found it didn\u0026rsquo;t work.\u003c/p\u003e\n\u003cp\u003e\u003cimg  class=\"center-img u-photo \"  src=\"nope.gif\" alt=\"Nope\"\u003e\u003c/p\u003e\n\u003cp\u003eAs is the RaspberryPi 4B do not support Thread or Zigbee without some type of specialized antenna\u0026hellip;\nI was understanding that the software use the wifi module of the RaspberryPi as a Zigbee/Thread emitter/reciver but no so I search on Amazon for the dongle for Thread.\u003c/p\u003e\n\u003ch3 id=\"antenna\" class=\"no-underline \"\u003e\n  \u003ca href=\"#antenna\"\u003e\n    \u003ci class=\"fa-whiteboard fa-semibold fa-angle-right\"\u003e\u003c/i\u003e\u003ci class=\"fa-whiteboard fa-semibold fa-angle-right\"\u003e\u003c/i\u003e\n    Antenna\n  \u003c/a\u003e\n  \u003c/h3\u003e\n\u003cp\u003eI bought a Usb dongle\u003csup id=\"fnref:13\"\u003e\u003ca href=\"#fn:13\" class=\"footnote-ref\" role=\"doc-noteref\"\u003e13\u003c/a\u003e\u003c/sup\u003e for connecting the RaspberryPi and the other gadget in the house (for now only the Ikea one)\u003c/p\u003e\n\u003cp\u003e\u003cimg  class=\"center-img u-photo \"  src=\"antenna.jpg\" alt=\"Antenna\"\u003e\u003csup id=\"fnref1:13\"\u003e\u003ca href=\"#fn:13\" class=\"footnote-ref\" role=\"doc-noteref\"\u003e13\u003c/a\u003e\u003c/sup\u003e\u003c/p\u003e\n\u003cp\u003eThis antenna is a little special: you can flash it for changing it form Zigbee to Thread and vice versa so I start to config it.\u003c/p\u003e\n\u003ch4 id=\"setup-the-antenna\" class=\"no-underline \"\u003e\n  \u003ca href=\"#setup-the-antenna\"\u003e\n    \u003ci class=\"fa-whiteboard fa-semibold fa-angle-right\"\u003e\u003c/i\u003e\u003ci class=\"fa-whiteboard fa-semibold fa-angle-right\"\u003e\u003c/i\u003e\u003ci class=\"fa-whiteboard fa-semibold fa-angle-right\"\u003e\u003c/i\u003e\n    Setup the Antenna\n  \u003c/a\u003e\n  \u003c/h4\u003e\n\u003cp\u003eFirst I flash the antenna. I need to port from Zigbee to Thread\u003csup id=\"fnref:14\"\u003e\u003ca href=\"#fn:14\" class=\"footnote-ref\" role=\"doc-noteref\"\u003e14\u003c/a\u003e\u003c/sup\u003e and with the online tool it was so easy I thought I did something wrong.\u003c/p\u003e\n\u003cp\u003eAfter this I connect the dongle and start to config the Home Assistant.\u003c/p\u003e\n\u003cp\u003eFirst I need to have installed Thread  from \u0026ldquo;Add Integration\u0026rdquo; and it showed an empty list of device. This is correct because I didn\u0026rsquo;t have a Thread router installed.\u003c/p\u003e\n\u003cp\u003eSo we add a OpenRouter. How? Installing from the officials app of mine Home Assistant.\u003c/p\u003e\n\u003cp\u003e\u003cimg  class=\"center-img u-photo \"  src=\"Thread.png\" alt=\"Open Thread on a menu\"\u003e\u003c/p\u003e\n\u003cp\u003eAfter this I edit the config in this way (the device was auto-finded) and I set this for my device. \u003csup id=\"fnref:15\"\u003e\u003ca href=\"#fn:15\" class=\"footnote-ref\" role=\"doc-noteref\"\u003e15\u003c/a\u003e\u003c/sup\u003e\u003c/p\u003e\n\u003cp\u003e\u003cimg  class=\"center-img u-photo \"  src=\"openThread.png\" alt=\"Open Thread config\"\u003e\u003c/p\u003e\n\u003cp\u003eFor checking if all was ok I went and seach in the log for the OpenThread for a specific line.\u003c/p\u003e\n\u003cp\u003e\u003cimg  class=\"center-img u-photo \"  src=\"log-antenna.png\" alt=\"Log Antenna\"\u003e\u003c/p\u003e\n\u003cp\u003eAfter this I went to check if the Thread integration showed the Ikea sensor and it didn\u0026rsquo;t show\u0026hellip; Why? Because I am STUPID.\u003c/p\u003e\n\u003ch4 id=\"setup-the-last-little-things\" class=\"no-underline \"\u003e\n  \u003ca href=\"#setup-the-last-little-things\"\u003e\n    \u003ci class=\"fa-whiteboard fa-semibold fa-angle-right\"\u003e\u003c/i\u003e\u003ci class=\"fa-whiteboard fa-semibold fa-angle-right\"\u003e\u003c/i\u003e\u003ci class=\"fa-whiteboard fa-semibold fa-angle-right\"\u003e\u003c/i\u003e\n    Setup the last little things\n  \u003c/a\u003e\n  \u003c/h4\u003e\n\u003cp\u003eAlpstuga (my air sensor) is not Thread, is Matter over Thread, so I need to add the thing with the Matter integration. And with this last integration the system worked!\u003c/p\u003e\n\u003cp\u003e\u003cimg  class=\"center-img u-photo \"  src=\"its-alive.gif\" alt=\"Its alive\"\u003e\u003c/p\u003e\n\u003cp\u003eI am happy of this system? No. Why? I have the wrong time on the Alpstuga.\u003c/p\u003e\n\u003cp\u003eThis thing I don\u0026rsquo;t understand so I search online for understand how can I fix the time on the device.\u003c/p\u003e\n\u003cp\u003eI find this is a common problem with the Alpstuga device and someone made a Hacs\u003csup id=\"fnref:16\"\u003e\u003ca href=\"#fn:16\" class=\"footnote-ref\" role=\"doc-noteref\"\u003e16\u003c/a\u003e\u003c/sup\u003e plugin\u003csup id=\"fnref:17\"\u003e\u003ca href=\"#fn:17\" class=\"footnote-ref\" role=\"doc-noteref\"\u003e17\u003c/a\u003e\u003c/sup\u003e wich add a cron and a button for sync the Home Assistant\u0026rsquo;s clock. I also add the plugin for integrate my Playstation Network in my Home Assistant\u003csup id=\"fnref:18\"\u003e\u003ca href=\"#fn:18\" class=\"footnote-ref\" role=\"doc-noteref\"\u003e18\u003c/a\u003e\u003c/sup\u003e.\u003c/p\u003e\n\u003ch2 id=\"conclusion\" class=\"no-underline \"\u003e\n  \u003ca href=\"#conclusion\"\u003e\n    \u003ci class=\"fa-whiteboard fa-semibold fa-angle-right\"\u003e\u003c/i\u003e\n    Conclusion\n  \u003c/a\u003e\n  \u003c/h2\u003e\n\u003cp\u003eFor now this is what I had done but I want to have automation (for now I don\u0026rsquo;t have any) and some stuff for lower the gas bill so there will be more post about my smart home.\u003c/p\u003e\n\u003cdiv class=\"footnotes\" role=\"doc-endnotes\"\u003e\n\u003chr\u003e\n\u003col\u003e\n\u003cli id=\"fn:1\"\u003e\n\u003cp\u003eI pay a company to install it and I clean after.\u0026#160;\u003ca href=\"#fnref:1\" class=\"footnote-backref\" role=\"doc-backlink\"\u003e\u0026#x21a9;\u0026#xfe0e;\u003c/a\u003e\u003c/p\u003e\n\u003c/li\u003e\n\u003cli id=\"fn:2\"\u003e\n\u003cp\u003e\u003ca class=\"a-post interlink-script\" href=\"https://threadgroup.org/\"   target=\"_blank\"\u003eThread Standard\u0026nbsp;\u0026nbsp;\u003ci class=\"fa-whiteboard fa-semibold fa-link\"\u003e\u003c/i\u003e\u003c/a\u003e\n\u0026#160;\u003ca href=\"#fnref:2\" class=\"footnote-backref\" role=\"doc-backlink\"\u003e\u0026#x21a9;\u0026#xfe0e;\u003c/a\u003e\u003c/p\u003e\n\u003c/li\u003e\n\u003cli id=\"fn:3\"\u003e\n\u003cp\u003e\u003ca class=\"a-post interlink-script\" href=\"https://csa-iot.org/all-solutions/zigbee/\"   target=\"_blank\"\u003eZigbee Standard\u0026nbsp;\u0026nbsp;\u003ci class=\"fa-whiteboard fa-semibold fa-link\"\u003e\u003c/i\u003e\u003c/a\u003e\n\u0026#160;\u003ca href=\"#fnref:3\" class=\"footnote-backref\" role=\"doc-backlink\"\u003e\u0026#x21a9;\u0026#xfe0e;\u003c/a\u003e\u003c/p\u003e\n\u003c/li\u003e\n\u003cli id=\"fn:4\"\u003e\n\u003cp\u003e\u003ca class=\"a-post interlink-script\" href=\"https://csa-iot.org/all-solutions/matter/\"   target=\"_blank\"\u003eMatter Standard\u0026nbsp;\u0026nbsp;\u003ci class=\"fa-whiteboard fa-semibold fa-link\"\u003e\u003c/i\u003e\u003c/a\u003e\n\u0026#160;\u003ca href=\"#fnref:4\" class=\"footnote-backref\" role=\"doc-backlink\"\u003e\u0026#x21a9;\u0026#xfe0e;\u003c/a\u003e\u003c/p\u003e\n\u003c/li\u003e\n\u003cli id=\"fn:5\"\u003e\n\u003cp\u003e\u003ca class=\"a-post interlink-script\" href=\"https://www.home-assistant.io/\"   target=\"_blank\"\u003eHome Assistant\u0026nbsp;\u0026nbsp;\u003ci class=\"fa-whiteboard fa-semibold fa-link\"\u003e\u003c/i\u003e\u003c/a\u003e\n\u0026#160;\u003ca href=\"#fnref:5\" class=\"footnote-backref\" role=\"doc-backlink\"\u003e\u0026#x21a9;\u0026#xfe0e;\u003c/a\u003e\u0026#160;\u003ca href=\"#fnref1:5\" class=\"footnote-backref\" role=\"doc-backlink\"\u003e\u0026#x21a9;\u0026#xfe0e;\u003c/a\u003e\u003c/p\u003e\n\u003c/li\u003e\n\u003cli id=\"fn:6\"\u003e\n\u003cp\u003e\u003ca class=\"a-post interlink-script\" href=\"https://www.home-assistant.io/integrations/matter/\"   target=\"_blank\"\u003eHome Assistant Matter\u0026nbsp;\u0026nbsp;\u003ci class=\"fa-whiteboard fa-semibold fa-link\"\u003e\u003c/i\u003e\u003c/a\u003e\n\u0026#160;\u003ca href=\"#fnref:6\" class=\"footnote-backref\" role=\"doc-backlink\"\u003e\u0026#x21a9;\u0026#xfe0e;\u003c/a\u003e\u003c/p\u003e\n\u003c/li\u003e\n\u003cli id=\"fn:7\"\u003e\n\u003cp\u003e\u003ca class=\"a-post interlink-script\" href=\"https://www.home-assistant.io/integrations/thread/\"   target=\"_blank\"\u003eHome Assistant Thread\u0026nbsp;\u0026nbsp;\u003ci class=\"fa-whiteboard fa-semibold fa-link\"\u003e\u003c/i\u003e\u003c/a\u003e\n\u0026#160;\u003ca href=\"#fnref:7\" class=\"footnote-backref\" role=\"doc-backlink\"\u003e\u0026#x21a9;\u0026#xfe0e;\u003c/a\u003e\u003c/p\u003e\n\u003c/li\u003e\n\u003cli id=\"fn:8\"\u003e\n\u003cp\u003e\u003ca class=\"a-post interlink-script\" href=\"https://www.home-assistant.io/integrations/zha/\"   target=\"_blank\"\u003eZigbee Home Automation\u0026nbsp;\u0026nbsp;\u003ci class=\"fa-whiteboard fa-semibold fa-link\"\u003e\u003c/i\u003e\u003c/a\u003e\n\u0026#160;\u003ca href=\"#fnref:8\" class=\"footnote-backref\" role=\"doc-backlink\"\u003e\u0026#x21a9;\u0026#xfe0e;\u003c/a\u003e\u003c/p\u003e\n\u003c/li\u003e\n\u003cli id=\"fn:9\"\u003e\n\u003cp\u003e\u003ca class=\"a-post interlink-script\" href=\"https://www.raspberrypi.com/products/raspberry-pi-4-model-b/\"   target=\"_blank\"\u003eRaspberryPi 4B\u0026nbsp;\u0026nbsp;\u003ci class=\"fa-whiteboard fa-semibold fa-link\"\u003e\u003c/i\u003e\u003c/a\u003e\n\u0026#160;\u003ca href=\"#fnref:9\" class=\"footnote-backref\" role=\"doc-backlink\"\u003e\u0026#x21a9;\u0026#xfe0e;\u003c/a\u003e\u003c/p\u003e\n\u003c/li\u003e\n\u003cli id=\"fn:10\"\u003e\n\u003cp\u003e\u003ca class=\"a-post interlink-script\" href=\"https://www.amazon.it/dp/B07YJGWPQL\"   target=\"_blank\"\u003eRaspberry Pi 4B Case from Owootecc\u0026nbsp;\u0026nbsp;\u003ci class=\"fa-whiteboard fa-semibold fa-link\"\u003e\u003c/i\u003e\u003c/a\u003e\n\u0026#160;\u003ca href=\"#fnref:10\" class=\"footnote-backref\" role=\"doc-backlink\"\u003e\u0026#x21a9;\u0026#xfe0e;\u003c/a\u003e\u003c/p\u003e\n\u003c/li\u003e\n\u003cli id=\"fn:11\"\u003e\n\u003cp\u003e\u003ca class=\"a-post interlink-script\" href=\"https://www.raspberrypi.com/software/\"   target=\"_blank\"\u003eRaspberry Pi software\u0026nbsp;\u0026nbsp;\u003ci class=\"fa-whiteboard fa-semibold fa-link\"\u003e\u003c/i\u003e\u003c/a\u003e\n\u0026#160;\u003ca href=\"#fnref:11\" class=\"footnote-backref\" role=\"doc-backlink\"\u003e\u0026#x21a9;\u0026#xfe0e;\u003c/a\u003e\u003c/p\u003e\n\u003c/li\u003e\n\u003cli id=\"fn:12\"\u003e\n\u003cp\u003e\u003ca class=\"a-post interlink-script\" href=\"https://www.ikea.com/it/it/p/alpstuga-sensore-della-qualita-dellaria-smart-50604187/\"   target=\"_blank\"\u003eIkea Alpstuga\u0026nbsp;\u0026nbsp;\u003ci class=\"fa-whiteboard fa-semibold fa-link\"\u003e\u003c/i\u003e\u003c/a\u003e\n\u0026#160;\u003ca href=\"#fnref:12\" class=\"footnote-backref\" role=\"doc-backlink\"\u003e\u0026#x21a9;\u0026#xfe0e;\u003c/a\u003e\u003c/p\u003e\n\u003c/li\u003e\n\u003cli id=\"fn:13\"\u003e\n\u003cp\u003e\u003ca class=\"a-post interlink-script\" href=\"https://www.amazon.it/dp/B0FMJD288B\"   target=\"_blank\"\u003eSONOFF Zigbee 3.0 USB Dongle Plus MG24\u0026nbsp;\u0026nbsp;\u003ci class=\"fa-whiteboard fa-semibold fa-link\"\u003e\u003c/i\u003e\u003c/a\u003e\n\u0026#160;\u003ca href=\"#fnref:13\" class=\"footnote-backref\" role=\"doc-backlink\"\u003e\u0026#x21a9;\u0026#xfe0e;\u003c/a\u003e\u0026#160;\u003ca href=\"#fnref1:13\" class=\"footnote-backref\" role=\"doc-backlink\"\u003e\u0026#x21a9;\u0026#xfe0e;\u003c/a\u003e\u003c/p\u003e\n\u003c/li\u003e\n\u003cli id=\"fn:14\"\u003e\n\u003cp\u003e\u003ca class=\"a-post interlink-script\" href=\"https://dongle.sonoff.tech/sonoff-dongle-flasher/\"   target=\"_blank\"\u003eSonoff dongle flasher/\u0026nbsp;\u0026nbsp;\u003ci class=\"fa-whiteboard fa-semibold fa-link\"\u003e\u003c/i\u003e\u003c/a\u003e\n\u0026#160;\u003ca href=\"#fnref:14\" class=\"footnote-backref\" role=\"doc-backlink\"\u003e\u0026#x21a9;\u0026#xfe0e;\u003c/a\u003e\u003c/p\u003e\n\u003c/li\u003e\n\u003cli id=\"fn:15\"\u003e\n\u003cp\u003eThis config work for me, it can not work for you\u0026#160;\u003ca href=\"#fnref:15\" class=\"footnote-backref\" role=\"doc-backlink\"\u003e\u0026#x21a9;\u0026#xfe0e;\u003c/a\u003e\u003c/p\u003e\n\u003c/li\u003e\n\u003cli id=\"fn:16\"\u003e\n\u003cp\u003e\u003ca class=\"a-post interlink-script\" href=\"https://www.hacs.xyz/\"   target=\"_blank\"\u003eHome Assistant Hacs\u0026nbsp;\u0026nbsp;\u003ci class=\"fa-whiteboard fa-semibold fa-link\"\u003e\u003c/i\u003e\u003c/a\u003e\n\u0026#160;\u003ca href=\"#fnref:16\" class=\"footnote-backref\" role=\"doc-backlink\"\u003e\u0026#x21a9;\u0026#xfe0e;\u003c/a\u003e\u003c/p\u003e\n\u003c/li\u003e\n\u003cli id=\"fn:17\"\u003e\n\u003cp\u003e\u003ca class=\"a-post interlink-script\" href=\"https://github.com/Loweack/Matter-Time-Sync/\"   target=\"_blank\"\u003eMatter time synk\u0026nbsp;\u0026nbsp;\u003ci class=\"fa-whiteboard fa-semibold fa-link\"\u003e\u003c/i\u003e\u003c/a\u003e\n\u0026#160;\u003ca href=\"#fnref:17\" class=\"footnote-backref\" role=\"doc-backlink\"\u003e\u0026#x21a9;\u0026#xfe0e;\u003c/a\u003e\u003c/p\u003e\n\u003c/li\u003e\n\u003cli id=\"fn:18\"\u003e\n\u003cp\u003e\u003ca class=\"a-post interlink-script\" href=\"https://www.home-assistant.io/integrations/playstation_network/\"   target=\"_blank\"\u003ePlayStation Network Home Assistant\u0026nbsp;\u0026nbsp;\u003ci class=\"fa-whiteboard fa-semibold fa-link\"\u003e\u003c/i\u003e\u003c/a\u003e\n\u0026#160;\u003ca href=\"#fnref:18\" class=\"footnote-backref\" role=\"doc-backlink\"\u003e\u0026#x21a9;\u0026#xfe0e;\u003c/a\u003e\u003c/p\u003e\n\u003c/li\u003e\n\u003c/ol\u003e\n\u003c/div\u003e\n","content_text":"And some time ago I installed the Fiber1 in my home and I want to use in the best way, so I start to rework all my local network and I think about adding some home automation.\nXkcd - Virtual Assistant If you ask it to please turn off that feature, it apologizes a whole bunch and promises to try to be quieter, then switches to a slightly lower-volume version of the clip with \u0026#34;sorry!\u0026#34; after the louder sounds. What do I need? First I search for understand what I need to have for build my personal home automation. So serching on the web I found I need:\nA brain/core/server for coordinate all the stuffs A software for the brain, for the automation and other stuff A router for adding the brain to the network for update and other stuff Dongle/sensor/tech for connectivity with the sensors and smart stuff (one for protocol) The smart stuff (light bulb, sensor, timer, endpoint api\u0026hellip;) So I need to choose which protocol I want in my home\u0026hellip; And I don\u0026rsquo;t know\u0026hellip;\nSo I change the point of view:\nI want to use good smart stuff but I don\u0026rsquo;t want to pay too much I want something Open Source so I am not bind to a company I want something offline or/and on MY HOME SERVER The protocols Searching for the protocols I choose Thread2 and Zigbee3. One reason is because they are the most used protocol for communication and more easy to find online (Amazon) and offline (Ikea and othe local shop).\nFor starting I will implement only Thread because the more easy tech for me are all Matter over Thread so I start with Thread.\nFrom the infographic I found, I need to implement Matter4 also because Matter is the top stuff for an Home Assistant. The software Now I want a software, Open Source, which I can support Thread and Matter (and also Zigbee) and I found a software (Open Source) wich support all I need: Home Assistant5.\nIt support Matter6, Thread7 and Zigbee8 and I can put it in a RaspberryPi or other server.\nHardware So I start to make a list of what I have and what I need. Some things I buy online, some things come from some tech market and some come form the shoes box of my old stuff\u0026hellip;\nI only write about the real things but if I use cable or other \u0026ldquo;standard stuff\u0026rdquo; I don\u0026rsquo;t write about it. So yes I bought some usb extention and some network cable but they aren\u0026rsquo;t important for this post.\nCore/Brain Stuff First I need the Brain for the project\nFrom what I read in the Home Assistant5 documentation I need some type of server with some gadget connected to them.\nSo I search and got a RaspberryPi 4B9. I also bought a microSD with 64GB of memory (I am on a budget for this project) as an Hard Disk for the \u0026ldquo;server\u0026rdquo;.\nSearching in my closet and in some shoes boxes I found a case10 for RaspberryPi with active cooling system (and LGB light)\nSo I flash the microSD with the Home Assistant software. Thanks to the Raspberry Pi Software11 choosing the right iso and flash it in the SD was a walk in the park.\nAfter the flashing I set it up and add to my local network and check for update.\nSo the brain is ready!\nSensor form Ikea I went to Ikea for some stuff and some Swedish meatballs and I came back with an Ikea Alpstuga12.\nIt is a timer, air sensor with CO2 and PM2.5 sensor and output all of them and an Air Quality value.\nThe only bad thing about it is the color but for the price I don\u0026rsquo;t complain.\nSo after coming home I found it didn\u0026rsquo;t work.\nAs is the RaspberryPi 4B do not support Thread or Zigbee without some type of specialized antenna\u0026hellip; I was understanding that the software use the wifi module of the RaspberryPi as a Zigbee/Thread emitter/reciver but no so I search on Amazon for the dongle for Thread.\nAntenna I bought a Usb dongle13 for connecting the RaspberryPi and the other gadget in the house (for now only the Ikea one)\n13\nThis antenna is a little special: you can flash it for changing it form Zigbee to Thread and vice versa so I start to config it.\nSetup the Antenna First I flash the antenna. I need to port from Zigbee to Thread14 and with the online tool it was so easy I thought I did something wrong.\nAfter this I connect the dongle and start to config the Home Assistant.\nFirst I need to have installed Thread from \u0026ldquo;Add Integration\u0026rdquo; and it showed an empty list of device. This is correct because I didn\u0026rsquo;t have a Thread router installed.\nSo we add a OpenRouter. How? Installing from the officials app of mine Home Assistant.\nAfter this I edit the config in this way (the device was auto-finded) and I set this for my device. 15\nFor checking if all was ok I went and seach in the log for the OpenThread for a specific line.\nAfter this I went to check if the Thread integration showed the Ikea sensor and it didn\u0026rsquo;t show\u0026hellip; Why? Because I am STUPID.\nSetup the last little things Alpstuga (my air sensor) is not Thread, is Matter over Thread, so I need to add the thing with the Matter integration. And with this last integration the system worked!\nI am happy of this system? No. Why? I have the wrong time on the Alpstuga.\nThis thing I don\u0026rsquo;t understand so I search online for understand how can I fix the time on the device.\nI find this is a common problem with the Alpstuga device and someone made a Hacs16 plugin17 wich add a cron and a button for sync the Home Assistant\u0026rsquo;s clock. I also add the plugin for integrate my Playstation Network in my Home Assistant18.\nConclusion For now this is what I had done but I want to have automation (for now I don\u0026rsquo;t have any) and some stuff for lower the gas bill so there will be more post about my smart home.\nI pay a company to install it and I clean after.\u0026#160;\u0026#x21a9;\u0026#xfe0e;\nThread Standard\u0026nbsp;\u0026nbsp; \u0026#160;\u0026#x21a9;\u0026#xfe0e;\nZigbee Standard\u0026nbsp;\u0026nbsp; \u0026#160;\u0026#x21a9;\u0026#xfe0e;\nMatter Standard\u0026nbsp;\u0026nbsp; \u0026#160;\u0026#x21a9;\u0026#xfe0e;\nHome Assistant\u0026nbsp;\u0026nbsp; \u0026#160;\u0026#x21a9;\u0026#xfe0e;\u0026#160;\u0026#x21a9;\u0026#xfe0e;\nHome Assistant Matter\u0026nbsp;\u0026nbsp; \u0026#160;\u0026#x21a9;\u0026#xfe0e;\nHome Assistant Thread\u0026nbsp;\u0026nbsp; \u0026#160;\u0026#x21a9;\u0026#xfe0e;\nZigbee Home Automation\u0026nbsp;\u0026nbsp; \u0026#160;\u0026#x21a9;\u0026#xfe0e;\nRaspberryPi 4B\u0026nbsp;\u0026nbsp; \u0026#160;\u0026#x21a9;\u0026#xfe0e;\nRaspberry Pi 4B Case from Owootecc\u0026nbsp;\u0026nbsp; \u0026#160;\u0026#x21a9;\u0026#xfe0e;\nRaspberry Pi software\u0026nbsp;\u0026nbsp; \u0026#160;\u0026#x21a9;\u0026#xfe0e;\nIkea Alpstuga\u0026nbsp;\u0026nbsp; \u0026#160;\u0026#x21a9;\u0026#xfe0e;\nSONOFF Zigbee 3.0 USB Dongle Plus MG24\u0026nbsp;\u0026nbsp; \u0026#160;\u0026#x21a9;\u0026#xfe0e;\u0026#160;\u0026#x21a9;\u0026#xfe0e;\nSonoff dongle flasher/\u0026nbsp;\u0026nbsp; \u0026#160;\u0026#x21a9;\u0026#xfe0e;\nThis config work for me, it can not work for you\u0026#160;\u0026#x21a9;\u0026#xfe0e;\nHome Assistant Hacs\u0026nbsp;\u0026nbsp; \u0026#160;\u0026#x21a9;\u0026#xfe0e;\nMatter time synk\u0026nbsp;\u0026nbsp; \u0026#160;\u0026#x21a9;\u0026#xfe0e;\nPlayStation Network Home Assistant\u0026nbsp;\u0026nbsp; \u0026#160;\u0026#x21a9;\u0026#xfe0e;\n","image":"https://fundor333.com/post/2026/starting-my-home-automation-experiment/cover.png","banner_image":"https://fundor333.com/post/2026/starting-my-home-automation-experiment/cover.png"},{"title":"Why Do I Disinstall Poetry and Use Only Uv ","date_published":"2026-01-26T21:58:02+01:00","date_modified":"2026-07-16T22:49:21+02:00","id":"https://fundor333.com/post/2026/why-do-i-disinstall-poetry-and-use-only-uv-/","url":"https://fundor333.com/post/2026/why-do-i-disinstall-poetry-and-use-only-uv-/","tags":["poetry","pipenv","pyproject","pyenv","uv","makefile","make","precommit","dev","fingerfood"],"content_html":"\u003cp\u003e558 days ago (yes I count them), I wrote a follow-up article called \u003ca class=\"a-post interlink-script\" href=\"/post/2024/why-do-i-disinstall-pipenv-and-use-only-poetry/\"  \u003eWhy Do I Disinstall Pipenv and Use Only Poetry?\u003c/a\u003e\n and now I remake mine dev space, for building python project.\u003c/p\u003e\n\u003cp\u003eSome of the arguments are old, some are new but all come from my dev stack.\u003c/p\u003e\n\u003ch2 id=\"build-a-venv\" class=\"no-underline \"\u003e\n  \u003ca href=\"#build-a-venv\"\u003e\n    \u003ci class=\"fa-whiteboard fa-semibold fa-angle-right\"\u003e\u003c/i\u003e\n    Build a .venv\n  \u003c/a\u003e\n  \u003c/h2\u003e\n\u003cp\u003eFor every Python project I wrote, I code all the project with a Virtual Env or .venv.\nIt is a local \u0026ldquo;installation\u0026rdquo; of Python for the folder and it keep all the dependency inside it.\u003c/p\u003e\n\u003cp\u003eIt is the best way to develop python project because you can have any number of Python project, with different version of Python and/or different version of the dipendency for each project.\u003c/p\u003e\n\u003cp\u003eBecause I use git I need a good way to lock and commit the dipendency of my project. Some time ago I was using Poetry but now I use UV for build, update and manage the Virtual Env\u003c/p\u003e\n\u003cp\u003e\u003cimg  class=\"center-img u-photo \"  src=\"virtual-environment-make.jpg\" alt=\"virtual-environment-make.jpg\"\u003e\u003c/p\u003e\n\u003ch2 id=\"creating-a-env-file\" class=\"no-underline \"\u003e\n  \u003ca href=\"#creating-a-env-file\"\u003e\n    \u003ci class=\"fa-whiteboard fa-semibold fa-angle-right\"\u003e\u003c/i\u003e\n    Creating a .env file\n  \u003c/a\u003e\n  \u003c/h2\u003e\n\u003cp\u003eEvery python project I create, I always add a .env file, where I store all the environment variable for the project but I don\u0026rsquo;t add them to the repo because It is not necessary add the local config for dev in a repo.\u003c/p\u003e\n\u003cp\u003eYou can also automatically use the .env file in Uv so every time you are inside the .venv, you also have all the variables.\u003c/p\u003e\n\u003ch2 id=\"using-uv\" class=\"no-underline \"\u003e\n  \u003ca href=\"#using-uv\"\u003e\n    \u003ci class=\"fa-whiteboard fa-semibold fa-angle-right\"\u003e\u003c/i\u003e\n    Using UV\n  \u003c/a\u003e\n  \u003c/h2\u003e\n\u003cp\u003eSo after some time I was using Poetry and Pipenv, I find \u003ca class=\"a-post interlink-script\" href=\"https://github.com/astral-sh/uv\"   target=\"_blank\"\u003eUV\u0026nbsp;\u0026nbsp;\u003ci class=\"fa-whiteboard fa-semibold fa-link\"\u003e\u003c/i\u003e\u003c/a\u003e\n, a tool write in Rust for locking dipendnecy, set up and manage the .venv and create package for the publication in one tool.\u003c/p\u003e\n\u003cp\u003eYou can easly start a procjet with a simple command\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;\"\u003e\u003ccode class=\"language-bash\" data-lang=\"bash\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003euv init\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003cp\u003ewhich create the pyproject.toml and the .venv with all the dipendency.\u003c/p\u003e\n\u003cp\u003eWith some other command you can easily add, remove and update the dipendency or import in a easy way your .env file.\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;\"\u003e\u003ccode class=\"language-bash\" data-lang=\"bash\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003euv run --env-file\u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e.env\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003cp\u003eI move to UV because I can use a single tool for all my python necessity and it is faster and less bugged.\u003c/p\u003e\n\u003ch2 id=\"editor-config\" class=\"no-underline \"\u003e\n  \u003ca href=\"#editor-config\"\u003e\n    \u003ci class=\"fa-whiteboard fa-semibold fa-angle-right\"\u003e\u003c/i\u003e\n    Editor Config\n  \u003c/a\u003e\n  \u003c/h2\u003e\n\u003cp\u003eWe have the .venv, we have the .env, we have the dependency manager so I add the Editor Config file for the style of the code.\nThe \u003ca class=\"a-post interlink-script\" href=\"https://editorconfig.org/\"   target=\"_blank\"\u003eEditor Config file\u0026nbsp;\u0026nbsp;\u003ci class=\"fa-whiteboard fa-semibold fa-link\"\u003e\u003c/i\u003e\u003c/a\u003e\n is a file where you define the style for the type of file you write in your repo.\u003c/p\u003e\n\u003cp\u003eI have mine made year after year but I start with the \u003ca class=\"a-post interlink-script\" href=\"https://editorconfig.org/#example-file\"   target=\"_blank\"\u003eexample\u0026nbsp;\u0026nbsp;\u003ci class=\"fa-whiteboard fa-semibold fa-link\"\u003e\u003c/i\u003e\u003c/a\u003e\n in the site because it is easy and with all the stuff you need.\u003c/p\u003e\n\u003ch2 id=\"makefile-it\" class=\"no-underline \"\u003e\n  \u003ca href=\"#makefile-it\"\u003e\n    \u003ci class=\"fa-whiteboard fa-semibold fa-angle-right\"\u003e\u003c/i\u003e\n    Makefile it\n  \u003c/a\u003e\n  \u003c/h2\u003e\n\u003cp\u003eSo, after adding stuff over stuff to the repo, I add a makefile where yu have all the aliases for a python project, \u003csup id=\"fnref:1\"\u003e\u003ca href=\"#fn:1\" class=\"footnote-ref\" role=\"doc-noteref\"\u003e1\u003c/a\u003e\u003c/sup\u003e.\u003c/p\u003e\n\u003cp\u003eMy basic makefile is something like this\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;\"\u003e\u003ccode class=\"language-Makefile\" data-lang=\"Makefile\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eSHELL \u003cspan style=\"color:#f92672\"\u003e:=\u003c/span\u003e /bin/bash\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eRUNNER \u003cspan style=\"color:#f92672\"\u003e:=\u003c/span\u003e uv run --env-file\u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e.env\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#a6e22e\"\u003e.PHONY\u003c/span\u003e\u003cspan style=\"color:#f92672\"\u003e:\u003c/span\u003e help\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#a6e22e\"\u003ehelp\u003c/span\u003e\u003cspan style=\"color:#f92672\"\u003e:\u003c/span\u003e \u003cspan style=\"color:#75715e\"\u003e## Show this help\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t@egrep -h \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;\\s##\\s\u0026#39;\u003c/span\u003e \u003cspan style=\"color:#66d9ef\"\u003e$(\u003c/span\u003eMAKEFILE_LIST\u003cspan style=\"color:#66d9ef\"\u003e)\u003c/span\u003e | sort | awk \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;BEGIN {FS = \u0026#34;:.*?## \u0026#34;}; {printf \u0026#34;\\033[36m%-20s\\033[0m %s\\n\u0026#34;, $$1, $$2}\u0026#39;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#a6e22e\"\u003e.PHONY\u003c/span\u003e\u003cspan style=\"color:#f92672\"\u003e:\u003c/span\u003e install\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#a6e22e\"\u003einstall\u003c/span\u003e\u003cspan style=\"color:#f92672\"\u003e:\u003c/span\u003e \u003cspan style=\"color:#75715e\"\u003e## Make venv and install requirements\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t@uv sync\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t@\u003cspan style=\"color:#66d9ef\"\u003e$(\u003c/span\u003eRUNNER\u003cspan style=\"color:#66d9ef\"\u003e)\u003c/span\u003e pre-commit install\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t@pre-commit autoupdate\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#a6e22e\"\u003e.PHONY\u003c/span\u003e\u003cspan style=\"color:#f92672\"\u003e:\u003c/span\u003e update\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#a6e22e\"\u003eupdate\u003c/span\u003e\u003cspan style=\"color:#f92672\"\u003e:\u003c/span\u003e \u003cspan style=\"color:#75715e\"\u003e## Update requirements\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t@uv lock --upgrade\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t@\u003cspan style=\"color:#66d9ef\"\u003e$(\u003c/span\u003eRUNNER\u003cspan style=\"color:#66d9ef\"\u003e)\u003c/span\u003e pre-commit autoupdate\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#a6e22e\"\u003eprecommit\u003c/span\u003e\u003cspan style=\"color:#f92672\"\u003e:\u003c/span\u003e \u003cspan style=\"color:#75715e\"\u003e## Run pre-commit hooks\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t@git add . \u0026amp; uv run --env-file\u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e.env pre-commit run --all-files\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003cp\u003eThe help command come form a blog post\u003csup id=\"fnref:2\"\u003e\u003ca href=\"#fn:2\" class=\"footnote-ref\" role=\"doc-noteref\"\u003e2\u003c/a\u003e\u003c/sup\u003e and describe better at my other post\u003csup id=\"fnref:3\"\u003e\u003ca href=\"#fn:3\" class=\"footnote-ref\" role=\"doc-noteref\"\u003e3\u003c/a\u003e\u003c/sup\u003e\u003c/p\u003e\n\u003cp\u003eI write a makefile for all my project because I forgot a lot of the command and parameters, so a makefile is a good way to have an \u0026ldquo;deploy\u0026rdquo; command or a \u0026ldquo;test\u0026rdquo; command for the project and forgot all the task needed for run a \u0026ldquo;test\u0026rdquo; or a \u0026ldquo;deploy\u0026rdquo;.\u003c/p\u003e\n\u003cp\u003eI also put all the test command into the makefile because sometime the test command is too long to remember\u0026hellip;\u003c/p\u003e\n\u003ch2 id=\"pre-commit-and-some-automation\" class=\"no-underline \"\u003e\n  \u003ca href=\"#pre-commit-and-some-automation\"\u003e\n    \u003ci class=\"fa-whiteboard fa-semibold fa-angle-right\"\u003e\u003c/i\u003e\n    Pre commit and some automation\n  \u003c/a\u003e\n  \u003c/h2\u003e\n\u003cp\u003eThis is my personal safety net for the commits. Some time I wrote and push without any work or thing about what I am doing\u0026hellip; For this reason I add pre-commit\u003csup id=\"fnref:4\"\u003e\u003ca href=\"#fn:4\" class=\"footnote-ref\" role=\"doc-noteref\"\u003e4\u003c/a\u003e\u003c/sup\u003e for autofix and check all this minor error.\u003c/p\u003e\n\u003cp\u003e\u003cimg  class=\"center-img u-photo \"  src=\"cox.gif\" alt=\"cox.gif\"\u003e\u003c/p\u003e\n\u003cp\u003eThe took launch a lot of test BEFORE I can save the commit so I can find the error or getting a big fat NOPE for the commit, which I need to review for the problem.\u003c/p\u003e\n\u003ch2 id=\"conclusion\" class=\"no-underline \"\u003e\n  \u003ca href=\"#conclusion\"\u003e\n    \u003ci class=\"fa-whiteboard fa-semibold fa-angle-right\"\u003e\u003c/i\u003e\n    Conclusion\n  \u003c/a\u003e\n  \u003c/h2\u003e\n\u003cp\u003eThis is the stack I work with and I love it. It can be something custom and old style for some of the older tecnology but I find it complete for what I do.\u003c/p\u003e\n\u003cdiv class=\"footnotes\" role=\"doc-endnotes\"\u003e\n\u003chr\u003e\n\u003col\u003e\n\u003cli id=\"fn:1\"\u003e\n\u003cp\u003eI wrote an article about makefile caller \u003ca class=\"a-post interlink-script\" href=\"https://fundor333.com/post/2021/the-team-makefile/\"   target=\"_blank\"\u003eThe Team Makefile\u0026nbsp;\u0026nbsp;\u003ci class=\"fa-whiteboard fa-semibold fa-link\"\u003e\u003c/i\u003e\u003c/a\u003e\n\u0026#160;\u003ca href=\"#fnref:1\" class=\"footnote-backref\" role=\"doc-backlink\"\u003e\u0026#x21a9;\u0026#xfe0e;\u003c/a\u003e\u003c/p\u003e\n\u003c/li\u003e\n\u003cli id=\"fn:2\"\u003e\n\u003cp\u003e\u003ca class=\"a-post interlink-script\" href=\"https://victoria.dev/archive/how-to-create-a-self-documenting-makefile/\"   target=\"_blank\"\u003eHow to create a self-documenting Makefile\u0026nbsp;\u0026nbsp;\u003ci class=\"fa-whiteboard fa-semibold fa-link\"\u003e\u003c/i\u003e\u003c/a\u003e\n\u0026#160;\u003ca href=\"#fnref:2\" class=\"footnote-backref\" role=\"doc-backlink\"\u003e\u0026#x21a9;\u0026#xfe0e;\u003c/a\u003e\u003c/p\u003e\n\u003c/li\u003e\n\u003cli id=\"fn:3\"\u003e\n\u003cp\u003e\u003ca class=\"a-post interlink-script\" href=\"https://fundor333.com/post/2021/the-team-makefile/\"   target=\"_blank\"\u003eThe Team Makefile\u0026nbsp;\u0026nbsp;\u003ci class=\"fa-whiteboard fa-semibold fa-link\"\u003e\u003c/i\u003e\u003c/a\u003e\n\u0026#160;\u003ca href=\"#fnref:3\" class=\"footnote-backref\" role=\"doc-backlink\"\u003e\u0026#x21a9;\u0026#xfe0e;\u003c/a\u003e\u003c/p\u003e\n\u003c/li\u003e\n\u003cli id=\"fn:4\"\u003e\n\u003cp\u003e\u003ca class=\"a-post interlink-script\" href=\"https://praful932.dev/blog-2-pre-commit-hooks/\"   target=\"_blank\"\u003eUsing pre-commit hooks to write better code\u0026nbsp;\u0026nbsp;\u003ci class=\"fa-whiteboard fa-semibold fa-link\"\u003e\u003c/i\u003e\u003c/a\u003e\n\u0026#160;\u003ca href=\"#fnref:4\" class=\"footnote-backref\" role=\"doc-backlink\"\u003e\u0026#x21a9;\u0026#xfe0e;\u003c/a\u003e\u003c/p\u003e\n\u003c/li\u003e\n\u003c/ol\u003e\n\u003c/div\u003e\n","content_text":"558 days ago (yes I count them), I wrote a follow-up article called Why Do I Disinstall Pipenv and Use Only Poetry? and now I remake mine dev space, for building python project.\nSome of the arguments are old, some are new but all come from my dev stack.\nBuild a .venv For every Python project I wrote, I code all the project with a Virtual Env or .venv. It is a local \u0026ldquo;installation\u0026rdquo; of Python for the folder and it keep all the dependency inside it.\nIt is the best way to develop python project because you can have any number of Python project, with different version of Python and/or different version of the dipendency for each project.\nBecause I use git I need a good way to lock and commit the dipendency of my project. Some time ago I was using Poetry but now I use UV for build, update and manage the Virtual Env\nCreating a .env file Every python project I create, I always add a .env file, where I store all the environment variable for the project but I don\u0026rsquo;t add them to the repo because It is not necessary add the local config for dev in a repo.\nYou can also automatically use the .env file in Uv so every time you are inside the .venv, you also have all the variables.\nUsing UV So after some time I was using Poetry and Pipenv, I find UV\u0026nbsp;\u0026nbsp; , a tool write in Rust for locking dipendnecy, set up and manage the .venv and create package for the publication in one tool.\nYou can easly start a procjet with a simple command\nuv init which create the pyproject.toml and the .venv with all the dipendency.\nWith some other command you can easily add, remove and update the dipendency or import in a easy way your .env file.\nuv run --env-file=.env I move to UV because I can use a single tool for all my python necessity and it is faster and less bugged.\nEditor Config We have the .venv, we have the .env, we have the dependency manager so I add the Editor Config file for the style of the code. The Editor Config file\u0026nbsp;\u0026nbsp; is a file where you define the style for the type of file you write in your repo.\nI have mine made year after year but I start with the example\u0026nbsp;\u0026nbsp; in the site because it is easy and with all the stuff you need.\nMakefile it So, after adding stuff over stuff to the repo, I add a makefile where yu have all the aliases for a python project, 1.\nMy basic makefile is something like this\nSHELL := /bin/bash RUNNER := uv run --env-file=.env .PHONY: help help: ## Show this help @egrep -h \u0026#39;\\s##\\s\u0026#39; $(MAKEFILE_LIST) | sort | awk \u0026#39;BEGIN {FS = \u0026#34;:.*?## \u0026#34;}; {printf \u0026#34;\\033[36m%-20s\\033[0m %s\\n\u0026#34;, $$1, $$2}\u0026#39; .PHONY: install install: ## Make venv and install requirements @uv sync @$(RUNNER) pre-commit install @pre-commit autoupdate .PHONY: update update: ## Update requirements @uv lock --upgrade @$(RUNNER) pre-commit autoupdate precommit: ## Run pre-commit hooks @git add . \u0026amp; uv run --env-file=.env pre-commit run --all-files The help command come form a blog post2 and describe better at my other post3\nI write a makefile for all my project because I forgot a lot of the command and parameters, so a makefile is a good way to have an \u0026ldquo;deploy\u0026rdquo; command or a \u0026ldquo;test\u0026rdquo; command for the project and forgot all the task needed for run a \u0026ldquo;test\u0026rdquo; or a \u0026ldquo;deploy\u0026rdquo;.\nI also put all the test command into the makefile because sometime the test command is too long to remember\u0026hellip;\nPre commit and some automation This is my personal safety net for the commits. Some time I wrote and push without any work or thing about what I am doing\u0026hellip; For this reason I add pre-commit4 for autofix and check all this minor error.\nThe took launch a lot of test BEFORE I can save the commit so I can find the error or getting a big fat NOPE for the commit, which I need to review for the problem.\nConclusion This is the stack I work with and I love it. It can be something custom and old style for some of the older tecnology but I find it complete for what I do.\nI wrote an article about makefile caller The Team Makefile\u0026nbsp;\u0026nbsp; \u0026#160;\u0026#x21a9;\u0026#xfe0e;\nHow to create a self-documenting Makefile\u0026nbsp;\u0026nbsp; \u0026#160;\u0026#x21a9;\u0026#xfe0e;\nThe Team Makefile\u0026nbsp;\u0026nbsp; \u0026#160;\u0026#x21a9;\u0026#xfe0e;\nUsing pre-commit hooks to write better code\u0026nbsp;\u0026nbsp; \u0026#160;\u0026#x21a9;\u0026#xfe0e;\n","image":"https://fundor333.com/post/2026/why-do-i-disinstall-poetry-and-use-only-uv-/cover.png","banner_image":"https://fundor333.com/post/2026/why-do-i-disinstall-poetry-and-use-only-uv-/cover.png"},{"title":"Htmx Django and Django Table2","date_published":"2026-01-19T12:33:09+01:00","date_modified":"2026-07-16T22:49:21+02:00","id":"https://fundor333.com/post/2026/htmx-django-and-django-table2/","url":"https://fundor333.com/post/2026/htmx-django-and-django-table2/","tags":["django","htmx","django-table2","montharchiveview","rant","dev"],"content_html":"\u003cp\u003eFor some time I am developing my personal Django server. It keeps some data for me and it is my automation server. And I want to test a Htmx code on Django so I make a little thing in my personal django project.\u003c/p\u003e\n\u003ch2 id=\"what-i-have\" class=\"no-underline \"\u003e\n  \u003ca href=\"#what-i-have\"\u003e\n    \u003ci class=\"fa-whiteboard fa-semibold fa-angle-right\"\u003e\u003c/i\u003e\n    What I have\n  \u003c/a\u003e\n  \u003c/h2\u003e\n\u003cp\u003eI have a MonthArchiveView with render a table list with a lot of function I need: add element, change month show, exports query as files, etc\u0026hellip;\u003c/p\u003e\n\u003cp\u003eI also don\u0026rsquo;t like to reload all the page for change the month I am seeing on the page.\nSo I start to implement what I need.\u003c/p\u003e\n\u003cp\u003eAnd, from some comment from the web and some friends, I want less code and more clean one.\u003c/p\u003e\n\u003ch2 id=\"what-i-used\" class=\"no-underline \"\u003e\n  \u003ca href=\"#what-i-used\"\u003e\n    \u003ci class=\"fa-whiteboard fa-semibold fa-angle-right\"\u003e\u003c/i\u003e\n    What I used\n  \u003c/a\u003e\n  \u003c/h2\u003e\n\u003cp\u003eFor this project I used:\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e\u003cstrong\u003eDjango\u003c/strong\u003e the framework used\u003csup id=\"fnref:1\"\u003e\u003ca href=\"#fn:1\" class=\"footnote-ref\" role=\"doc-noteref\"\u003e1\u003c/a\u003e\u003c/sup\u003e\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003eDjango Table2\u003c/strong\u003e a module for easy creation of table for Django\u003csup id=\"fnref:2\"\u003e\u003ca href=\"#fn:2\" class=\"footnote-ref\" role=\"doc-noteref\"\u003e2\u003c/a\u003e\u003c/sup\u003e\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003eDjango Htmx\u003c/strong\u003e a module for easy support of Htmx\u003csup id=\"fnref:3\"\u003e\u003ca href=\"#fn:3\" class=\"footnote-ref\" role=\"doc-noteref\"\u003e3\u003c/a\u003e\u003c/sup\u003e\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003eTablib\u003c/strong\u003e a module for exporting the table as multiple file type\u003csup id=\"fnref:4\"\u003e\u003ca href=\"#fn:4\" class=\"footnote-ref\" role=\"doc-noteref\"\u003e4\u003c/a\u003e\u003c/sup\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch3 id=\"the-py-code\" class=\"no-underline \"\u003e\n  \u003ca href=\"#the-py-code\"\u003e\n    \u003ci class=\"fa-whiteboard fa-semibold fa-angle-right\"\u003e\u003c/i\u003e\u003ci class=\"fa-whiteboard fa-semibold fa-angle-right\"\u003e\u003c/i\u003e\n    The Py code\n  \u003c/a\u003e\n  \u003c/h3\u003e\n\u003cp\u003eSo I start with the code for the model. It need to have a DateTimeField or a DateField (this becose I want to have an MonthArchiveView view).\u003c/p\u003e\n\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;\"\u003e\u003ccode class=\"language-python\" data-lang=\"python\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# blog/model.py\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#66d9ef\"\u003eclass\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003ePost\u003c/span\u003e(models\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003eModel):\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    title \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e models\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003eCharField(max_length\u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#ae81ff\"\u003e400\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    slug \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e models\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003eSlugField(max_length\u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#ae81ff\"\u003e400\u003c/span\u003e, unique\u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#66d9ef\"\u003eTrue\u003c/span\u003e, blank\u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#66d9ef\"\u003eTrue\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    content \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e models\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003eTextAreaField()\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    date \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e models\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003eDateTimeField(auto_now_add\u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#66d9ef\"\u003eTrue\u003c/span\u003e)\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003eand after I add the code for the table with the ordering of the data\u003c/p\u003e\n\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;\"\u003e\u003ccode class=\"language-python\" data-lang=\"python\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# blog/tables.py\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#f92672\"\u003eimport\u003c/span\u003e django_tables2 \u003cspan style=\"color:#66d9ef\"\u003eas\u003c/span\u003e tables\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#f92672\"\u003efrom\u003c/span\u003e blog.models \u003cspan style=\"color:#f92672\"\u003eimport\u003c/span\u003e Post\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#66d9ef\"\u003eclass\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003ePostTable\u003c/span\u003e(tables\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003eTable):\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003eclass\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003eMeta\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        model \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e Post\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        order_by \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e (\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;-date\u0026#34;\u003c/span\u003e, \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;title\u0026#34;\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        fields \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e [\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;date\u0026#34;\u003c/span\u003e, \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;title\u0026#34;\u003c/span\u003e, \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;slug\u0026#34;\u003c/span\u003e]\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003eAfter the model and the table we need the view called by the HTMX code.\u003c/p\u003e\n\u003cp\u003eI set all the config for choose the right data field and which is the format for month and year, followed for the export types\u0026rsquo; settings.\u003c/p\u003e\n\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;\"\u003e\u003ccode class=\"language-python\" data-lang=\"python\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# blog/views.py\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#f92672\"\u003efrom\u003c/span\u003e django.views.generic \u003cspan style=\"color:#f92672\"\u003eimport\u003c/span\u003e ListView\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#f92672\"\u003efrom\u003c/span\u003e django.contrib.auth.mixins \u003cspan style=\"color:#f92672\"\u003eimport\u003c/span\u003e LoginRequiredMixin\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#f92672\"\u003efrom\u003c/span\u003e django_tables2 \u003cspan style=\"color:#f92672\"\u003eimport\u003c/span\u003e SingleTableView, tables\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#f92672\"\u003efrom\u003c/span\u003e blog.models \u003cspan style=\"color:#f92672\"\u003eimport\u003c/span\u003e Post\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#f92672\"\u003efrom\u003c/span\u003e blog.tables \u003cspan style=\"color:#f92672\"\u003eimport\u003c/span\u003e PostTable\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#66d9ef\"\u003eclass\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003ePostMonthArchiveHtmx\u003c/span\u003e(LoginRequiredMixin, ExportMixin, SingleTableMixin, MonthArchiveView):\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    model \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e Post\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    template_name \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;generic/table2_with_export.html\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    table_class \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e PostTable\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    date_field \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;date\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    allow_future \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#66d9ef\"\u003eTrue\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    month_format \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;%m\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    year_format \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;%Y\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    allow_empty \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#66d9ef\"\u003eTrue\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    export_formats \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e (\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    TableExport\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003eCSV,\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    TableExport\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003eXLS,\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    TableExport\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003eXLSX,\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    TableExport\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003eODS,)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003edef\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003eget_month\u003c/span\u003e(self):\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#66d9ef\"\u003etry\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            month \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e super()\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003eget_month()\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#66d9ef\"\u003eexcept\u003c/span\u003e Http404:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            month \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e now()\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003estrftime(self\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003eget_month_format())\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#66d9ef\"\u003ereturn\u003c/span\u003e month\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003edef\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003eget_year\u003c/span\u003e(self):\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#66d9ef\"\u003etry\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            year \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e super()\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003eget_year()\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#66d9ef\"\u003eexcept\u003c/span\u003e Http404:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            year \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e now()\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003estrftime(self\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003eget_year_format())\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#66d9ef\"\u003ereturn\u003c/span\u003e year\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003edef\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003eget_export_filename\u003c/span\u003e(self, export_format):\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#66d9ef\"\u003ereturn\u003c/span\u003e \u003cspan style=\"color:#e6db74\"\u003ef\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;Export Post \u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e{\u003c/span\u003eself\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003eget_year()\u003cspan style=\"color:#e6db74\"\u003e}\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e-\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e{\u003c/span\u003eself\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003eget_month()\u003cspan style=\"color:#e6db74\"\u003e}\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e.\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e{\u003c/span\u003eexport_format\u003cspan style=\"color:#e6db74\"\u003e}\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003eI added a function for changing the name of the output file (because I like filename with date reference) and two functions for setting month and year if not given (we need them later for the Htmx part).\u003c/p\u003e\n\u003ch3 id=\"the-jinja-part\" class=\"no-underline \"\u003e\n  \u003ca href=\"#the-jinja-part\"\u003e\n    \u003ci class=\"fa-whiteboard fa-semibold fa-angle-right\"\u003e\u003c/i\u003e\u003ci class=\"fa-whiteboard fa-semibold fa-angle-right\"\u003e\u003c/i\u003e\n    The Jinja part\n  \u003c/a\u003e\n  \u003c/h3\u003e\n\u003cp\u003eAfter the python code I wrote this generic template for all my django-table2 table (in this case with the export code)\u003c/p\u003e\n\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;\"\u003e\u003ccode class=\"language-django\" data-lang=\"django\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e# templates/generic/table2_with_export.html\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e{%\u003c/span\u003e \u003cspan style=\"color:#66d9ef\"\u003eload\u003c/span\u003e render_table from django_tables2 \u003cspan style=\"color:#75715e\"\u003e%}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e{%\u003c/span\u003e \u003cspan style=\"color:#66d9ef\"\u003eload\u003c/span\u003e export_url from django_tables2 \u003cspan style=\"color:#75715e\"\u003e%}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u0026lt;div\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#75715e\"\u003e{%\u003c/span\u003e \u003cspan style=\"color:#66d9ef\"\u003efor\u003c/span\u003e format \u003cspan style=\"color:#66d9ef\"\u003ein\u003c/span\u003e view.export_formats \u003cspan style=\"color:#75715e\"\u003e%}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u0026lt;a href=\u0026#34;\u003cspan style=\"color:#75715e\"\u003e{{\u003c/span\u003e request.path \u003cspan style=\"color:#75715e\"\u003e}}{%\u003c/span\u003e \u003cspan style=\"color:#66d9ef\"\u003eexport_url\u003c/span\u003e format \u003cspan style=\"color:#75715e\"\u003e%}\u003c/span\u003e\u0026#34; target=\u0026#34;_blank\u0026#34;\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u0026lt;code\u0026gt;\u003cspan style=\"color:#75715e\"\u003e{{\u003c/span\u003e format \u003cspan style=\"color:#75715e\"\u003e}}\u003c/span\u003e\u0026lt;/code\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u0026lt;/a\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#75715e\"\u003e{%\u003c/span\u003e \u003cspan style=\"color:#66d9ef\"\u003eendfor\u003c/span\u003e \u003cspan style=\"color:#75715e\"\u003e%}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u0026lt;hr\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#75715e\"\u003e{%\u003c/span\u003e \u003cspan style=\"color:#66d9ef\"\u003erender_table\u003c/span\u003e table \u003cspan style=\"color:#75715e\"\u003e%}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u0026lt;/div\u0026gt;\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003eI take out all the css stuff so you can add your style and/or css classes.\u003c/p\u003e\n\u003cp\u003eAt this point we have all we need to have a html page with the table and the exports we need. We only need to add this view into the urls\u0026hellip;\u003c/p\u003e\n\u003cp\u003eFor example this is a generic example for a urls file for this project\u003c/p\u003e\n\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;\"\u003e\u003ccode class=\"language-python\" data-lang=\"python\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# blog/urls.py\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#f92672\"\u003efrom\u003c/span\u003e django.urls \u003cspan style=\"color:#f92672\"\u003eimport\u003c/span\u003e path\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#f92672\"\u003efrom\u003c/span\u003e blog.views \u003cspan style=\"color:#f92672\"\u003eimport\u003c/span\u003e (\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    PostMonthArchiveHtmx,\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eapp_name \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;blog\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eurlpatterns \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e [\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    path(\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;htmx/post\u0026#34;\u003c/span\u003e, PostMonthArchiveHtmx\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003eas_view(month_format\u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;%m\u0026#34;\u003c/span\u003e,name\u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;htmx-post\u0026#34;\u003c/span\u003e)),\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e]\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003eYou can see that I didn\u0026rsquo;t add the code for having the month and the year in the url. This is because I had a lot of problems with the next part and this is the cleanest way I found to code this.\u003c/p\u003e\n\u003ch3 id=\"the-htmx-fragment\" class=\"no-underline \"\u003e\n  \u003ca href=\"#the-htmx-fragment\"\u003e\n    \u003ci class=\"fa-whiteboard fa-semibold fa-angle-right\"\u003e\u003c/i\u003e\u003ci class=\"fa-whiteboard fa-semibold fa-angle-right\"\u003e\u003c/i\u003e\n    The Htmx fragment\n  \u003c/a\u003e\n  \u003c/h3\u003e\n\u003cp\u003eI will assume that you have done the quickstart form Htmx\u0026rsquo;s site\u003csup id=\"fnref:5\"\u003e\u003ca href=\"#fn:5\" class=\"footnote-ref\" role=\"doc-noteref\"\u003e5\u003c/a\u003e\u003c/sup\u003e because I don\u0026rsquo;t want to write about Htmx\u0026hellip;\u003c/p\u003e\n\u003cp\u003eSo for using inside a Django project for calling the page with Htmx we need to add the csrf token inside the header of the request so I added inside the main tag for my project.\u003c/p\u003e\n\u003cp\u003eIt resembles this fragment.\u003c/p\u003e\n\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;\"\u003e\u003ccode class=\"language-html\" data-lang=\"html\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e\u0026lt;!-- template/base.html --\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e\u0026lt;!-- Other part of the template--\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u0026lt;\u003cspan style=\"color:#f92672\"\u003ediv\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003ehx-headers\u003c/span\u003e\u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;{\u0026#34;x-csrftoken\u0026#34;: \u0026#34;{{ csrf_token }}\u0026#34;}\u0026#39;\u003c/span\u003e\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  {% block content %}\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    (no content)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  {% endblock %}\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u0026lt;/\u003cspan style=\"color:#f92672\"\u003ediv\u003c/span\u003e\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e\u0026lt;!-- Other part of the template--\u0026gt;\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003eSo now I need to write the div for the Htmx. And this is what I wrote:\u003c/p\u003e\n\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;\"\u003e\u003ccode class=\"language-html\" data-lang=\"html\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u0026lt;\u003cspan style=\"color:#f92672\"\u003ediv\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003ehx-get\u003c/span\u003e\u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;{% url \u0026#39;blog:htmx-post\u0026#39; %}?year={{ month|date:\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#a6e22e\"\u003eY\u003c/span\u003e\u003cspan style=\"color:#960050;background-color:#1e0010\"\u003e\u0026#34;\u003c/span\u003e \u003cspan style=\"color:#960050;background-color:#1e0010\"\u003e}}\u0026amp;\u003c/span\u003e\u003cspan style=\"color:#a6e22e\"\u003emonth\u003c/span\u003e\u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e{{\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003emonth\u003c/span\u003e\u003cspan style=\"color:#960050;background-color:#1e0010\"\u003e|\u003c/span\u003e\u003cspan style=\"color:#a6e22e\"\u003edate:\u003c/span\u003e\u003cspan style=\"color:#960050;background-color:#1e0010\"\u003e\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#a6e22e\"\u003em\u003c/span\u003e\u003cspan style=\"color:#960050;background-color:#1e0010\"\u003e\u0026#34;\u003c/span\u003e \u003cspan style=\"color:#960050;background-color:#1e0010\"\u003e}}\u0026amp;{{\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003erequest\u003c/span\u003e\u003cspan style=\"color:#960050;background-color:#1e0010\"\u003e.\u003c/span\u003e\u003cspan style=\"color:#a6e22e\"\u003eGET\u003c/span\u003e\u003cspan style=\"color:#960050;background-color:#1e0010\"\u003e.\u003c/span\u003e\u003cspan style=\"color:#a6e22e\"\u003eurlencode\u003c/span\u003e \u003cspan style=\"color:#960050;background-color:#1e0010\"\u003e}}\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e     \u003cspan style=\"color:#a6e22e\"\u003ehx-trigger\u003c/span\u003e\u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;load\u0026#34;\u003c/span\u003e\u0026gt;This will be replaced.\u0026lt;/\u003cspan style=\"color:#f92672\"\u003ediv\u003c/span\u003e\u0026gt;\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003eI build the url in the hx-get in a strange way because I need to add the query input for the MonthArchiveView (the \u0026amp;month and \u0026amp;year field in the url) and add all the other field. In this way I also have the sorting links in the header of the table working.\u003c/p\u003e\n\u003ch2 id=\"conclusion\" class=\"no-underline \"\u003e\n  \u003ca href=\"#conclusion\"\u003e\n    \u003ci class=\"fa-whiteboard fa-semibold fa-angle-right\"\u003e\u003c/i\u003e\n    Conclusion\n  \u003c/a\u003e\n  \u003c/h2\u003e\n\u003cp\u003eThis is how I have combine this 3 libs for my personal project and if you find it useful share it. Thanks!\u003c/p\u003e\n\u003cdiv class=\"footnotes\" role=\"doc-endnotes\"\u003e\n\u003chr\u003e\n\u003col\u003e\n\u003cli id=\"fn:1\"\u003e\n\u003cp\u003e\u003ca class=\"a-post interlink-script\" href=\"https://www.djangoproject.com/\"   target=\"_blank\"\u003eDjango is a high-level Python web framework that encourages rapid development and clean, pragmatic design. Built by experienced developers, it takes care of much of the hassle of web development, so you can focus on writing your app without needing to reinvent the wheel. It’s free and open source\u0026nbsp;\u0026nbsp;\u003ci class=\"fa-whiteboard fa-semibold fa-link\"\u003e\u003c/i\u003e\u003c/a\u003e\n\u0026#160;\u003ca href=\"#fnref:1\" class=\"footnote-backref\" role=\"doc-backlink\"\u003e\u0026#x21a9;\u0026#xfe0e;\u003c/a\u003e\u003c/p\u003e\n\u003c/li\u003e\n\u003cli id=\"fn:2\"\u003e\n\u003cp\u003e\u003ca class=\"a-post interlink-script\" href=\"https://github.com/jieter/django-tables2\"   target=\"_blank\"\u003edjango-tables2 - An app for creating HTML tables\u0026nbsp;\u0026nbsp;\u003ci class=\"fa-whiteboard fa-semibold fa-link\"\u003e\u003c/i\u003e\u003c/a\u003e\n\u0026#160;\u003ca href=\"#fnref:2\" class=\"footnote-backref\" role=\"doc-backlink\"\u003e\u0026#x21a9;\u0026#xfe0e;\u003c/a\u003e\u003c/p\u003e\n\u003c/li\u003e\n\u003cli id=\"fn:3\"\u003e\n\u003cp\u003e\u003ca class=\"a-post interlink-script\" href=\"https://pypi.org/project/django-htmx/\"   target=\"_blank\"\u003edjango-htmx Extensions for using Django with htmx\u0026nbsp;\u0026nbsp;\u003ci class=\"fa-whiteboard fa-semibold fa-link\"\u003e\u003c/i\u003e\u003c/a\u003e\n\u0026#160;\u003ca href=\"#fnref:3\" class=\"footnote-backref\" role=\"doc-backlink\"\u003e\u0026#x21a9;\u0026#xfe0e;\u003c/a\u003e\u003c/p\u003e\n\u003c/li\u003e\n\u003cli id=\"fn:4\"\u003e\n\u003cp\u003e\u003ca class=\"a-post interlink-script\" href=\"https://pypi.org/project/tablib/\"   target=\"_blank\"\u003eTablib: format-agnostic tabular dataset library\u0026nbsp;\u0026nbsp;\u003ci class=\"fa-whiteboard fa-semibold fa-link\"\u003e\u003c/i\u003e\u003c/a\u003e\n\u0026#160;\u003ca href=\"#fnref:4\" class=\"footnote-backref\" role=\"doc-backlink\"\u003e\u0026#x21a9;\u0026#xfe0e;\u003c/a\u003e\u003c/p\u003e\n\u003c/li\u003e\n\u003cli id=\"fn:5\"\u003e\n\u003cp\u003e\u003ca class=\"a-post interlink-script\" href=\"https://htmx.org/docs/#introduction\"   target=\"_blank\"\u003ehtmx in a Nutshell\u0026nbsp;\u0026nbsp;\u003ci class=\"fa-whiteboard fa-semibold fa-link\"\u003e\u003c/i\u003e\u003c/a\u003e\n\u0026#160;\u003ca href=\"#fnref:5\" class=\"footnote-backref\" role=\"doc-backlink\"\u003e\u0026#x21a9;\u0026#xfe0e;\u003c/a\u003e\u003c/p\u003e\n\u003c/li\u003e\n\u003c/ol\u003e\n\u003c/div\u003e\n","content_text":"For some time I am developing my personal Django server. It keeps some data for me and it is my automation server. And I want to test a Htmx code on Django so I make a little thing in my personal django project.\nWhat I have I have a MonthArchiveView with render a table list with a lot of function I need: add element, change month show, exports query as files, etc\u0026hellip;\nI also don\u0026rsquo;t like to reload all the page for change the month I am seeing on the page. So I start to implement what I need.\nAnd, from some comment from the web and some friends, I want less code and more clean one.\nWhat I used For this project I used:\nDjango the framework used1 Django Table2 a module for easy creation of table for Django2 Django Htmx a module for easy support of Htmx3 Tablib a module for exporting the table as multiple file type4 The Py code So I start with the code for the model. It need to have a DateTimeField or a DateField (this becose I want to have an MonthArchiveView view).\n# blog/model.py class Post(models.Model): title = models.CharField(max_length=400) slug = models.SlugField(max_length=400, unique=True, blank=True) content = models.TextAreaField() date = models.DateTimeField(auto_now_add=True)and after I add the code for the table with the ordering of the data\n# blog/tables.py import django_tables2 as tables from blog.models import Post class PostTable(tables.Table): class Meta: model = Post order_by = (\u0026#34;-date\u0026#34;, \u0026#34;title\u0026#34;) fields = [\u0026#34;date\u0026#34;, \u0026#34;title\u0026#34;, \u0026#34;slug\u0026#34;]After the model and the table we need the view called by the HTMX code.\nI set all the config for choose the right data field and which is the format for month and year, followed for the export types\u0026rsquo; settings.\n# blog/views.py from django.views.generic import ListView from django.contrib.auth.mixins import LoginRequiredMixin from django_tables2 import SingleTableView, tables from blog.models import Post from blog.tables import PostTable class PostMonthArchiveHtmx(LoginRequiredMixin, ExportMixin, SingleTableMixin, MonthArchiveView): model = Post template_name = \u0026#34;generic/table2_with_export.html\u0026#34; table_class = PostTable date_field = \u0026#34;date\u0026#34; allow_future = True month_format = \u0026#34;%m\u0026#34; year_format = \u0026#34;%Y\u0026#34; allow_empty = True export_formats = ( TableExport.CSV, TableExport.XLS, TableExport.XLSX, TableExport.ODS,) def get_month(self): try: month = super().get_month() except Http404: month = now().strftime(self.get_month_format()) return month def get_year(self): try: year = super().get_year() except Http404: year = now().strftime(self.get_year_format()) return year def get_export_filename(self, export_format): return f\u0026#34;Export Post {self.get_year()}-{self.get_month()}.{export_format}\u0026#34;I added a function for changing the name of the output file (because I like filename with date reference) and two functions for setting month and year if not given (we need them later for the Htmx part).\nThe Jinja part After the python code I wrote this generic template for all my django-table2 table (in this case with the export code)\n# templates/generic/table2_with_export.html {% load render_table from django_tables2 %} {% load export_url from django_tables2 %} \u0026lt;div\u0026gt; {% for format in view.export_formats %} \u0026lt;a href=\u0026#34;{{ request.path }}{% export_url format %}\u0026#34; target=\u0026#34;_blank\u0026#34;\u0026gt; \u0026lt;code\u0026gt;{{ format }}\u0026lt;/code\u0026gt; \u0026lt;/a\u0026gt; {% endfor %} \u0026lt;hr\u0026gt; {% render_table table %} \u0026lt;/div\u0026gt;I take out all the css stuff so you can add your style and/or css classes.\nAt this point we have all we need to have a html page with the table and the exports we need. We only need to add this view into the urls\u0026hellip;\nFor example this is a generic example for a urls file for this project\n# blog/urls.py from django.urls import path from blog.views import ( PostMonthArchiveHtmx, ) app_name = \u0026#34;blog\u0026#34; urlpatterns = [ path(\u0026#34;htmx/post\u0026#34;, PostMonthArchiveHtmx.as_view(month_format=\u0026#34;%m\u0026#34;,name=\u0026#34;htmx-post\u0026#34;)), ]You can see that I didn\u0026rsquo;t add the code for having the month and the year in the url. This is because I had a lot of problems with the next part and this is the cleanest way I found to code this.\nThe Htmx fragment I will assume that you have done the quickstart form Htmx\u0026rsquo;s site5 because I don\u0026rsquo;t want to write about Htmx\u0026hellip;\nSo for using inside a Django project for calling the page with Htmx we need to add the csrf token inside the header of the request so I added inside the main tag for my project.\nIt resembles this fragment.\n\u0026lt;!-- template/base.html --\u0026gt; \u0026lt;!-- Other part of the template--\u0026gt; \u0026lt;div hx-headers=\u0026#39;{\u0026#34;x-csrftoken\u0026#34;: \u0026#34;{{ csrf_token }}\u0026#34;}\u0026#39;\u0026gt; {% block content %} (no content) {% endblock %} \u0026lt;/div\u0026gt; \u0026lt;!-- Other part of the template--\u0026gt;So now I need to write the div for the Htmx. And this is what I wrote:\n\u0026lt;div hx-get=\u0026#34;{% url \u0026#39;blog:htmx-post\u0026#39; %}?year={{ month|date:\u0026#34;Y\u0026#34; }}\u0026amp;month={{ month|date:\u0026#34;m\u0026#34; }}\u0026amp;{{ request.GET.urlencode }}\u0026#34; hx-trigger=\u0026#34;load\u0026#34;\u0026gt;This will be replaced.\u0026lt;/div\u0026gt;I build the url in the hx-get in a strange way because I need to add the query input for the MonthArchiveView (the \u0026amp;month and \u0026amp;year field in the url) and add all the other field. In this way I also have the sorting links in the header of the table working.\nConclusion This is how I have combine this 3 libs for my personal project and if you find it useful share it. Thanks!\nDjango is a high-level Python web framework that encourages rapid development and clean, pragmatic design. Built by experienced developers, it takes care of much of the hassle of web development, so you can focus on writing your app without needing to reinvent the wheel. It’s free and open source\u0026nbsp;\u0026nbsp; \u0026#160;\u0026#x21a9;\u0026#xfe0e;\ndjango-tables2 - An app for creating HTML tables\u0026nbsp;\u0026nbsp; \u0026#160;\u0026#x21a9;\u0026#xfe0e;\ndjango-htmx Extensions for using Django with htmx\u0026nbsp;\u0026nbsp; \u0026#160;\u0026#x21a9;\u0026#xfe0e;\nTablib: format-agnostic tabular dataset library\u0026nbsp;\u0026nbsp; \u0026#160;\u0026#x21a9;\u0026#xfe0e;\nhtmx in a Nutshell\u0026nbsp;\u0026nbsp; \u0026#160;\u0026#x21a9;\u0026#xfe0e;\n","image":"https://fundor333.com/post/2026/htmx-django-and-django-table2/cover.png","banner_image":"https://fundor333.com/post/2026/htmx-django-and-django-table2/cover.png"},{"title":"Generate Dataframe Summaries With Python","date_published":"2025-09-03T17:13:02+08:00","date_modified":"2026-07-16T22:49:21+02:00","id":"https://fundor333.com/post/2025/generate-dataframe-summaries-with-python/","url":"https://fundor333.com/post/2025/generate-dataframe-summaries-with-python/","tags":["datascience","dataframe","pandas","llm","Ollama","mistral","dev"],"content_html":"\u003cp\u003eHow much time do you spend with making summaries of dataset? Too much and I don\u0026rsquo;t like doing it so I search to do it with the AI. So this is my sperimentation with some medical data see at PyDataVe 22nd event and Mistral model.\u003c/p\u003e\n\u003ch2 id=\"the-code-for-the-inizializzation\" class=\"no-underline \"\u003e\n  \u003ca href=\"#the-code-for-the-inizializzation\"\u003e\n    \u003ci class=\"fa-whiteboard fa-semibold fa-angle-right\"\u003e\u003c/i\u003e\n    The code for the inizializzation\n  \u003c/a\u003e\n  \u003c/h2\u003e\n\u003cp\u003eFor start I need to install some dipendency\u003c/p\u003e\n\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;\"\u003e\u003ccode class=\"language-text\" data-lang=\"text\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003elangchain\u0026gt;=0.3.27\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003elangchain-ollama\u0026gt;=0.3.7\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003epandas\u0026gt;=2.3.2\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;\"\u003e\u003ccode class=\"language-python\" data-lang=\"python\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#f92672\"\u003eimport\u003c/span\u003e pandas \u003cspan style=\"color:#66d9ef\"\u003eas\u003c/span\u003e pd\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#f92672\"\u003efrom\u003c/span\u003e langchain_ollama \u003cspan style=\"color:#f92672\"\u003eimport\u003c/span\u003e ChatOllama\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#f92672\"\u003efrom\u003c/span\u003e typing \u003cspan style=\"color:#f92672\"\u003eimport\u003c/span\u003e Literal\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003edf \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e pd\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003eread_csv(\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;data/test.csv\u0026#34;\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eprint(\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;-*-\u0026#34;\u003c/span\u003e \u003cspan style=\"color:#f92672\"\u003e*\u003c/span\u003e \u003cspan style=\"color:#ae81ff\"\u003e20\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eprint(\u003cspan style=\"color:#e6db74\"\u003ef\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;Dataset shape: \u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e{\u003c/span\u003edf\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003eshape\u003cspan style=\"color:#e6db74\"\u003e}\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eprint(\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;-*-\u0026#34;\u003c/span\u003e \u003cspan style=\"color:#f92672\"\u003e*\u003c/span\u003e \u003cspan style=\"color:#ae81ff\"\u003e20\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eprint(\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;Missing value stats:\u0026#34;\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eprint(df\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003eisnull()\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003esum())\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cpre\u003e\u003ccode\u003e-*--*--*--*--*--*--*--*--*--*--*--*--*--*--*--*--*--*--*--*-\nDataset shape: (418, 20)\n-*--*--*--*--*--*--*--*--*--*--*--*--*--*--*--*--*--*--*--*-\nMissing value stats:\nID                 0\nN_Days             0\nStatus             0\nDrug             106\nAge                0\nSex                0\nAscites          106\nHepatomegaly     106\nSpiders          106\nEdema              0\nBilirubin          0\nCholesterol      134\nAlbumin            0\nCopper           108\nAlk_Phos         106\nSGOT             106\nTryglicerides    136\nPlatelets         11\nProthrombin        2\nStage              6\ndtype: int64\n\u003c/code\u003e\u003c/pre\u003e\n\u003cp\u003eThis is a section of the dataset and what is missing value of the stats.\u003c/p\u003e\n\u003cp\u003eNow we will start with the AI. In my case I user Ollama with Mistral model.\nI install the model with\u003c/p\u003e\n\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;\"\u003e\u003ccode class=\"language-bash\" data-lang=\"bash\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eollama run mistral\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003eAnd prepare the code for use the model. First you need to make a connection with the local LLM instance. This code use Mistral but you can pass any local LLM instance you have.\u003c/p\u003e\n\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;\"\u003e\u003ccode class=\"language-python\" data-lang=\"python\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#66d9ef\"\u003edef\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003eget_llm\u003c/span\u003e(model_name: str \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;mistral:latest\u0026#34;\u003c/span\u003e) \u003cspan style=\"color:#f92672\"\u003e-\u0026gt;\u003c/span\u003e ChatOllama:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;\u0026#34;\u0026#34;\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#e6db74\"\u003e    Create and configure a ChatOllama instance for local LLM inference.\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#e6db74\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#e6db74\"\u003e    This function initializes a ChatOllama client configured to connect to a\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#e6db74\"\u003e    local Ollama server. The client is set up with deterministic output\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#e6db74\"\u003e    (temperature=0) for consistent responses across multiple calls with the\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#e6db74\"\u003e    same input.\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#e6db74\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#e6db74\"\u003e    Parameters\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#e6db74\"\u003e    ----------\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#e6db74\"\u003e    model_name : str, optional\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#e6db74\"\u003e        The name of the Ollama model to use for chat completions.\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#e6db74\"\u003e        Must be a valid model name that is available on the local Ollama\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#e6db74\"\u003e        installation. Default is \u0026#34;mistral:latest\u0026#34;.\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#e6db74\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#e6db74\"\u003e    Returns\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#e6db74\"\u003e    -------\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#e6db74\"\u003e    ChatOllama\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#e6db74\"\u003e        A configured ChatOllama instance ready for chat completions.\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#e6db74\"\u003e    \u0026#34;\u0026#34;\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003ereturn\u003c/span\u003e ChatOllama(\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        model\u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003emodel_name, base_url\u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;http://localhost:11434\u0026#34;\u003c/span\u003e, temperature\u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#ae81ff\"\u003e0\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    )\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003eIf you want to test the connection you can use this command\u003c/p\u003e\n\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;\"\u003e\u003ccode class=\"language-python\" data-lang=\"python\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eprint(get_llm()\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003einvoke(\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;test\u0026#34;\u003c/span\u003e)\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003econtent)\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cpre\u003e\u003ccode\u003e Hallo! Wie geht es Ihnen? Ich bin hier, um Ihnen zu helfen. Was möchten Sie heute tun?\n\nIch kann Ihnen beispielsweise helfen:\n\n* Fragen beantworten\n* Informationen suchen\n* Aufgaben lösen\n* und vieles mehr!\n\nWelche Aufgabe haben wir heute vor uns?\n\u003c/code\u003e\u003c/pre\u003e\n\u003ch2 id=\"make-a-context\" class=\"no-underline \"\u003e\n  \u003ca href=\"#make-a-context\"\u003e\n    \u003ci class=\"fa-whiteboard fa-semibold fa-angle-right\"\u003e\u003c/i\u003e\n    Make a context\n  \u003c/a\u003e\n  \u003c/h2\u003e\n\u003cp\u003eNow we need to generate a context for the LLM. If you do this function with all the necessary data you can relaunch this script every time you need a new README/summary of the dataset. This is better to be a dataset with a fixed schema and a date which change every year like medical data (this), monthly sell report, census data\u0026hellip;\u003c/p\u003e\n\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;\"\u003e\u003ccode class=\"language-python\" data-lang=\"python\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#66d9ef\"\u003edef\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003eget_summary_context_message\u003c/span\u003e(df: pd\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003eDataFrame, dataset_name:str) \u003cspan style=\"color:#f92672\"\u003e-\u0026gt;\u003c/span\u003e str:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#75715e\"\u003e# Basic application statistics\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    total_analisys \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e len(df)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#75715e\"\u003e# Gender distribution\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    gender_counts \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e df[\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;Sex\u0026#34;\u003c/span\u003e]\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003evalue_counts()\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    male_count \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e gender_counts\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003eget(\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;M\u0026#34;\u003c/span\u003e, \u003cspan style=\"color:#ae81ff\"\u003e0\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    female_count \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e gender_counts\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003eget(\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;F\u0026#34;\u003c/span\u003e, \u003cspan style=\"color:#ae81ff\"\u003e0\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#75715e\"\u003e# Stage Statistics\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    stage_data \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e df[\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;Stage\u0026#34;\u003c/span\u003e]\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003edropna()\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    stage_avg \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e stage_data\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003emean()\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    stage_25th \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e stage_data\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003equantile(\u003cspan style=\"color:#ae81ff\"\u003e0.25\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    stage_50th \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e stage_data\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003equantile(\u003cspan style=\"color:#ae81ff\"\u003e0.50\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    stage_75th \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e stage_data\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003equantile(\u003cspan style=\"color:#ae81ff\"\u003e0.75\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#75715e\"\u003e# NDays Statistics\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    days_data \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e df[\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;N_Days\u0026#34;\u003c/span\u003e]\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003edropna()\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    days_avg \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e days_data\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003emean()\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    days_25th \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e days_data\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003equantile(\u003cspan style=\"color:#ae81ff\"\u003e0.25\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    days_50th \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e days_data\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003equantile(\u003cspan style=\"color:#ae81ff\"\u003e0.50\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    days_75th \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e days_data\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003equantile(\u003cspan style=\"color:#ae81ff\"\u003e0.75\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003edef\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003estatus_category\u003c/span\u003e(exp):\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#66d9ef\"\u003eif\u003c/span\u003e pd\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003eisna(exp):\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#66d9ef\"\u003ereturn\u003c/span\u003e \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;Unkown\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#66d9ef\"\u003eelif\u003c/span\u003e exp \u003cspan style=\"color:#f92672\"\u003e==\u003c/span\u003e \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;C\u0026#34;\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#66d9ef\"\u003ereturn\u003c/span\u003e \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;Censored\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#66d9ef\"\u003eelif\u003c/span\u003e exp \u003cspan style=\"color:#f92672\"\u003e==\u003c/span\u003e \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;CL\u0026#34;\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#66d9ef\"\u003ereturn\u003c/span\u003e \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;Censored due to Lever tx\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#66d9ef\"\u003eelif\u003c/span\u003e exp \u003cspan style=\"color:#f92672\"\u003e==\u003c/span\u003e \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;D\u0026#34;\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#66d9ef\"\u003ereturn\u003c/span\u003e \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;Death\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#66d9ef\"\u003eelse\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#66d9ef\"\u003ereturn\u003c/span\u003e \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;Unkow\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    df[\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;Status Str\u0026#39;\u003c/span\u003e]\u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e df[\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;Status\u0026#39;\u003c/span\u003e]\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003eapply(status_category)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    status_str_stats \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e []\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003efor\u003c/span\u003e category \u003cspan style=\"color:#f92672\"\u003ein\u003c/span\u003e [\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;Censored\u0026#34;\u003c/span\u003e, \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;Censored due to Lever tx\u0026#34;\u003c/span\u003e, \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;Death\u0026#34;\u003c/span\u003e,]:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        category_data \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e df[df[\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;Status Str\u0026#34;\u003c/span\u003e] \u003cspan style=\"color:#f92672\"\u003e==\u003c/span\u003e category]\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#66d9ef\"\u003eif\u003c/span\u003e len(category_data) \u003cspan style=\"color:#f92672\"\u003e\u0026gt;\u003c/span\u003e \u003cspan style=\"color:#ae81ff\"\u003e0\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            male \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e len(category_data[category_data[\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;Sex\u0026#34;\u003c/span\u003e] \u003cspan style=\"color:#f92672\"\u003e==\u003c/span\u003e \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;M\u0026#34;\u003c/span\u003e])\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            female \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e len(category_data[category_data[\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;Sex\u0026#34;\u003c/span\u003e] \u003cspan style=\"color:#f92672\"\u003e==\u003c/span\u003e \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;F\u0026#34;\u003c/span\u003e])\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            total \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e len(category_data)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            rate_m \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e (male \u003cspan style=\"color:#f92672\"\u003e/\u003c/span\u003e total) \u003cspan style=\"color:#f92672\"\u003e*\u003c/span\u003e \u003cspan style=\"color:#ae81ff\"\u003e100\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            rate_f \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e (female \u003cspan style=\"color:#f92672\"\u003e/\u003c/span\u003e total) \u003cspan style=\"color:#f92672\"\u003e*\u003c/span\u003e \u003cspan style=\"color:#ae81ff\"\u003e100\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            status_str_stats\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003eappend((category, male, female, total, rate_m, rate_f))\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    summary \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003ef\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;\u0026#34;\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e{\u003c/span\u003edataset_name\u003cspan style=\"color:#e6db74\"\u003e}\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#e6db74\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#e6db74\"\u003eTotal Analisys: \u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e{\u003c/span\u003etotal_analisys\u003cspan style=\"color:#e6db74\"\u003e:\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e,\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e}\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#e6db74\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#e6db74\"\u003eGender Distribution:\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#e6db74\"\u003e- Male applicants: \u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e{\u003c/span\u003emale_count\u003cspan style=\"color:#e6db74\"\u003e:\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e,\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e}\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e (\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e{\u003c/span\u003emale_count\u003cspan style=\"color:#f92672\"\u003e/\u003c/span\u003etotal_analisys\u003cspan style=\"color:#f92672\"\u003e*\u003c/span\u003e\u003cspan style=\"color:#ae81ff\"\u003e100\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e:\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e.1f\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e}\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e%)\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#e6db74\"\u003e- Female applicants: \u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e{\u003c/span\u003efemale_count\u003cspan style=\"color:#e6db74\"\u003e:\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e,\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e}\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e (\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e{\u003c/span\u003efemale_count\u003cspan style=\"color:#f92672\"\u003e/\u003c/span\u003etotal_analisys\u003cspan style=\"color:#f92672\"\u003e*\u003c/span\u003e\u003cspan style=\"color:#ae81ff\"\u003e100\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e:\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e.1f\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e}\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e%)\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#e6db74\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#e6db74\"\u003eStage Statistics:\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#e6db74\"\u003e- Average Stage: \u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e{\u003c/span\u003estage_avg\u003cspan style=\"color:#e6db74\"\u003e:\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e.2f\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e}\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#e6db74\"\u003e- 25th percentile: \u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e{\u003c/span\u003estage_25th\u003cspan style=\"color:#e6db74\"\u003e:\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e.2f\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e}\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#e6db74\"\u003e- 50th percentile (median): \u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e{\u003c/span\u003estage_50th\u003cspan style=\"color:#e6db74\"\u003e:\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e.2f\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e}\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#e6db74\"\u003e- 75th percentile: \u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e{\u003c/span\u003estage_75th\u003cspan style=\"color:#e6db74\"\u003e:\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e.2f\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e}\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#e6db74\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#e6db74\"\u003eN Day Statistics:\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#e6db74\"\u003e- N Days Stage: \u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e{\u003c/span\u003edays_avg\u003cspan style=\"color:#e6db74\"\u003e:\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e.2f\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e}\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#e6db74\"\u003e- 25th percentile: \u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e{\u003c/span\u003edays_25th\u003cspan style=\"color:#e6db74\"\u003e:\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e.2f\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e}\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#e6db74\"\u003e- 50th percentile (median): \u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e{\u003c/span\u003edays_50th\u003cspan style=\"color:#e6db74\"\u003e:\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e.2f\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e}\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#e6db74\"\u003e- 75th percentile: \u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e{\u003c/span\u003edays_75th\u003cspan style=\"color:#e6db74\"\u003e:\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e.2f\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e}\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;\u0026#34;\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    summary \u003cspan style=\"color:#f92672\"\u003e+=\u003c/span\u003e \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ae81ff\"\u003e\\n\\n\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003eStatus Rates by Sex:\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003efor\u003c/span\u003e category, male, female, total, rate_m, rate_f \u003cspan style=\"color:#f92672\"\u003ein\u003c/span\u003e status_str_stats:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        summary \u003cspan style=\"color:#f92672\"\u003e+=\u003c/span\u003e (\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#e6db74\"\u003ef\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ae81ff\"\u003e\\n\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e- \u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e{\u003c/span\u003ecategory\u003cspan style=\"color:#e6db74\"\u003e}\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e: \u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e{\u003c/span\u003emale\u003cspan style=\"color:#e6db74\"\u003e}\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e/\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e{\u003c/span\u003etotal\u003cspan style=\"color:#e6db74\"\u003e}\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e Male (\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e{\u003c/span\u003erate_m\u003cspan style=\"color:#e6db74\"\u003e:\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e.1f\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e}\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e% rate)\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#f92672\"\u003e+\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#e6db74\"\u003ef\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#ae81ff\"\u003e\\n\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e- \u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e{\u003c/span\u003ecategory\u003cspan style=\"color:#e6db74\"\u003e}\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e: \u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e{\u003c/span\u003efemale\u003cspan style=\"color:#e6db74\"\u003e}\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e/\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e{\u003c/span\u003etotal\u003cspan style=\"color:#e6db74\"\u003e}\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e Female (\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e{\u003c/span\u003erate_f\u003cspan style=\"color:#e6db74\"\u003e:\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e.1f\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e}\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e% rate)\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        )\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003ereturn\u003c/span\u003e summary\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003ch2 id=\"make-a-report\" class=\"no-underline \"\u003e\n  \u003ca href=\"#make-a-report\"\u003e\n    \u003ci class=\"fa-whiteboard fa-semibold fa-angle-right\"\u003e\u003c/i\u003e\n    Make a report\n  \u003c/a\u003e\n  \u003c/h2\u003e\n\u003cp\u003eAfter checking all you need to have a template for the repo of the dataset.\u003c/p\u003e\n\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;\"\u003e\u003ccode class=\"language-python\" data-lang=\"python\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eSUMMARIZE_DATAFRAME_PROMPT \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;\u0026#34;\u0026#34;\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#e6db74\"\u003eYou are an expert data analyst and data summarizer.\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#e6db74\"\u003eYour task is to take in complex datasets and return user-friendly descriptions and findings.\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#e6db74\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#e6db74\"\u003eYou were given this dataset:\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#e6db74\"\u003e- Name: \u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e{dataset_name}\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#e6db74\"\u003e- Source: \u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e{dataset_source}\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#e6db74\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#e6db74\"\u003eThis dataset was analyzed in a pipeline before it was given to you.\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#e6db74\"\u003eThese are the findings returned by the analysis pipeline:\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#e6db74\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026lt;context\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#e6db74\"\u003e{context}\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026lt;/context\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#e6db74\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#e6db74\"\u003eBased on these findings, write a detailed report in \u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e{report_format}\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e format.\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#e6db74\"\u003eGive the report a meaningful title and separate findings into sections with headings and subheadings.\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#e6db74\"\u003eOutput only the report in \u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e{report_format}\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e and nothing else.\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#e6db74\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#e6db74\"\u003eReport:\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;\u0026#34;\u0026#34;\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003eThis prompt and a lot of the code of this article are from \u003ca class=\"a-post interlink-script\" href=\"https://towardsdatascience.com/llms-pandas-how-i-use-generative-ai-to-generate-pandas-dataframe-summaries-2/\"   target=\"_blank\"\u003ethis post\u0026nbsp;\u0026nbsp;\u003ci class=\"fa-whiteboard fa-semibold fa-link\"\u003e\u003c/i\u003e\u003c/a\u003e\n.\u003c/p\u003e\n\u003cp\u003eAfter this we need a function that take the dataset \u003cem\u003edf\u003c/em\u003e, the prompt \u003cem\u003eSUMMARIZE_DATAFRAME_PROMPT\u003c/em\u003e with the needed info and return the content of the report.\u003c/p\u003e\n\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;\"\u003e\u003ccode class=\"language-python\" data-lang=\"python\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#66d9ef\"\u003edef\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003eget_report_summary\u003c/span\u003e(\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    dataset: pd\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003eDataFrame,\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    dataset_name: str,\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    dataset_source: str,\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    report_format: Literal[\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;markdown\u0026#34;\u003c/span\u003e, \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;html\u0026#34;\u003c/span\u003e] \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;markdown\u0026#34;\u003c/span\u003e,\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e) \u003cspan style=\"color:#f92672\"\u003e-\u0026gt;\u003c/span\u003e str:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    context_message \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e get_summary_context_message(df\u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003edataset, dataset_name\u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003edataset_name)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    prompt \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e SUMMARIZE_DATAFRAME_PROMPT\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003eformat(\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        dataset_name\u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003edataset_name,\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        dataset_source\u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003edataset_source,\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        context\u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003econtext_message,\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        report_format\u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003ereport_format,\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    )\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003ereturn\u003c/span\u003e get_llm()\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003einvoke(input\u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003eprompt)\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003econtent\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003eIn our case we launch it as\u003c/p\u003e\n\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;\"\u003e\u003ccode class=\"language-python\" data-lang=\"python\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003emd_report \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e get_report_summary(\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    dataset\u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003edf,\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    dataset_name\u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;Cirrhosis Patient Survival Prediction\u0026#34;\u003c/span\u003e,\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    dataset_source\u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;https://www.kaggle.com/datasets/joebeachcapital/cirrhosis-patient-survival-prediction/data\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eprint(md_report)\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cpre\u003e\u003ccode\u003e # Cirrhosis Patient Survival Prediction Analysis Report\n\n## Overview\nThe dataset analyzed consists of 418 records related to cirrhosis patients, sourced from [Kaggle](https://www.kaggle.com/datasets/joebeachcapital/cirrhosis-patient-survival-prediction/data). The data provides information about the patient's gender, stage of cirrhosis, number of days since diagnosis, and final status (censored or death).\n\n## Demographics\n### Gender Distribution\nThe dataset shows a significant imbalance in gender distribution with 89.5% female applicants (374) and only 10.5% male applicants (44).\n\n## Cirrhosis Stage Statistics\n### Average Stage\nThe average stage of cirrhosis for the analyzed patients is 3.02, indicating a severe level of liver damage.\n\n### Percentiles\n- **25th percentile**: The cirrhosis stage is at least 2.00 for 25% of the patients.\n- **Median (50th percentile)**: Half of the patients have a cirrhosis stage of 3.00.\n- **75th percentile**: For 75% of the patients, the cirrhosis stage is 4.00 or lower.\n\n## N Days Statistics\n### N Days Stage\nThe average number of days since diagnosis for the analyzed patients is 1917.78 days.\n\n### Percentiles\n- **25th percentile**: The minimum number of days since diagnosis for 25% of the patients is 1092.75 days.\n- **Median (50th percentile)**: Half of the patients have been diagnosed with cirrhosis for at least 1730.00 days.\n- **75th percentile**: For 75% of the patients, the number of days since diagnosis is 2613.50 days or less.\n\n## Status Rates by Sex\nThe following table shows the rates of different statuses (censored due to Lever tx and death) for both male and female applicants:\n\n|                     | Male Applicants | Female Applicants |\n|---------------------|-----------------|-------------------|\n| Censored            | 17/232 (7.3%)    | 215/232 (92.7%)   |\n| Censored due to Lever tx | 3/25 (12.0%)     | 22/25 (88.0%)     |\n| Death                | 24/161 (14.9%)   | 137/161 (85.1%)   |\n\nThe analysis indicates that female applicants are more likely to have their status censored, either due to the lack of information or other factors, while male applicants are more likely to experience death. However, it's important to note that the sample size for male applicants is significantly smaller than that of female applicants.\n\u003c/code\u003e\u003c/pre\u003e\n","content_text":"How much time do you spend with making summaries of dataset? Too much and I don\u0026rsquo;t like doing it so I search to do it with the AI. So this is my sperimentation with some medical data see at PyDataVe 22nd event and Mistral model.\nThe code for the inizializzation For start I need to install some dipendency\nlangchain\u0026gt;=0.3.27 langchain-ollama\u0026gt;=0.3.7 pandas\u0026gt;=2.3.2 import pandas as pd from langchain_ollama import ChatOllama from typing import Literal df = pd.read_csv(\u0026#34;data/test.csv\u0026#34;) print(\u0026#34;-*-\u0026#34; * 20) print(f\u0026#34;Dataset shape: {df.shape}\u0026#34;) print(\u0026#34;-*-\u0026#34; * 20) print(\u0026#34;Missing value stats:\u0026#34;) print(df.isnull().sum())-*--*--*--*--*--*--*--*--*--*--*--*--*--*--*--*--*--*--*--*- Dataset shape: (418, 20) -*--*--*--*--*--*--*--*--*--*--*--*--*--*--*--*--*--*--*--*- Missing value stats: ID 0 N_Days 0 Status 0 Drug 106 Age 0 Sex 0 Ascites 106 Hepatomegaly 106 Spiders 106 Edema 0 Bilirubin 0 Cholesterol 134 Albumin 0 Copper 108 Alk_Phos 106 SGOT 106 Tryglicerides 136 Platelets 11 Prothrombin 2 Stage 6 dtype: int64 This is a section of the dataset and what is missing value of the stats.\nNow we will start with the AI. In my case I user Ollama with Mistral model. I install the model with\nollama run mistralAnd prepare the code for use the model. First you need to make a connection with the local LLM instance. This code use Mistral but you can pass any local LLM instance you have.\ndef get_llm(model_name: str = \u0026#34;mistral:latest\u0026#34;) -\u0026gt; ChatOllama: \u0026#34;\u0026#34;\u0026#34; Create and configure a ChatOllama instance for local LLM inference. This function initializes a ChatOllama client configured to connect to a local Ollama server. The client is set up with deterministic output (temperature=0) for consistent responses across multiple calls with the same input. Parameters ---------- model_name : str, optional The name of the Ollama model to use for chat completions. Must be a valid model name that is available on the local Ollama installation. Default is \u0026#34;mistral:latest\u0026#34;. Returns ------- ChatOllama A configured ChatOllama instance ready for chat completions. \u0026#34;\u0026#34;\u0026#34; return ChatOllama( model=model_name, base_url=\u0026#34;http://localhost:11434\u0026#34;, temperature=0 )If you want to test the connection you can use this command\nprint(get_llm().invoke(\u0026#34;test\u0026#34;).content) Hallo! Wie geht es Ihnen? Ich bin hier, um Ihnen zu helfen. Was möchten Sie heute tun? Ich kann Ihnen beispielsweise helfen: * Fragen beantworten * Informationen suchen * Aufgaben lösen * und vieles mehr! Welche Aufgabe haben wir heute vor uns? Make a context Now we need to generate a context for the LLM. If you do this function with all the necessary data you can relaunch this script every time you need a new README/summary of the dataset. This is better to be a dataset with a fixed schema and a date which change every year like medical data (this), monthly sell report, census data\u0026hellip;\ndef get_summary_context_message(df: pd.DataFrame, dataset_name:str) -\u0026gt; str: # Basic application statistics total_analisys = len(df) # Gender distribution gender_counts = df[\u0026#34;Sex\u0026#34;].value_counts() male_count = gender_counts.get(\u0026#34;M\u0026#34;, 0) female_count = gender_counts.get(\u0026#34;F\u0026#34;, 0) # Stage Statistics stage_data = df[\u0026#34;Stage\u0026#34;].dropna() stage_avg = stage_data.mean() stage_25th = stage_data.quantile(0.25) stage_50th = stage_data.quantile(0.50) stage_75th = stage_data.quantile(0.75) # NDays Statistics days_data = df[\u0026#34;N_Days\u0026#34;].dropna() days_avg = days_data.mean() days_25th = days_data.quantile(0.25) days_50th = days_data.quantile(0.50) days_75th = days_data.quantile(0.75) def status_category(exp): if pd.isna(exp): return \u0026#34;Unkown\u0026#34; elif exp == \u0026#34;C\u0026#34;: return \u0026#34;Censored\u0026#34; elif exp == \u0026#34;CL\u0026#34;: return \u0026#34;Censored due to Lever tx\u0026#34; elif exp == \u0026#34;D\u0026#34;: return \u0026#34;Death\u0026#34; else: return \u0026#34;Unkow\u0026#34; df[\u0026#39;Status Str\u0026#39;]= df[\u0026#39;Status\u0026#39;].apply(status_category) status_str_stats = [] for category in [\u0026#34;Censored\u0026#34;, \u0026#34;Censored due to Lever tx\u0026#34;, \u0026#34;Death\u0026#34;,]: category_data = df[df[\u0026#34;Status Str\u0026#34;] == category] if len(category_data) \u0026gt; 0: male = len(category_data[category_data[\u0026#34;Sex\u0026#34;] == \u0026#34;M\u0026#34;]) female = len(category_data[category_data[\u0026#34;Sex\u0026#34;] == \u0026#34;F\u0026#34;]) total = len(category_data) rate_m = (male / total) * 100 rate_f = (female / total) * 100 status_str_stats.append((category, male, female, total, rate_m, rate_f)) summary =f\u0026#34;\u0026#34;\u0026#34;{dataset_name} Total Analisys: {total_analisys:,} Gender Distribution: - Male applicants: {male_count:,} ({male_count/total_analisys*100:.1f}%) - Female applicants: {female_count:,} ({female_count/total_analisys*100:.1f}%) Stage Statistics: - Average Stage: {stage_avg:.2f} - 25th percentile: {stage_25th:.2f} - 50th percentile (median): {stage_50th:.2f} - 75th percentile: {stage_75th:.2f} N Day Statistics: - N Days Stage: {days_avg:.2f} - 25th percentile: {days_25th:.2f} - 50th percentile (median): {days_50th:.2f} - 75th percentile: {days_75th:.2f} \u0026#34;\u0026#34;\u0026#34; summary += \u0026#34;\\n\\nStatus Rates by Sex:\u0026#34; for category, male, female, total, rate_m, rate_f in status_str_stats: summary += ( f\u0026#34;\\n- {category}: {male}/{total} Male ({rate_m:.1f}% rate)\u0026#34;+ f\u0026#34;\\n- {category}: {female}/{total} Female ({rate_f:.1f}% rate)\u0026#34; ) return summary Make a report After checking all you need to have a template for the repo of the dataset.\nSUMMARIZE_DATAFRAME_PROMPT = \u0026#34;\u0026#34;\u0026#34; You are an expert data analyst and data summarizer. Your task is to take in complex datasets and return user-friendly descriptions and findings. You were given this dataset: - Name: {dataset_name} - Source: {dataset_source} This dataset was analyzed in a pipeline before it was given to you. These are the findings returned by the analysis pipeline: \u0026lt;context\u0026gt; {context} \u0026lt;/context\u0026gt; Based on these findings, write a detailed report in {report_format} format. Give the report a meaningful title and separate findings into sections with headings and subheadings. Output only the report in {report_format} and nothing else. Report: \u0026#34;\u0026#34;\u0026#34;This prompt and a lot of the code of this article are from this post\u0026nbsp;\u0026nbsp; .\nAfter this we need a function that take the dataset df, the prompt SUMMARIZE_DATAFRAME_PROMPT with the needed info and return the content of the report.\ndef get_report_summary( dataset: pd.DataFrame, dataset_name: str, dataset_source: str, report_format: Literal[\u0026#34;markdown\u0026#34;, \u0026#34;html\u0026#34;] = \u0026#34;markdown\u0026#34;, ) -\u0026gt; str: context_message = get_summary_context_message(df=dataset, dataset_name=dataset_name) prompt = SUMMARIZE_DATAFRAME_PROMPT.format( dataset_name=dataset_name, dataset_source=dataset_source, context=context_message, report_format=report_format, ) return get_llm().invoke(input=prompt).contentIn our case we launch it as\nmd_report = get_report_summary( dataset=df, dataset_name=\u0026#34;Cirrhosis Patient Survival Prediction\u0026#34;, dataset_source=\u0026#34;https://www.kaggle.com/datasets/joebeachcapital/cirrhosis-patient-survival-prediction/data\u0026#34; ) print(md_report) # Cirrhosis Patient Survival Prediction Analysis Report ## Overview The dataset analyzed consists of 418 records related to cirrhosis patients, sourced from [Kaggle](https://www.kaggle.com/datasets/joebeachcapital/cirrhosis-patient-survival-prediction/data). The data provides information about the patient's gender, stage of cirrhosis, number of days since diagnosis, and final status (censored or death). ## Demographics ### Gender Distribution The dataset shows a significant imbalance in gender distribution with 89.5% female applicants (374) and only 10.5% male applicants (44). ## Cirrhosis Stage Statistics ### Average Stage The average stage of cirrhosis for the analyzed patients is 3.02, indicating a severe level of liver damage. ### Percentiles - **25th percentile**: The cirrhosis stage is at least 2.00 for 25% of the patients. - **Median (50th percentile)**: Half of the patients have a cirrhosis stage of 3.00. - **75th percentile**: For 75% of the patients, the cirrhosis stage is 4.00 or lower. ## N Days Statistics ### N Days Stage The average number of days since diagnosis for the analyzed patients is 1917.78 days. ### Percentiles - **25th percentile**: The minimum number of days since diagnosis for 25% of the patients is 1092.75 days. - **Median (50th percentile)**: Half of the patients have been diagnosed with cirrhosis for at least 1730.00 days. - **75th percentile**: For 75% of the patients, the number of days since diagnosis is 2613.50 days or less. ## Status Rates by Sex The following table shows the rates of different statuses (censored due to Lever tx and death) for both male and female applicants: | | Male Applicants | Female Applicants | |---------------------|-----------------|-------------------| | Censored | 17/232 (7.3%) | 215/232 (92.7%) | | Censored due to Lever tx | 3/25 (12.0%) | 22/25 (88.0%) | | Death | 24/161 (14.9%) | 137/161 (85.1%) | The analysis indicates that female applicants are more likely to have their status censored, either due to the lack of information or other factors, while male applicants are more likely to experience death. However, it's important to note that the sample size for male applicants is significantly smaller than that of female applicants. ","image":"https://fundor333.com/post/2025/generate-dataframe-summaries-with-python/cover.png","banner_image":"https://fundor333.com/post/2025/generate-dataframe-summaries-with-python/cover.png"},{"title":"Hugo Blog With Jupyter Notebook","date_published":"2025-09-01T08:40:34+02:00","date_modified":"2026-07-16T22:49:21+02:00","id":"https://fundor333.com/post/2025/hugo-blog-with-jupyter-notebook/","url":"https://fundor333.com/post/2025/hugo-blog-with-jupyter-notebook/","tags":["hugo","juppyter","notebook","datascience","pydatave","dev"],"content_html":"\u003cp\u003eA long time ago, I wrote a \u003ca class=\"a-post interlink-script\" href=\"/post/2017/jupyter-notebook-pelican-combo/\"  \u003epost\u003c/a\u003e\n about writing a post for the Pelican static site generator made with a Jupyter Notebook. I did it because, at the time, I was a huge fan of the Notebooks and I had the blog generated by Pelican so\u0026hellip;\u003c/p\u003e\n\u003cp\u003e\u003cimg  class=\"center-img u-photo \"  src=\"pydatave.jpg\" alt=\"pydatave.jpg\"\u003e\u003c/p\u003e\n\u003cp\u003eAnd now, after a PyDataVe (the 22nd event), I make a Jupyter Notebook after a lot of time and I feel the need to have a solution for make a Jupyter Notebook one of the post of my blog so I find a way to do it. This time in Hugo\u003c/p\u003e\n\u003ch2 id=\"jupyter-in-my-hugo\" class=\"no-underline \"\u003e\n  \u003ca href=\"#jupyter-in-my-hugo\"\u003e\n    \u003ci class=\"fa-whiteboard fa-semibold fa-angle-right\"\u003e\u003c/i\u003e\n    Jupyter in my Hugo\n  \u003c/a\u003e\n  \u003c/h2\u003e\n\u003cp\u003eSo first I search for a way to convert a Jupyter Notebook to a Markdown file with the headers for Hugo. So I find a \u003ca class=\"a-post interlink-script\" href=\"https://github.com/soda92/hugo-nbconvert\"   target=\"_blank\"\u003epython module\u0026nbsp;\u0026nbsp;\u003ci class=\"fa-whiteboard fa-semibold fa-link\"\u003e\u003c/i\u003e\u003c/a\u003e\n to generate a Notebook with a starting metadata for my blog. All the metadata are inside the first cell set as a Markdown type cell.\u003c/p\u003e\n\u003cp\u003eAll this is made by launching this command for generate the notebook\u003c/p\u003e\n\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;\"\u003e\u003ccode class=\"language-bash\" data-lang=\"bash\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003ehugo_nbnew content/post/test-hugo-page\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003eAnd at the end of all the writing I launch this command\u003c/p\u003e\n\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;\"\u003e\u003ccode class=\"language-bash\" data-lang=\"bash\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003ehugo_nbconvert content/post/test-hugo-page/index.ipynb\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003efor generate/updating the markdown file for Hugo.\u003c/p\u003e\n\u003ch2 id=\"other-little-things-i-have-done\" class=\"no-underline \"\u003e\n  \u003ca href=\"#other-little-things-i-have-done\"\u003e\n    \u003ci class=\"fa-whiteboard fa-semibold fa-angle-right\"\u003e\u003c/i\u003e\n    Other little things I have done\n  \u003c/a\u003e\n  \u003c/h2\u003e\n\u003cp\u003eAfter testing all of this stuff I make some script for my personal writing pipeline (if I don\u0026rsquo;t make some automation I feel bad) I fix some CSS of my site for the code part. I am a Backend Dev, so I don\u0026rsquo;t share my CSS edit because it is something working but not so pretty to share\u0026hellip;\u003c/p\u003e\n\u003cp\u003eAfter that I find myself wanting to have some way to cite a part of the post with a link (because I want to share a specific part of the post as a response to post/tweet/tooth on the web) and I search for something clean and usefull.\u003c/p\u003e\n\u003cp\u003eSo I find a \u003ca class=\"a-post interlink-script\" href=\"https://www.bryanbraun.com/anchorjs/\"   target=\"_blank\"\u003eJS script\u0026nbsp;\u0026nbsp;\u003ci class=\"fa-whiteboard fa-semibold fa-link\"\u003e\u003c/i\u003e\u003c/a\u003e\n for adding deep anchor links to my post and I set it to add a deep anchor for every paragraph of the posts.\u003c/p\u003e\n\u003cp\u003e\u003cimg  class=\"center-img u-photo \"  src=\"mastodon.png\" alt=\"mastodon.png\"\u003e\u003c/p\u003e\n\u003cp\u003eAnd after all I check if I implement the \u003ca class=\"a-post interlink-script\" href=\"https://blog.joinmastodon.org/2024/07/highlighting-journalism-on-mastodon/\"   target=\"_blank\"\u003emeta tag for journalism for Mastodon\u0026nbsp;\u0026nbsp;\u003ci class=\"fa-whiteboard fa-semibold fa-link\"\u003e\u003c/i\u003e\u003c/a\u003e\n because I share a lot of stuff on Mastodon.\u003c/p\u003e\n\u003ch2 id=\"final-consideration\" class=\"no-underline \"\u003e\n  \u003ca href=\"#final-consideration\"\u003e\n    \u003ci class=\"fa-whiteboard fa-semibold fa-angle-right\"\u003e\u003c/i\u003e\n    Final consideration\n  \u003c/a\u003e\n  \u003c/h2\u003e\n\u003cp\u003eI like my new configuration with the possibility to add Jupyter Notebook in my blog and this is the first Notebook I had to my Hugo Blog. I also like the idea that I can work for something else, make a Notebook and, only changing the data, make multiple article about something with the updated data every time I need to add the blog with the latest report for the dataset.\u003c/p\u003e\n","content_text":"A long time ago, I wrote a post about writing a post for the Pelican static site generator made with a Jupyter Notebook. I did it because, at the time, I was a huge fan of the Notebooks and I had the blog generated by Pelican so\u0026hellip;\nAnd now, after a PyDataVe (the 22nd event), I make a Jupyter Notebook after a lot of time and I feel the need to have a solution for make a Jupyter Notebook one of the post of my blog so I find a way to do it. This time in Hugo\nJupyter in my Hugo So first I search for a way to convert a Jupyter Notebook to a Markdown file with the headers for Hugo. So I find a python module\u0026nbsp;\u0026nbsp; to generate a Notebook with a starting metadata for my blog. All the metadata are inside the first cell set as a Markdown type cell.\nAll this is made by launching this command for generate the notebook\nhugo_nbnew content/post/test-hugo-pageAnd at the end of all the writing I launch this command\nhugo_nbconvert content/post/test-hugo-page/index.ipynbfor generate/updating the markdown file for Hugo.\nOther little things I have done After testing all of this stuff I make some script for my personal writing pipeline (if I don\u0026rsquo;t make some automation I feel bad) I fix some CSS of my site for the code part. I am a Backend Dev, so I don\u0026rsquo;t share my CSS edit because it is something working but not so pretty to share\u0026hellip;\nAfter that I find myself wanting to have some way to cite a part of the post with a link (because I want to share a specific part of the post as a response to post/tweet/tooth on the web) and I search for something clean and usefull.\nSo I find a JS script\u0026nbsp;\u0026nbsp; for adding deep anchor links to my post and I set it to add a deep anchor for every paragraph of the posts.\nAnd after all I check if I implement the meta tag for journalism for Mastodon\u0026nbsp;\u0026nbsp; because I share a lot of stuff on Mastodon.\nFinal consideration I like my new configuration with the possibility to add Jupyter Notebook in my blog and this is the first Notebook I had to my Hugo Blog. I also like the idea that I can work for something else, make a Notebook and, only changing the data, make multiple article about something with the updated data every time I need to add the blog with the latest report for the dataset.\n","image":"https://fundor333.com/post/2025/hugo-blog-with-jupyter-notebook/cover.png","banner_image":"https://fundor333.com/post/2025/hugo-blog-with-jupyter-notebook/cover.png"},{"title":"Generate Post With Img for Hugo","date_published":"2025-07-12T08:36:34+02:00","date_modified":"2026-07-16T22:49:21+02:00","id":"https://fundor333.com/post/2025/generate-post-with-img-for-hugo/","url":"https://fundor333.com/post/2025/generate-post-with-img-for-hugo/","tags":["image","hugo","script","hacking","dev","fingerfood"],"content_html":"\u003cp\u003eSome days ago I find a new post from a blog I follow about \u0026ldquo;\u003ca class=\"a-post interlink-script\" href=\"https://www.burgeonlab.com/blog/hugo-and-wordpress-open-graph-meta-tags/\"   target=\"_blank\"\u003eOpen Graph Meta Tags on Hugo and WordPress Blogs\u0026nbsp;\u0026nbsp;\u003ci class=\"fa-whiteboard fa-semibold fa-link\"\u003e\u003c/i\u003e\u003c/a\u003e\n\u0026rdquo; as a toot\u003c/p\u003e\n\n\n\n\n\n\n\n\n    \n    \n        \n        \n    \n\n    \n        \u003cdiv class=\"toot\"\u003e\n            \u003cdiv class=\"toot-header\"\u003e\n                \u003ca class=\"toot-profile\" href=\"https://fosstodon.org/@eclecticpassions\" rel=\"noopener\"\u003e\n                    \u003cimg src=\"https://cdn.fosstodon.org/accounts/avatars/110/631/569/439/879/798/original/63c2880c18d2bab3.jpg\"\n                         alt=\"Avatar for @eclecticpassions@fosstodon.org\"\n                         loading=\"lazy\"\u003e\n                \u003c/a\u003e\n                \u003cdiv class=\"toot-author\"\u003e\n                    \u003ca class=\"toot-author-name\"\n                       href=\"https://fosstodon.org/@eclecticpassions\"\n                       rel=\"noopener\"\u003eNaty S\u003c/a\u003e\n                    \u003ca class=\"toot-author-handle\"\n                       href=\"https://fosstodon.org/@eclecticpassions\"\n                       rel=\"noopener\"\u003e@eclecticpassions@fosstodon.org\u003c/a\u003e\n                \u003c/div\u003e\n            \u003c/div\u003e\n\n            \u003cdiv class=\"toot-content\"\u003e\u003cp\u003eNew \u003ca href=\"https://fosstodon.org/tags/blogpost\" class=\"mention hashtag\" rel=\"tag\"\u003e#\u003cspan\u003eblogpost\u003c/span\u003e\u003c/a\u003e\u003c/p\u003e\u003cp\u003e➡️ \u003ca href=\"https://www.burgeonlab.com/blog/hugo-and-wordpress-open-graph-meta-tags/\" target=\"_blank\" rel=\"nofollow noopener\" translate=\"no\"\u003e\u003cspan class=\"invisible\"\u003ehttps://www.\u003c/span\u003e\u003cspan class=\"ellipsis\"\u003eburgeonlab.com/blog/hugo-and-w\u003c/span\u003e\u003cspan class=\"invisible\"\u003eordpress-open-graph-meta-tags/\u003c/span\u003e\u003c/a\u003e\u003c/p\u003e\u003cp\u003eI often see bloggers on Mastodon with no images for their blog links or sometimes no link card at all (this was me not too long ago).\u003c/p\u003e\u003cp\u003eI\u0026#39;ve been sorting out Open Graph meta tags for my three blogs (Hugo and WordPress) and I\u0026#39;m happy to say it\u0026#39;s all working great now! Read my post to get some tips! 👆 \u003c/p\u003e\u003cp\u003e\u003ca href=\"https://fosstodon.org/tags/BurgeonLab\" class=\"mention hashtag\" rel=\"tag\"\u003e#\u003cspan\u003eBurgeonLab\u003c/span\u003e\u003c/a\u003e\u003cbr /\u003e\u003ca href=\"https://fosstodon.org/tags/blog\" class=\"mention hashtag\" rel=\"tag\"\u003e#\u003cspan\u003eblog\u003c/span\u003e\u003c/a\u003e \u003ca href=\"https://fosstodon.org/tags/blogging\" class=\"mention hashtag\" rel=\"tag\"\u003e#\u003cspan\u003eblogging\u003c/span\u003e\u003c/a\u003e \u003ca href=\"https://fosstodon.org/tags/blogs\" class=\"mention hashtag\" rel=\"tag\"\u003e#\u003cspan\u003eblogs\u003c/span\u003e\u003c/a\u003e \u003ca href=\"https://fosstodon.org/tags/hugo\" class=\"mention hashtag\" rel=\"tag\"\u003e#\u003cspan\u003ehugo\u003c/span\u003e\u003c/a\u003e \u003ca href=\"https://fosstodon.org/tags/wordpress\" class=\"mention hashtag\" rel=\"tag\"\u003e#\u003cspan\u003ewordpress\u003c/span\u003e\u003c/a\u003e \u003ca href=\"https://fosstodon.org/tags/webdev\" class=\"mention hashtag\" rel=\"tag\"\u003e#\u003cspan\u003ewebdev\u003c/span\u003e\u003c/a\u003e \u003ca href=\"https://fosstodon.org/tags/opengraph\" class=\"mention hashtag\" rel=\"tag\"\u003e#\u003cspan\u003eopengraph\u003c/span\u003e\u003c/a\u003e\u003c/p\u003e\u003c/div\u003e\n\n            \n\n            \u003cdiv class=\"toot-footer\"\u003e\n                \u003ca href=\"https://fosstodon.org@eclecticpassions/status/114818281454845557\"\n                   class=\"toot-date\"\n                   rel=\"noopener\"\u003e3:18 PM · Jul 8, 2025\u003c/a\u003e\n            \u003c/div\u003e\n        \u003c/div\u003e\n    \n\n\n\u003cp\u003eand I find I do the same thing and some more. I generate a default cover because I prefer to have a \u0026ldquo;standard\u0026rdquo; generated image or a specific image as the feature image. The image set in the settings is a default, a  \u0026ldquo;if all other image fall use this\u0026rdquo; kind of stuff.\u003c/p\u003e\n\u003ch2 id=\"how-i-generate-the-post\" class=\"no-underline \"\u003e\n  \u003ca href=\"#how-i-generate-the-post\"\u003e\n    \u003ci class=\"fa-whiteboard fa-semibold fa-angle-right\"\u003e\u003c/i\u003e\n    How I generate the post?\n  \u003c/a\u003e\n  \u003c/h2\u003e\n\u003cp\u003eWhen I write a post I launch a \u003ca class=\"a-post interlink-script\" href=\"https://fundor333.com/post/2021/the-team-makefile/\"  \u003emakefile command\u003c/a\u003e\n and it launch two command for me:\u003c/p\u003e\n\u003col\u003e\n\u003cli\u003eGenerate a new post with hugo new\u003c/li\u003e\n\u003cli\u003eGenerate a cover with my python script\u003c/li\u003e\n\u003c/ol\u003e\n\u003ch2 id=\"some-code\" class=\"no-underline \"\u003e\n  \u003ca href=\"#some-code\"\u003e\n    \u003ci class=\"fa-whiteboard fa-semibold fa-angle-right\"\u003e\u003c/i\u003e\n    Some code\n  \u003c/a\u003e\n  \u003c/h2\u003e\n\u003cp\u003eFor this project I use a font (\u003ca class=\"a-post interlink-script\" href=\"https://font.download/font/futura-book\"   target=\"_blank\"\u003eFutura Book font\u0026nbsp;\u0026nbsp;\u003ci class=\"fa-whiteboard fa-semibold fa-link\"\u003e\u003c/i\u003e\u003c/a\u003e\n) and a image where put the title and other thing of the post (for now only the title).\nThis is the image \u0026ldquo;clean\u0026rdquo;, without the text.\u003c/p\u003e\n\u003cp\u003e\u003cimg  class=\"center-img u-photo \"  src=\"cover-blank.jpg\" alt=\"cover-blank.jpg\"\u003e\u003c/p\u003e\n\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;\"\u003e\u003ccode class=\"language-python\" data-lang=\"python\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#f92672\"\u003efrom\u003c/span\u003e PIL \u003cspan style=\"color:#f92672\"\u003eimport\u003c/span\u003e Image, ImageDraw, ImageFont  \u003cspan style=\"color:#75715e\"\u003e# 👉️ Import modules from PIL\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#66d9ef\"\u003edef\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003egenerate_img\u003c/span\u003e(message: str, path: str):\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    font_path \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;Futura Book font.ttf\u0026#34;\u003c/span\u003e  \u003cspan style=\"color:#75715e\"\u003e# 👉️ Font .ttf Path\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    font_size \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#ae81ff\"\u003e100\u003c/span\u003e  \u003cspan style=\"color:#75715e\"\u003e# 👉️ Font Size\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    img \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e Image\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003eopen(\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;cover-blank.jpg\u0026#34;\u003c/span\u003e)  \u003cspan style=\"color:#75715e\"\u003e# 👉️ Open Image\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    dr \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e ImageDraw\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003eDraw(img)  \u003cspan style=\"color:#75715e\"\u003e# 👉️ Create New Image\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    my_font \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e ImageFont\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003etruetype(font_path, font_size)  \u003cspan style=\"color:#75715e\"\u003e# 👉️ Initialize Font\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    text_x \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e (img\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003ewidth) \u003cspan style=\"color:#f92672\"\u003e//\u003c/span\u003e \u003cspan style=\"color:#ae81ff\"\u003e2\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    text_y \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e (img\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003eheight) \u003cspan style=\"color:#f92672\"\u003e//\u003c/span\u003e \u003cspan style=\"color:#ae81ff\"\u003e2\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    dr\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003etext((text_x, text_y), message, font\u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003emy_font, fill\u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e(\u003cspan style=\"color:#ae81ff\"\u003e255\u003c/span\u003e, \u003cspan style=\"color:#ae81ff\"\u003e255\u003c/span\u003e, \u003cspan style=\"color:#ae81ff\"\u003e255\u003c/span\u003e), anchor\u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;mm\u0026#34;\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    print(\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;Generated content/\u0026#34;\u003c/span\u003e \u003cspan style=\"color:#f92672\"\u003e+\u003c/span\u003e path \u003cspan style=\"color:#f92672\"\u003e+\u003c/span\u003e \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;/cover.png\u0026#34;\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    img\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003esave(\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;content/\u0026#34;\u003c/span\u003e \u003cspan style=\"color:#f92672\"\u003e+\u003c/span\u003e path \u003cspan style=\"color:#f92672\"\u003e+\u003c/span\u003e \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;/cover.png\u0026#34;\u003c/span\u003e)\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003eThis script use Python (the library is PIL) and I set the fill parameters for a standard size OpenGraph image.\u003c/p\u003e\n\u003cp\u003eIf you use a python script for generate new post you can implement this code inside of the script or you can add some code to make a command line to launch after your \u0026ldquo;new post\u0026rdquo; command.\u003c/p\u003e\n","content_text":"Some days ago I find a new post from a blog I follow about \u0026ldquo;Open Graph Meta Tags on Hugo and WordPress Blogs\u0026nbsp;\u0026nbsp; \u0026rdquo; as a toot\nNaty S @eclecticpassions@fosstodon.org New #blogpost\n➡️ https://www.burgeonlab.com/blog/hugo-and-wordpress-open-graph-meta-tags/\nI often see bloggers on Mastodon with no images for their blog links or sometimes no link card at all (this was me not too long ago).\nI\u0026#39;ve been sorting out Open Graph meta tags for my three blogs (Hugo and WordPress) and I\u0026#39;m happy to say it\u0026#39;s all working great now! Read my post to get some tips! 👆 #BurgeonLab\n#blog #blogging #blogs #hugo #wordpress #webdev #opengraph\n3:18 PM · Jul 8, 2025 and I find I do the same thing and some more. I generate a default cover because I prefer to have a \u0026ldquo;standard\u0026rdquo; generated image or a specific image as the feature image. The image set in the settings is a default, a \u0026ldquo;if all other image fall use this\u0026rdquo; kind of stuff.\nHow I generate the post? When I write a post I launch a makefile command and it launch two command for me:\nGenerate a new post with hugo new Generate a cover with my python script Some code For this project I use a font (Futura Book font\u0026nbsp;\u0026nbsp; ) and a image where put the title and other thing of the post (for now only the title). This is the image \u0026ldquo;clean\u0026rdquo;, without the text.\nfrom PIL import Image, ImageDraw, ImageFont # 👉️ Import modules from PIL def generate_img(message: str, path: str): font_path = \u0026#34;Futura Book font.ttf\u0026#34; # 👉️ Font .ttf Path font_size = 100 # 👉️ Font Size img = Image.open(\u0026#34;cover-blank.jpg\u0026#34;) # 👉️ Open Image dr = ImageDraw.Draw(img) # 👉️ Create New Image my_font = ImageFont.truetype(font_path, font_size) # 👉️ Initialize Font text_x = (img.width) // 2 text_y = (img.height) // 2 dr.text((text_x, text_y), message, font=my_font, fill=(255, 255, 255), anchor=\u0026#34;mm\u0026#34;) print(\u0026#34;Generated content/\u0026#34; + path + \u0026#34;/cover.png\u0026#34;) img.save(\u0026#34;content/\u0026#34; + path + \u0026#34;/cover.png\u0026#34;)This script use Python (the library is PIL) and I set the fill parameters for a standard size OpenGraph image.\nIf you use a python script for generate new post you can implement this code inside of the script or you can add some code to make a command line to launch after your \u0026ldquo;new post\u0026rdquo; command.\n","image":"https://fundor333.com/post/2025/generate-post-with-img-for-hugo/cover.png","banner_image":"https://fundor333.com/post/2025/generate-post-with-img-for-hugo/cover.png"},{"title":"Add Minor Things to Django for templating","date_published":"2025-06-15T21:36:00+02:00","date_modified":"2026-07-16T22:49:21+02:00","id":"https://fundor333.com/post/2025/add-minor-things-to-django/","url":"https://fundor333.com/post/2025/add-minor-things-to-django/","tags":["django","coding","dev","fingerfood"],"content_html":"\u003cp\u003eMore and more time I need some little thing for templating:\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003eThe date fild of a form with the right input type for the page\u003c/li\u003e\n\u003cli\u003eA link with all the get parameters of the current page (form, paginator, etc\u0026hellip;) and one added\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch2 id=\"the-code\" class=\"no-underline \"\u003e\n  \u003ca href=\"#the-code\"\u003e\n    \u003ci class=\"fa-whiteboard fa-semibold fa-angle-right\"\u003e\u003c/i\u003e\n    The Code\n  \u003c/a\u003e\n  \u003c/h2\u003e\n\u003cp\u003eThis little code is mine but you can use it on all your project without thinking. If you find an error comment or webmention or replay with activity pub to my toot\u003c/p\u003e\n\u003ch3 id=\"date-field-for-django-form\" class=\"no-underline \"\u003e\n  \u003ca href=\"#date-field-for-django-form\"\u003e\n    \u003ci class=\"fa-whiteboard fa-semibold fa-angle-right\"\u003e\u003c/i\u003e\u003ci class=\"fa-whiteboard fa-semibold fa-angle-right\"\u003e\u003c/i\u003e\n    Date Field for Django Form\n  \u003c/a\u003e\n  \u003c/h3\u003e\n\u003cp\u003eThis is the widget I add to the django form for adding the right input type.\u003c/p\u003e\n\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;\"\u003e\u003ccode class=\"language-python\" data-lang=\"python\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#f92672\"\u003efrom\u003c/span\u003e django.forms \u003cspan style=\"color:#f92672\"\u003eimport\u003c/span\u003e TextInput\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#66d9ef\"\u003eclass\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003eDateInput\u003c/span\u003e(TextInput):\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    input_type \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;date\u0026#34;\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003eI need this because the css/js framework I use add a data picker if you fill the input_type\u003c/p\u003e\n\u003ch3 id=\"tag-for-changekeep-a-field\" class=\"no-underline \"\u003e\n  \u003ca href=\"#tag-for-changekeep-a-field\"\u003e\n    \u003ci class=\"fa-whiteboard fa-semibold fa-angle-right\"\u003e\u003c/i\u003e\u003ci class=\"fa-whiteboard fa-semibold fa-angle-right\"\u003e\u003c/i\u003e\n    Tag for change/keep a field\n  \u003c/a\u003e\n  \u003c/h3\u003e\n\u003cp\u003eSometime I need to edit or add a get parameter in a link, like when you change the view from list to grid (for example).\nSo I coded this simple tag.\u003c/p\u003e\n\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;\"\u003e\u003ccode class=\"language-python\" data-lang=\"python\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#f92672\"\u003efrom\u003c/span\u003e django \u003cspan style=\"color:#f92672\"\u003eimport\u003c/span\u003e template\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eregister \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e template\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003eLibrary()\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#a6e22e\"\u003e@register.simple_tag\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#66d9ef\"\u003edef\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003eurl_replace\u003c/span\u003e(request, field, value):\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    dict_ \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e request\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003eGET\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003ecopy()\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    dict_[field] \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e value\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003ereturn\u003c/span\u003e dict_\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003eurlencode()\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003ethe only thing it does is change or add a value into the list of existing value.\u003c/p\u003e\n\u003cp\u003eFor example\u003c/p\u003e\n\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;\"\u003e\u003ccode class=\"language-jinja\" data-lang=\"jinja\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u0026lt;a href:\u0026#34;https://fundor333.com?\u003cspan style=\"color:#75715e\"\u003e{%\u003c/span\u003e \u003cspan style=\"color:#66d9ef\"\u003eurl_replace_diff\u003c/span\u003e request \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;page\u0026#39;\u003c/span\u003e page_obj.page_number \u003cspan style=\"color:#75715e\"\u003e%}\u003c/span\u003e\u0026#34;\u0026gt;Link\u0026lt;/a\u0026gt;\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003eIn this one I pass the pagination number to the new page. Why? Because I need to have the current page and all the serch filter also in the new page and this is the cleaner way WITHOUT using Js (I need control and Js is not controll)\u003c/p\u003e\n","content_text":"More and more time I need some little thing for templating:\nThe date fild of a form with the right input type for the page A link with all the get parameters of the current page (form, paginator, etc\u0026hellip;) and one added The Code This little code is mine but you can use it on all your project without thinking. If you find an error comment or webmention or replay with activity pub to my toot\nDate Field for Django Form This is the widget I add to the django form for adding the right input type.\nfrom django.forms import TextInput class DateInput(TextInput): input_type = \u0026#34;date\u0026#34;I need this because the css/js framework I use add a data picker if you fill the input_type\nTag for change/keep a field Sometime I need to edit or add a get parameter in a link, like when you change the view from list to grid (for example). So I coded this simple tag.\nfrom django import template register = template.Library() @register.simple_tag def url_replace(request, field, value): dict_ = request.GET.copy() dict_[field] = value return dict_.urlencode()the only thing it does is change or add a value into the list of existing value.\nFor example\n\u0026lt;a href:\u0026#34;https://fundor333.com?{% url_replace_diff request \u0026#39;page\u0026#39; page_obj.page_number %}\u0026#34;\u0026gt;Link\u0026lt;/a\u0026gt;In this one I pass the pagination number to the new page. Why? Because I need to have the current page and all the serch filter also in the new page and this is the cleaner way WITHOUT using Js (I need control and Js is not controll)\n","image":"https://fundor333.com/post/2025/add-minor-things-to-django/cover.png","banner_image":"https://fundor333.com/post/2025/add-minor-things-to-django/cover.png"},{"title":"So This Is Why I Sometime Reset the Feed Reader of Friends","date_published":"2025-05-31T12:32:59+02:00","date_modified":"2026-07-16T22:49:21+02:00","id":"https://fundor333.com/post/2025/so-this-is-why-i-sometime-reset-the-feed-reader-of-friends/","url":"https://fundor333.com/post/2025/so-this-is-why-i-sometime-reset-the-feed-reader-of-friends/","tags":["feed","atom","rss","coding","rant"],"content_html":"\u003cp\u003eI have a friend who read my blog using my feed. And sometime he pings me for some problem with the feed, like a drop of all the article as new\u003c/p\u003e\n\n\n\n\n\n\n\n\n    \n    \n        \n        \n    \n\n    \n        \u003cdiv class=\"toot\"\u003e\n            \u003cdiv class=\"toot-header\"\u003e\n                \u003ca class=\"toot-profile\" href=\"https://social.lol/@robb\" rel=\"noopener\"\u003e\n                    \u003cimg src=\"https://s3.eu-central-003.backblazeb2.com/social-lol-media/accounts/avatars/109/523/762/776/095/110/original/548f0c6ecfffa5f1.jpg\"\n                         alt=\"Avatar for @robb@social.lol\"\n                         loading=\"lazy\"\u003e\n                \u003c/a\u003e\n                \u003cdiv class=\"toot-author\"\u003e\n                    \u003ca class=\"toot-author-name\"\n                       href=\"https://social.lol/@robb\"\n                       rel=\"noopener\"\u003eRobb Knight\u003c/a\u003e\n                    \u003ca class=\"toot-author-handle\"\n                       href=\"https://social.lol/@robb\"\n                       rel=\"noopener\"\u003e@robb@social.lol\u003c/a\u003e\n                \u003c/div\u003e\n            \u003c/div\u003e\n\n            \u003cdiv class=\"toot-content\"\u003e\u003cp\u003eWhen I open my RSS reader and it has over 200 unread items, I know one of you has messed up your rss feeds\u003c/p\u003e\u003cp\u003e📌 \u003ca href=\"https://rknight.me/notes/202501190902/\" target=\"_blank\" rel=\"nofollow noopener\" translate=\"no\"\u003e\u003cspan class=\"invisible\"\u003ehttps://\u003c/span\u003e\u003cspan class=\"\"\u003erknight.me/notes/202501190902/\u003c/span\u003e\u003cspan class=\"invisible\"\u003e\u003c/span\u003e\u003c/a\u003e\u003c/p\u003e\u003c/div\u003e\n\n            \n\n            \u003cdiv class=\"toot-footer\"\u003e\n                \u003ca href=\"https://social.lol@robb/status/113854214799861227\"\n                   class=\"toot-date\"\n                   rel=\"noopener\"\u003e9:04 AM · Jan 19, 2025\u003c/a\u003e\n            \u003c/div\u003e\n        \u003c/div\u003e\n    \n\n\n\n\n\n\n\n\n\n\n    \n    \n        \n        \n    \n\n    \n        \u003cdiv class=\"toot\"\u003e\n            \u003cdiv class=\"toot-header\"\u003e\n                \u003ca class=\"toot-profile\" href=\"https://mastodon.social/@andreagrandi\" rel=\"noopener\"\u003e\n                    \u003cimg src=\"https://files.mastodon.social/accounts/avatars/000/299/643/original/a1fe54a6da8006ce.jpg\"\n                         alt=\"Avatar for @andreagrandi@mastodon.social\"\n                         loading=\"lazy\"\u003e\n                \u003c/a\u003e\n                \u003cdiv class=\"toot-author\"\u003e\n                    \u003ca class=\"toot-author-name\"\n                       href=\"https://mastodon.social/@andreagrandi\"\n                       rel=\"noopener\"\u003eAndrea Grandi 🦕\u003c/a\u003e\n                    \u003ca class=\"toot-author-handle\"\n                       href=\"https://mastodon.social/@andreagrandi\"\n                       rel=\"noopener\"\u003e@andreagrandi@mastodon.social\u003c/a\u003e\n                \u003c/div\u003e\n            \u003c/div\u003e\n\n            \u003cdiv class=\"toot-content\"\u003e\u003cp\u003e\u003cspan class=\"h-card\" translate=\"no\"\u003e\u003ca href=\"https://social.lol/@robb\" class=\"u-url mention\"\u003e@\u003cspan\u003erobb\u003c/span\u003e\u003c/a\u003e\u003c/span\u003e I think my friend \u003cspan class=\"h-card\" translate=\"no\"\u003e\u003ca href=\"https://mastodon.social/@fundor333\" class=\"u-url mention\"\u003e@\u003cspan\u003efundor333\u003c/span\u003e\u003c/a\u003e\u003c/span\u003e ears must be burning right now :D\u003c/p\u003e\u003c/div\u003e\n\n            \n\n            \u003cdiv class=\"toot-footer\"\u003e\n                \u003ca href=\"https://mastodon.social@andreagrandi/status/113854638640440084\"\n                   class=\"toot-date\"\n                   rel=\"noopener\"\u003e10:51 AM · Jan 19, 2025\u003c/a\u003e\n            \u003c/div\u003e\n        \u003c/div\u003e\n    \n\n\n\u003cp\u003eAnd after read some other post with the same problem ( \u003ca class=\"a-post interlink-script\" href=\"https://rknight.me/notes/202501190902/\"   target=\"_blank\"\u003eRobb Knight problem with feed reader\u0026nbsp;\u0026nbsp;\u003ci class=\"fa-whiteboard fa-semibold fa-link\"\u003e\u003c/i\u003e\u003c/a\u003e\n \u003ca class=\"a-post interlink-script\" href=\"https://kevquirk.com/notes/20250528-1702?utm_source=fundor333.com\u0026amp;utm_medium=link\u0026amp;utm_campaign=blogging\u0026amp;ref=fundor333.com\"   target=\"_blank\"\u003eKev other problem with feed reader\u0026nbsp;\u0026nbsp;\u003ci class=\"fa-whiteboard fa-semibold fa-link\"\u003e\u003c/i\u003e\u003c/a\u003e\n ) I understand a little this: Atom is newer and superior than Rss.\u003c/p\u003e\n\u003ch2 id=\"atom-vs-rss\" class=\"no-underline \"\u003e\n  \u003ca href=\"#atom-vs-rss\"\u003e\n    \u003ci class=\"fa-whiteboard fa-semibold fa-angle-right\"\u003e\u003c/i\u003e\n    Atom vs Rss\n  \u003c/a\u003e\n  \u003c/h2\u003e\n\u003cp\u003eAtom is the newer one, born after the RSS and after fix a lot of the RSS bugs like:\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003eYou have a strict format for checking and validation in Atom\u003c/li\u003e\n\u003cli\u003eRSS is simpler but less strict and it is riddled with ambiguities which lead to inconsistency of interpretation\u003c/li\u003e\n\u003cli\u003eYou have a unique id for the feed in Atom\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eThe last one is the one I was searching\u0026hellip;\u003c/p\u003e\n\u003ch2 id=\"the-answer\" class=\"no-underline \"\u003e\n  \u003ca href=\"#the-answer\"\u003e\n    \u003ci class=\"fa-whiteboard fa-semibold fa-angle-right\"\u003e\u003c/i\u003e\n    The Answer\n  \u003c/a\u003e\n  \u003c/h2\u003e\n\u003cp\u003eThe feed reader find the new feed (new because you change the url or you change the serverside code) and check:\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003eAtom Feed: the reader find the same ID so is the same feed\u003c/li\u003e\n\u003cli\u003eRSS Feed: the reader don\u0026rsquo;t find the ID and find something different not in the items part so it is a new one\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eSo I add the JsonFeed and AtomFeed to the blog for give the reader multiple option for the feed!\u003c/p\u003e\n\u003cp\u003eYou can find all at \u003ca class=\"a-post interlink-script\" href=\"https://fundor333.com/feeds/\"  \u003ethis link\u003c/a\u003e\n\u003c/p\u003e\n","content_text":"I have a friend who read my blog using my feed. And sometime he pings me for some problem with the feed, like a drop of all the article as new\nRobb Knight @robb@social.lol When I open my RSS reader and it has over 200 unread items, I know one of you has messed up your rss feeds\n📌 https://rknight.me/notes/202501190902/\n9:04 AM · Jan 19, 2025 Andrea Grandi 🦕 @andreagrandi@mastodon.social @robb I think my friend @fundor333 ears must be burning right now :D\n10:51 AM · Jan 19, 2025 And after read some other post with the same problem ( Robb Knight problem with feed reader\u0026nbsp;\u0026nbsp; Kev other problem with feed reader\u0026nbsp;\u0026nbsp; ) I understand a little this: Atom is newer and superior than Rss.\nAtom vs Rss Atom is the newer one, born after the RSS and after fix a lot of the RSS bugs like:\nYou have a strict format for checking and validation in Atom RSS is simpler but less strict and it is riddled with ambiguities which lead to inconsistency of interpretation You have a unique id for the feed in Atom The last one is the one I was searching\u0026hellip;\nThe Answer The feed reader find the new feed (new because you change the url or you change the serverside code) and check:\nAtom Feed: the reader find the same ID so is the same feed RSS Feed: the reader don\u0026rsquo;t find the ID and find something different not in the items part so it is a new one So I add the JsonFeed and AtomFeed to the blog for give the reader multiple option for the feed!\nYou can find all at this link ","image":"https://fundor333.com/post/2025/so-this-is-why-i-sometime-reset-the-feed-reader-of-friends/cover.png","banner_image":"https://fundor333.com/post/2025/so-this-is-why-i-sometime-reset-the-feed-reader-of-friends/cover.png"},{"title":"Having a Webring Into 2025","date_published":"2025-05-24T12:11:42+02:00","date_modified":"2026-07-16T22:49:21+02:00","id":"https://fundor333.com/post/2025/webring-into-2025/","url":"https://fundor333.com/post/2025/webring-into-2025/","tags":["webring","indieweb","rant"],"content_html":"\u003cp\u003eOnce upon a time Internet was different. No social media, no search engine, no fiber\u0026hellip;\nSo how people find new site? Because the internet users share link into the blogs.\u003c/p\u003e\n\u003cp\u003eAnd one of the best way to share other blog without filling a webpage with links was the WebRing.\u003c/p\u003e\n\u003ch2 id=\"webring\" class=\"no-underline \"\u003e\n  \u003ca href=\"#webring\"\u003e\n    \u003ci class=\"fa-whiteboard fa-semibold fa-angle-right\"\u003e\u003c/i\u003e\n    WebRing?\n  \u003c/a\u003e\n  \u003c/h2\u003e\n\u003cp\u003eFor \u003ca class=\"a-post interlink-script\" href=\"https://en.wikipedia.org/wiki/Webring\"   target=\"_blank\"\u003eWikipedia\u0026nbsp;\u0026nbsp;\u003ci class=\"fa-whiteboard fa-semibold fa-link\"\u003e\u003c/i\u003e\u003c/a\u003e\n a Webring is\u003c/p\u003e\n\u003cblockquote\u003e\n\u003cp\u003eA webring (or web ring) is a collection of websites linked together in a circular structure, usually organized around a specific theme, and often educational or social.[1] They were popular in the 1990s and early 2000s, particularly among amateur websites.\u003c/p\u003e\n\u003c/blockquote\u003e\n\u003cp\u003eToday, with the Search Engin owned by the big tec and the AI being part of the mayor Search Engine we need more than ever list of human web pages to read and less AI generated post.\u003c/p\u003e\n\u003ch2 id=\"for-example\" class=\"no-underline \"\u003e\n  \u003ca href=\"#for-example\"\u003e\n    \u003ci class=\"fa-whiteboard fa-semibold fa-angle-right\"\u003e\u003c/i\u003e\n    For example?\n  \u003c/a\u003e\n  \u003c/h2\u003e\n\u003cp\u003eSome example of WebRing? This are some type of WebRing\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e\u003cem\u003eA themed WebRing\u003c/em\u003e Like a \u003ca class=\"a-post interlink-script\" href=\"https://djangowebring.com/\"   target=\"_blank\"\u003eWebRing about Python\u0026nbsp;\u0026nbsp;\u003ci class=\"fa-whiteboard fa-semibold fa-link\"\u003e\u003c/i\u003e\u003c/a\u003e\n\u003c/li\u003e\n\u003cli\u003e\u003cem\u003eAn Inspirational WebRing\u003c/em\u003e Like \u003ca class=\"a-post interlink-script\" href=\"https://webring.xxiivv.com/\"   target=\"_blank\"\u003eone for dev and artist\u0026nbsp;\u0026nbsp;\u003ci class=\"fa-whiteboard fa-semibold fa-link\"\u003e\u003c/i\u003e\u003c/a\u003e\n\u003c/li\u003e\n\u003cli\u003e\u003cem\u003eOne for Group of People\u003c/em\u003e Like \u003ca class=\"a-post interlink-script\" href=\"https://webring.recurse.com/\"   target=\"_blank\"\u003eone for onl;y personal site\u0026nbsp;\u0026nbsp;\u003ci class=\"fa-whiteboard fa-semibold fa-link\"\u003e\u003c/i\u003e\u003c/a\u003e\n\u003c/li\u003e\n\u003cli\u003e\u003cem\u003eOne for a Community\u003c/em\u003e Like \u003ca class=\"a-post interlink-script\" href=\"https://xn--sr8hvo.ws/directory\"   target=\"_blank\"\u003eone about IndieWeb\u0026nbsp;\u0026nbsp;\u003ci class=\"fa-whiteboard fa-semibold fa-link\"\u003e\u003c/i\u003e\u003c/a\u003e\n\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eIf you don\u0026rsquo;t find a WebRing for your \u0026ldquo;community\u0026rdquo;, you can create a new one with a tutorial ( \u003ca class=\"a-post interlink-script\" href=\"https://mxb.dev/blog/webring-kit/\"   target=\"_blank\"\u003eA Webring Kit\u0026nbsp;\u0026nbsp;\u003ci class=\"fa-whiteboard fa-semibold fa-link\"\u003e\u003c/i\u003e\u003c/a\u003e\n ) and a framework for making WebRing ( \u003ca class=\"a-post interlink-script\" href=\"https://github.com/maxboeck/webring\"   target=\"_blank\"\u003eGitHub Repo from A Webring Kit\u0026nbsp;\u0026nbsp;\u003ci class=\"fa-whiteboard fa-semibold fa-link\"\u003e\u003c/i\u003e\u003c/a\u003e\n )\u003c/p\u003e\n\u003cp\u003eRemember, this is a free way to have more traffic inside your site and for build your community\u003c/p\u003e\n","content_text":"Once upon a time Internet was different. No social media, no search engine, no fiber\u0026hellip; So how people find new site? Because the internet users share link into the blogs.\nAnd one of the best way to share other blog without filling a webpage with links was the WebRing.\nWebRing? For Wikipedia\u0026nbsp;\u0026nbsp; a Webring is\nA webring (or web ring) is a collection of websites linked together in a circular structure, usually organized around a specific theme, and often educational or social.[1] They were popular in the 1990s and early 2000s, particularly among amateur websites.\nToday, with the Search Engin owned by the big tec and the AI being part of the mayor Search Engine we need more than ever list of human web pages to read and less AI generated post.\nFor example? Some example of WebRing? This are some type of WebRing\nA themed WebRing Like a WebRing about Python\u0026nbsp;\u0026nbsp; An Inspirational WebRing Like one for dev and artist\u0026nbsp;\u0026nbsp; One for Group of People Like one for onl;y personal site\u0026nbsp;\u0026nbsp; One for a Community Like one about IndieWeb\u0026nbsp;\u0026nbsp; If you don\u0026rsquo;t find a WebRing for your \u0026ldquo;community\u0026rdquo;, you can create a new one with a tutorial ( A Webring Kit\u0026nbsp;\u0026nbsp; ) and a framework for making WebRing ( GitHub Repo from A Webring Kit\u0026nbsp;\u0026nbsp; )\nRemember, this is a free way to have more traffic inside your site and for build your community\n","image":"https://fundor333.com/post/2025/webring-into-2025/cover.png","banner_image":"https://fundor333.com/post/2025/webring-into-2025/cover.png"},{"title":"Django Generate Barcode With Reportlab","date_published":"2025-05-19T12:30:00+02:00","date_modified":"2026-07-16T22:49:21+02:00","id":"https://fundor333.com/post/2025/django-generate-barcode-with-reportlab/","url":"https://fundor333.com/post/2025/django-generate-barcode-with-reportlab/","tags":["reportlab","django","barcode","qrcode","dev"],"content_html":"\u003cp\u003eAfter \u003ca class=\"a-post interlink-script\" href=\"https://fundor333.com/post/2022/django-with-barcode-and-qrcode/\"   target=\"_blank\"\u003eDjango With Barcode and Qrcode\u0026nbsp;\u0026nbsp;\u003ci class=\"fa-whiteboard fa-semibold fa-link\"\u003e\u003c/i\u003e\u003c/a\u003e\n and \u003ca class=\"a-post interlink-script\" href=\"https://fundor333.com/post/2022/django-return-pdf-with-reportlab/\"   target=\"_blank\"\u003eDjango Return Pdf With Reportlab\u0026nbsp;\u0026nbsp;\u003ci class=\"fa-whiteboard fa-semibold fa-link\"\u003e\u003c/i\u003e\u003c/a\u003e\n I need something new in my Django server. I need a barcode generator for labeling stuffs.\u003c/p\u003e\n\u003ch2 id=\"the-problem\" class=\"no-underline \"\u003e\n  \u003ca href=\"#the-problem\"\u003e\n    \u003ci class=\"fa-whiteboard fa-semibold fa-angle-right\"\u003e\u003c/i\u003e\n    The problem\n  \u003c/a\u003e\n  \u003c/h2\u003e\n\u003cp\u003eEvery code is a solution to a pratical problem. In this case I need to make the barcode labels with text for keep an inventory.\nThe basic solution is generate a pdf/img file to print into sticker\u0026rsquo;s paper and cut it after.\u003c/p\u003e\n\u003cp\u003e\u003cimg  class=\"center-img u-photo \"  src=\"barcode.png\" alt=\"Barcode Example\"\u003e\u003c/p\u003e\n\u003cp\u003eSo, I need the data to convert into lable (the string on top to the barcode) and the barcode (or the qrcode) as in the screenshot, so I wrote this code for do it for pages and ready to print and stick it all around the world!\u003c/p\u003e\n\u003ch2 id=\"code\" class=\"no-underline \"\u003e\n  \u003ca href=\"#code\"\u003e\n    \u003ci class=\"fa-whiteboard fa-semibold fa-angle-right\"\u003e\u003c/i\u003e\n    Code\n  \u003c/a\u003e\n  \u003c/h2\u003e\n\u003ch3 id=\"the-view\" class=\"no-underline \"\u003e\n  \u003ca href=\"#the-view\"\u003e\n    \u003ci class=\"fa-whiteboard fa-semibold fa-angle-right\"\u003e\u003c/i\u003e\u003ci class=\"fa-whiteboard fa-semibold fa-angle-right\"\u003e\u003c/i\u003e\n    The view\n  \u003c/a\u003e\n  \u003c/h3\u003e\n\u003cp\u003eThis code is the view for generating download link for the pdf with all the barcode.\u003c/p\u003e\n\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;\"\u003e\u003ccode class=\"language-python\" data-lang=\"python\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#f92672\"\u003efrom\u003c/span\u003e django.views.generic \u003cspan style=\"color:#f92672\"\u003eimport\u003c/span\u003e View\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#66d9ef\"\u003eclass\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003eExampleBarcodePdf\u003c/span\u003e(View):\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    bar_height \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#66d9ef\"\u003eNone\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    position_text_y \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#66d9ef\"\u003eNone\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    filename \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;ExampleBarCode.pdf\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003edef\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003eget\u003c/span\u003e(self, request, \u003cspan style=\"color:#f92672\"\u003e*\u003c/span\u003eargs, \u003cspan style=\"color:#f92672\"\u003e**\u003c/span\u003ekwargs):\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      super()\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003eget(request, \u003cspan style=\"color:#f92672\"\u003e*\u003c/span\u003eargs, \u003cspan style=\"color:#f92672\"\u003e**\u003c/span\u003ekwargs)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      response \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e HttpResponse(content_type\u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;application/pdf\u0026#34;\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      response[\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;Content-Disposition\u0026#34;\u003c/span\u003e] \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e (\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e          \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;attachment; filename=\u0026#34;\u0026#39;\u003c/span\u003e \u003cspan style=\"color:#f92672\"\u003e+\u003c/span\u003e self\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003efilename \u003cspan style=\"color:#f92672\"\u003e+\u003c/span\u003e \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;\u0026#34;\u0026#39;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      )\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      a4p \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e A4PrinterBarcode()\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      pdf \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e a4p\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003eget_pdf(\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e          buffer\u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003eBytesIO(),\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e          datas\u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e[{barcode:\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;0000000000000\u0026#34;\u003c/span\u003e, \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;label\u0026#34;\u003c/span\u003e}, {\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;999999999999\u0026#34;\u003c/span\u003e, \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;other label\u0026#34;\u003c/span\u003e}],\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e          bar_height\u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003eself\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003ebar_height,\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e          position_text_y\u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003eself\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003eposition_text_y,\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      )\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      response\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003ewrite(pdf)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#66d9ef\"\u003ereturn\u003c/span\u003e response\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003ch3 id=\"the-pdf-generator\" class=\"no-underline \"\u003e\n  \u003ca href=\"#the-pdf-generator\"\u003e\n    \u003ci class=\"fa-whiteboard fa-semibold fa-angle-right\"\u003e\u003c/i\u003e\u003ci class=\"fa-whiteboard fa-semibold fa-angle-right\"\u003e\u003c/i\u003e\n    The pdf generator\n  \u003c/a\u003e\n  \u003c/h3\u003e\n\u003cp\u003eThis is the \u0026ldquo;printer\u0026rdquo; the code for generate pdf.\nAfter the import you find the constant with define the pdf.ß\u003c/p\u003e\n\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;\"\u003e\u003ccode class=\"language-python\" data-lang=\"python\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#f92672\"\u003efrom\u003c/span\u003e reportlab.graphics.barcode.eanbc \u003cspan style=\"color:#f92672\"\u003eimport\u003c/span\u003e Ean13BarcodeWidget\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#f92672\"\u003efrom\u003c/span\u003e reportlab.graphics.shapes \u003cspan style=\"color:#f92672\"\u003eimport\u003c/span\u003e Drawing\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#f92672\"\u003efrom\u003c/span\u003e reportlab.graphics.shapes \u003cspan style=\"color:#f92672\"\u003eimport\u003c/span\u003e String\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#f92672\"\u003efrom\u003c/span\u003e reportlab.lib.pagesizes \u003cspan style=\"color:#f92672\"\u003eimport\u003c/span\u003e A4\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#f92672\"\u003efrom\u003c/span\u003e reportlab.pdfgen \u003cspan style=\"color:#f92672\"\u003eimport\u003c/span\u003e canvas\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003ePAGESIZE \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e A4\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eNUM_LABELS_X \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#ae81ff\"\u003e3\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eNUM_LABELS_Y \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#ae81ff\"\u003e8\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eBAR_WIDTH \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#ae81ff\"\u003e1.5\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eBAR_HEIGHT \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#ae81ff\"\u003e51.0\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eTEXT_Y \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#ae81ff\"\u003e80\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eBARCODE_Y \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#ae81ff\"\u003e17\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eFONT_SIZE \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#ae81ff\"\u003e8\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eLABEL_WIDTH \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e PAGESIZE[\u003cspan style=\"color:#ae81ff\"\u003e0\u003c/span\u003e] \u003cspan style=\"color:#f92672\"\u003e/\u003c/span\u003e NUM_LABELS_X\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eLABEL_HEIGHT \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e PAGESIZE[\u003cspan style=\"color:#ae81ff\"\u003e1\u003c/span\u003e] \u003cspan style=\"color:#f92672\"\u003e/\u003c/span\u003e NUM_LABELS_Y\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eSHEET_TOP \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e PAGESIZE[\u003cspan style=\"color:#ae81ff\"\u003e1\u003c/span\u003e]\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#66d9ef\"\u003eclass\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003eA4PrinterBarcode\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003edef\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003egenerate_label\u003c/span\u003e(\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        self,\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        ean13: str,\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        description: str,\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        label_w: float \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#ae81ff\"\u003e0.0\u003c/span\u003e,\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        label_h: float \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#ae81ff\"\u003e0.0\u003c/span\u003e,\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        bar_with: float \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e BAR_WIDTH,\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        bar_height: float \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e BAR_HEIGHT,\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        postion_text_y: float \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e TEXT_Y,\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        font_size: int \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e FONT_SIZE,\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    ) \u003cspan style=\"color:#f92672\"\u003e-\u0026gt;\u003c/span\u003e Drawing:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;\u0026#34;\u0026#34;\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#e6db74\"\u003e        Generate a drawing with EAN-13 barcode and descriptive text.\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#e6db74\"\u003e        :param ean13: The EAN-13 Code.\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#e6db74\"\u003e        :type ean13: str\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#e6db74\"\u003e        :param description: Short product description.\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#e6db74\"\u003e        :type description: str\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#e6db74\"\u003e        :return: Drawing with barcode and description\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#e6db74\"\u003e        :rtype: Drawing\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#e6db74\"\u003e        \u0026#34;\u0026#34;\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#66d9ef\"\u003eif\u003c/span\u003e label_w \u003cspan style=\"color:#f92672\"\u003e==\u003c/span\u003e \u003cspan style=\"color:#ae81ff\"\u003e0.0\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            label_w \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e A4[\u003cspan style=\"color:#ae81ff\"\u003e0\u003c/span\u003e] \u003cspan style=\"color:#f92672\"\u003e/\u003c/span\u003e NUM_LABELS_X\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#66d9ef\"\u003eif\u003c/span\u003e label_h \u003cspan style=\"color:#f92672\"\u003e==\u003c/span\u003e \u003cspan style=\"color:#ae81ff\"\u003e0.0\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            label_h \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e A4[\u003cspan style=\"color:#ae81ff\"\u003e1\u003c/span\u003e] \u003cspan style=\"color:#f92672\"\u003e/\u003c/span\u003e NUM_LABELS_Y\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        text \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e String(\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#ae81ff\"\u003e0\u003c/span\u003e,\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            postion_text_y,\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            description,\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            fontName\u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;Helvetica\u0026#34;\u003c/span\u003e,\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            fontSize\u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003efont_size,\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            textAnchor\u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;middle\u0026#34;\u003c/span\u003e,\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        )\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        text\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003ex \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e label_w \u003cspan style=\"color:#f92672\"\u003e/\u003c/span\u003e \u003cspan style=\"color:#ae81ff\"\u003e2\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        barcode \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e Ean13BarcodeWidget(ean13)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        barcode\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003ebarWidth \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e bar_with\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        barcode\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003ebarHeight \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e bar_height\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        _, _, bw, _ \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e barcode\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003egetBounds()\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        barcode\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003ex \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e (label_w \u003cspan style=\"color:#f92672\"\u003e-\u003c/span\u003e bw) \u003cspan style=\"color:#f92672\"\u003e/\u003c/span\u003e \u003cspan style=\"color:#ae81ff\"\u003e2\u003c/span\u003e  \u003cspan style=\"color:#75715e\"\u003e# center barcode\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        barcode\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003ey \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#ae81ff\"\u003e18\u003c/span\u003e  \u003cspan style=\"color:#75715e\"\u003e# spacing from label bottom (pt)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        label_drawing \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e Drawing(label_w, label_h)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        label_drawing\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003eadd(text)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        label_drawing\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003eadd(barcode)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#66d9ef\"\u003ereturn\u003c/span\u003e label_drawing\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003edef\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003eget_pdf\u003c/span\u003e(\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        self,\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        buffer,\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        datas: list,\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        bar_height: float \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#66d9ef\"\u003eNone\u003c/span\u003e,\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        position_text_y: float \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#66d9ef\"\u003eNone\u003c/span\u003e,\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    ) \u003cspan style=\"color:#f92672\"\u003e-\u0026gt;\u003c/span\u003e bytes:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#66d9ef\"\u003eif\u003c/span\u003e bar_height \u003cspan style=\"color:#f92672\"\u003eis\u003c/span\u003e \u003cspan style=\"color:#66d9ef\"\u003eNone\u003c/span\u003e \u003cspan style=\"color:#f92672\"\u003eor\u003c/span\u003e bar_height \u003cspan style=\"color:#f92672\"\u003e\u0026lt;\u003c/span\u003e \u003cspan style=\"color:#ae81ff\"\u003e0\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            bar_height \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e BAR_HEIGHT\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#66d9ef\"\u003eif\u003c/span\u003e position_text_y \u003cspan style=\"color:#f92672\"\u003eis\u003c/span\u003e \u003cspan style=\"color:#66d9ef\"\u003eNone\u003c/span\u003e \u003cspan style=\"color:#f92672\"\u003eor\u003c/span\u003e position_text_y \u003cspan style=\"color:#f92672\"\u003e\u0026lt;\u003c/span\u003e \u003cspan style=\"color:#ae81ff\"\u003e0\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            position_text_y \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e TEXT_Y\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        p \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e canvas\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003eCanvas(buffer)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        j \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#ae81ff\"\u003e0\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#66d9ef\"\u003efor\u003c/span\u003e _ \u003cspan style=\"color:#f92672\"\u003ein\u003c/span\u003e range(len(datas) \u003cspan style=\"color:#f92672\"\u003e//\u003c/span\u003e (NUM_LABELS_X \u003cspan style=\"color:#f92672\"\u003e*\u003c/span\u003e NUM_LABELS_Y) \u003cspan style=\"color:#f92672\"\u003e+\u003c/span\u003e \u003cspan style=\"color:#ae81ff\"\u003e1\u003c/span\u003e):\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#66d9ef\"\u003efor\u003c/span\u003e u \u003cspan style=\"color:#f92672\"\u003ein\u003c/span\u003e range(\u003cspan style=\"color:#ae81ff\"\u003e0\u003c/span\u003e, NUM_LABELS_Y):\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                \u003cspan style=\"color:#66d9ef\"\u003efor\u003c/span\u003e i \u003cspan style=\"color:#f92672\"\u003ein\u003c/span\u003e range(\u003cspan style=\"color:#ae81ff\"\u003e0\u003c/span\u003e, NUM_LABELS_X):\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                    \u003cspan style=\"color:#66d9ef\"\u003eif\u003c/span\u003e j \u003cspan style=\"color:#f92672\"\u003e\u0026lt;\u003c/span\u003e len(datas):\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                        data \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e datas[j]\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                        cb \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e data\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003ebarcode\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                        desc \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e data\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003elabel\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                        \u003cspan style=\"color:#66d9ef\"\u003etry\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                            label \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e self\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003egenerate_label(\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                                ean13\u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003ecb,\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                                description\u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003edesc,\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                                bar_height\u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003ebar_height,\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                                postion_text_y\u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003eposition_text_y,\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                            )\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                            x \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e i \u003cspan style=\"color:#f92672\"\u003e*\u003c/span\u003e LABEL_WIDTH\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                            y \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e SHEET_TOP \u003cspan style=\"color:#f92672\"\u003e-\u003c/span\u003e LABEL_HEIGHT \u003cspan style=\"color:#f92672\"\u003e-\u003c/span\u003e u \u003cspan style=\"color:#f92672\"\u003e*\u003c/span\u003e LABEL_HEIGHT\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                            label\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003edrawOn(p, x, y)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                        \u003cspan style=\"color:#66d9ef\"\u003eexcept\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003eAttributeError\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                            \u003cspan style=\"color:#66d9ef\"\u003epass\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                        j \u003cspan style=\"color:#f92672\"\u003e+=\u003c/span\u003e \u003cspan style=\"color:#ae81ff\"\u003e1\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            p\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003eshowPage()\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        p\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003esave()\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        pdf \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e buffer\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003egetvalue()\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        buffer\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003eclose()\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#66d9ef\"\u003ereturn\u003c/span\u003e pdf\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003ch2 id=\"so-how-do-a4printerbarcode-work-\" class=\"no-underline \"\u003e\n  \u003ca href=\"#so-how-do-a4printerbarcode-work-\"\u003e\n    \u003ci class=\"fa-whiteboard fa-semibold fa-angle-right\"\u003e\u003c/i\u003e\n    So how do \u003cem\u003eA4PrinterBarcode\u003c/em\u003e work ?\n  \u003c/a\u003e\n  \u003c/h2\u003e\n\u003cp\u003eThe main concept of this class is to generate the \u0026ldquo;labels\u0026rdquo; (barcode and text) and put them into a grid pattern.\nSo we have two function:\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e\u003cem\u003egenerate_label\u003c/em\u003e generate the single \u0026ldquo;label\u0026rdquo;, one of the time\u003c/li\u003e\n\u003cli\u003e\u003cem\u003eget_pdf\u003c/em\u003e generate the pdf putting the \u0026ldquo;labels\u0026rdquo; in a grid pattern\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eIf you need, this class can be used without Django, in something like a \u003ca class=\"a-post interlink-script\" href=\"https://fundor333.com/post/2023/why-i-stop-making-script-and-start-to-make-bash-terminal-commands/\"   target=\"_blank\"\u003etool for terminal\u0026nbsp;\u0026nbsp;\u003ci class=\"fa-whiteboard fa-semibold fa-link\"\u003e\u003c/i\u003e\u003c/a\u003e\n\u003c/p\u003e\n","content_text":"After Django With Barcode and Qrcode\u0026nbsp;\u0026nbsp; and Django Return Pdf With Reportlab\u0026nbsp;\u0026nbsp; I need something new in my Django server. I need a barcode generator for labeling stuffs.\nThe problem Every code is a solution to a pratical problem. In this case I need to make the barcode labels with text for keep an inventory. The basic solution is generate a pdf/img file to print into sticker\u0026rsquo;s paper and cut it after.\nSo, I need the data to convert into lable (the string on top to the barcode) and the barcode (or the qrcode) as in the screenshot, so I wrote this code for do it for pages and ready to print and stick it all around the world!\nCode The view This code is the view for generating download link for the pdf with all the barcode.\nfrom django.views.generic import View class ExampleBarcodePdf(View): bar_height = None position_text_y = None filename = \u0026#34;ExampleBarCode.pdf\u0026#34; def get(self, request, *args, **kwargs): super().get(request, *args, **kwargs) response = HttpResponse(content_type=\u0026#34;application/pdf\u0026#34;) response[\u0026#34;Content-Disposition\u0026#34;] = ( \u0026#39;attachment; filename=\u0026#34;\u0026#39; + self.filename + \u0026#39;\u0026#34;\u0026#39; ) a4p = A4PrinterBarcode() pdf = a4p.get_pdf( buffer=BytesIO(), datas=[{barcode:\u0026#34;0000000000000\u0026#34;, \u0026#34;label\u0026#34;}, {\u0026#34;999999999999\u0026#34;, \u0026#34;other label\u0026#34;}], bar_height=self.bar_height, position_text_y=self.position_text_y, ) response.write(pdf) return response The pdf generator This is the \u0026ldquo;printer\u0026rdquo; the code for generate pdf. After the import you find the constant with define the pdf.ß\nfrom reportlab.graphics.barcode.eanbc import Ean13BarcodeWidget from reportlab.graphics.shapes import Drawing from reportlab.graphics.shapes import String from reportlab.lib.pagesizes import A4 from reportlab.pdfgen import canvas PAGESIZE = A4 NUM_LABELS_X = 3 NUM_LABELS_Y = 8 BAR_WIDTH = 1.5 BAR_HEIGHT = 51.0 TEXT_Y = 80 BARCODE_Y = 17 FONT_SIZE = 8 LABEL_WIDTH = PAGESIZE[0] / NUM_LABELS_X LABEL_HEIGHT = PAGESIZE[1] / NUM_LABELS_Y SHEET_TOP = PAGESIZE[1] class A4PrinterBarcode: def generate_label( self, ean13: str, description: str, label_w: float = 0.0, label_h: float = 0.0, bar_with: float = BAR_WIDTH, bar_height: float = BAR_HEIGHT, postion_text_y: float = TEXT_Y, font_size: int = FONT_SIZE, ) -\u0026gt; Drawing: \u0026#34;\u0026#34;\u0026#34; Generate a drawing with EAN-13 barcode and descriptive text. :param ean13: The EAN-13 Code. :type ean13: str :param description: Short product description. :type description: str :return: Drawing with barcode and description :rtype: Drawing \u0026#34;\u0026#34;\u0026#34; if label_w == 0.0: label_w = A4[0] / NUM_LABELS_X if label_h == 0.0: label_h = A4[1] / NUM_LABELS_Y text = String( 0, postion_text_y, description, fontName=\u0026#34;Helvetica\u0026#34;, fontSize=font_size, textAnchor=\u0026#34;middle\u0026#34;, ) text.x = label_w / 2 barcode = Ean13BarcodeWidget(ean13) barcode.barWidth = bar_with barcode.barHeight = bar_height _, _, bw, _ = barcode.getBounds() barcode.x = (label_w - bw) / 2 # center barcode barcode.y = 18 # spacing from label bottom (pt) label_drawing = Drawing(label_w, label_h) label_drawing.add(text) label_drawing.add(barcode) return label_drawing def get_pdf( self, buffer, datas: list, bar_height: float = None, position_text_y: float = None, ) -\u0026gt; bytes: if bar_height is None or bar_height \u0026lt; 0: bar_height = BAR_HEIGHT if position_text_y is None or position_text_y \u0026lt; 0: position_text_y = TEXT_Y p = canvas.Canvas(buffer) j = 0 for _ in range(len(datas) // (NUM_LABELS_X * NUM_LABELS_Y) + 1): for u in range(0, NUM_LABELS_Y): for i in range(0, NUM_LABELS_X): if j \u0026lt; len(datas): data = datas[j] cb = data.barcode desc = data.label try: label = self.generate_label( ean13=cb, description=desc, bar_height=bar_height, postion_text_y=position_text_y, ) x = i * LABEL_WIDTH y = SHEET_TOP - LABEL_HEIGHT - u * LABEL_HEIGHT label.drawOn(p, x, y) except AttributeError: pass j += 1 p.showPage() p.save() pdf = buffer.getvalue() buffer.close() return pdf So how do A4PrinterBarcode work ? The main concept of this class is to generate the \u0026ldquo;labels\u0026rdquo; (barcode and text) and put them into a grid pattern. So we have two function:\ngenerate_label generate the single \u0026ldquo;label\u0026rdquo;, one of the time get_pdf generate the pdf putting the \u0026ldquo;labels\u0026rdquo; in a grid pattern If you need, this class can be used without Django, in something like a tool for terminal\u0026nbsp;\u0026nbsp; ","image":"https://fundor333.com/post/2025/django-generate-barcode-with-reportlab/cover.png","banner_image":"https://fundor333.com/post/2025/django-generate-barcode-with-reportlab/cover.png"},{"title":"Activitypub vs Webmention Do You Need Them ?","date_published":"2025-05-16T07:23:27+02:00","date_modified":"2026-07-16T22:49:21+02:00","id":"https://fundor333.com/post/2025/activitypub-vs-webmention-do-you-need-them/","url":"https://fundor333.com/post/2025/activitypub-vs-webmention-do-you-need-them/","tags":["webmention","activitypub","indieweb","rant","dev"],"content_html":"\u003cp\u003eI have a lot of article about webmention because I implement them on my site/blog. And I use them ad comment, like sistem and more. But more I read about ActivityPub and the Feedverse more I thing it can be a good think to implement it insite your site for your content and for share to the Feedverse.\u003c/p\u003e\n\u003ch2 id=\"why-do-it\" class=\"no-underline \"\u003e\n  \u003ca href=\"#why-do-it\"\u003e\n    \u003ci class=\"fa-whiteboard fa-semibold fa-angle-right\"\u003e\u003c/i\u003e\n    Why do it?\n  \u003c/a\u003e\n  \u003c/h2\u003e\n\u003cp\u003eOne of the best arguments for having a personal ActivityPub site/server is you having a unique identity, don\u0026rsquo;t fragmenting your identity\u003csup id=\"fnref:1\"\u003e\u003ca href=\"#fn:1\" class=\"footnote-ref\" role=\"doc-noteref\"\u003e1\u003c/a\u003e\u003c/sup\u003e on multiple Feedverse accounts.\u003c/p\u003e\n\u003cp\u003eBut I implemented Webmention and stuff like \u003ca class=\"a-post interlink-script\" href=\"https://brid.gy/\"   target=\"_blank\"\u003eBrid\u0026nbsp;\u0026nbsp;\u003ci class=\"fa-whiteboard fa-semibold fa-link\"\u003e\u003c/i\u003e\u003c/a\u003e\n for having the likes, comments and all the stuff I have in the ActivityPub about my posts. So why I need to do it?\u003c/p\u003e\n\u003cp\u003eIf I need more reference to your post/article on the Feedverse, Mastodon has a function\u003csup id=\"fnref:2\"\u003e\u003ca href=\"#fn:2\" class=\"footnote-ref\" role=\"doc-noteref\"\u003e2\u003c/a\u003e\u003c/sup\u003e for show your account under your link making a link to your profile. It also easy to set up and some platform has a plugin for it (like for Wordpress) or easy articole online for your favorite platfome (for example this is for \u003ca class=\"a-post interlink-script\" href=\"https://onemanandhisblog.com/2024/10/adding-a-mastodon-author-to-ghost/\"   target=\"_blank\"\u003eGhost\u0026nbsp;\u0026nbsp;\u003ci class=\"fa-whiteboard fa-semibold fa-link\"\u003e\u003c/i\u003e\u003c/a\u003e\n).\u003c/p\u003e\n\u003cp\u003eBut if you aren\u0026rsquo;t in the FeedVerse you are loosing in a way in to a social media moviment which is groing with major players studing and testing the ground (Meta, Tumblr, with also X/Twitter looking without public testing) and more and more time pass, more and more service integrate the ActivityPub in their social/site/service.\u003c/p\u003e\n\u003cp\u003eI also have a lot of attention from the tech blogger, where if you don\u0026rsquo;t write about excitement\u003csup id=\"fnref:3\"\u003e\u003ca href=\"#fn:3\" class=\"footnote-ref\" role=\"doc-noteref\"\u003e3\u003c/a\u003e\u003c/sup\u003e you are writing about how to implement ActivityPub on your site[^4].\u003c/p\u003e\n\u003ch2 id=\"and-so-i-need-to-integrate-this-new-stuff-into-my-site\" class=\"no-underline \"\u003e\n  \u003ca href=\"#and-so-i-need-to-integrate-this-new-stuff-into-my-site\"\u003e\n    \u003ci class=\"fa-whiteboard fa-semibold fa-angle-right\"\u003e\u003c/i\u003e\n    And so? I need to integrate this new stuff into my site?\n  \u003c/a\u003e\n  \u003c/h2\u003e\n\u003cp\u003eNo and yes. If you want a presence in the FeedVerse you need to be active also there but no with a integration with the ActivityPub protocol: you can share it like the \u0026ldquo;old days\u0026rdquo;.\u003c/p\u003e\n\u003cp\u003eAlso having a ActivityPub implementation somewhere is a resource draining server so you need to think about how much money and time you want to spend on it.\u003c/p\u003e\n\u003cp\u003eIn the end Webmention and ActivityPub are two way to have more interaction with your site but you also need to now which interaction is better for your site.\u003c/p\u003e\n\u003cdiv class=\"footnotes\" role=\"doc-endnotes\"\u003e\n\u003chr\u003e\n\u003col\u003e\n\u003cli id=\"fn:1\"\u003e\n\u003cp\u003eTwo article about it \u003ca class=\"a-post interlink-script\" href=\"[Federated/Fragmentated]%28https://cogdogblog.com/2024/11/federated-fragmentated/?ref=jadin.me%29\"  \u003eFederated/Fragmentated\u003c/a\u003e\n and \u003ca class=\"a-post interlink-script\" href=\"https://jadin.me/who-is-this/\"   target=\"_blank\"\u003eWho is this?\u0026nbsp;\u0026nbsp;\u003ci class=\"fa-whiteboard fa-semibold fa-link\"\u003e\u003c/i\u003e\u003c/a\u003e\n\u0026#160;\u003ca href=\"#fnref:1\" class=\"footnote-backref\" role=\"doc-backlink\"\u003e\u0026#x21a9;\u0026#xfe0e;\u003c/a\u003e\u003c/p\u003e\n\u003c/li\u003e\n\u003cli id=\"fn:2\"\u003e\n\u003cp\u003ePost about it \u003ca class=\"a-post interlink-script\" href=\"https://blog.joinmastodon.org/2024/07/highlighting-journalism-on-mastodon/\"   target=\"_blank\"\u003eHighlighting journalism on Mastodon\u0026nbsp;\u0026nbsp;\u003ci class=\"fa-whiteboard fa-semibold fa-link\"\u003e\u003c/i\u003e\u003c/a\u003e\n\u0026#160;\u003ca href=\"#fnref:2\" class=\"footnote-backref\" role=\"doc-backlink\"\u003e\u0026#x21a9;\u0026#xfe0e;\u003c/a\u003e\u003c/p\u003e\n\u003c/li\u003e\n\u003cli id=\"fn:3\"\u003e\n\u003cp\u003eSome article about excitement \u003ca class=\"a-post interlink-script\" href=\"https://jadin.me/why-im-excited-about-ghost-getting-activitypub-support/\"   target=\"_blank\"\u003eWhy I\u0026rsquo;m excited about Ghost getting ActivityPub support\u0026nbsp;\u0026nbsp;\u003ci class=\"fa-whiteboard fa-semibold fa-link\"\u003e\u003c/i\u003e\u003c/a\u003e\n \u003ca class=\"a-post interlink-script\" href=\"https://onemanandhisblog.com/2025/03/the-federated-one-man-his-blog/\"   target=\"_blank\"\u003eThe federated One Man \u0026amp; His Blog\u0026nbsp;\u0026nbsp;\u003ci class=\"fa-whiteboard fa-semibold fa-link\"\u003e\u003c/i\u003e\u003c/a\u003e\n\n[^4] For example this article \u003ca class=\"a-post interlink-script\" href=\"https://maho.dev/2025/03/a-guide-to-implementing-activitypub-in-a-static-site-or-any-website-q1-2025-updates/\"   target=\"_blank\"\u003eA Guide to Implementing ActivityPub in a Static Site (or Any Website) - Q1 2025 Updates\u0026nbsp;\u0026nbsp;\u003ci class=\"fa-whiteboard fa-semibold fa-link\"\u003e\u003c/i\u003e\u003c/a\u003e\n\u0026#160;\u003ca href=\"#fnref:3\" class=\"footnote-backref\" role=\"doc-backlink\"\u003e\u0026#x21a9;\u0026#xfe0e;\u003c/a\u003e\u003c/p\u003e\n\u003c/li\u003e\n\u003c/ol\u003e\n\u003c/div\u003e\n","content_text":"I have a lot of article about webmention because I implement them on my site/blog. And I use them ad comment, like sistem and more. But more I read about ActivityPub and the Feedverse more I thing it can be a good think to implement it insite your site for your content and for share to the Feedverse.\nWhy do it? One of the best arguments for having a personal ActivityPub site/server is you having a unique identity, don\u0026rsquo;t fragmenting your identity1 on multiple Feedverse accounts.\nBut I implemented Webmention and stuff like Brid\u0026nbsp;\u0026nbsp; for having the likes, comments and all the stuff I have in the ActivityPub about my posts. So why I need to do it?\nIf I need more reference to your post/article on the Feedverse, Mastodon has a function2 for show your account under your link making a link to your profile. It also easy to set up and some platform has a plugin for it (like for Wordpress) or easy articole online for your favorite platfome (for example this is for Ghost\u0026nbsp;\u0026nbsp; ).\nBut if you aren\u0026rsquo;t in the FeedVerse you are loosing in a way in to a social media moviment which is groing with major players studing and testing the ground (Meta, Tumblr, with also X/Twitter looking without public testing) and more and more time pass, more and more service integrate the ActivityPub in their social/site/service.\nI also have a lot of attention from the tech blogger, where if you don\u0026rsquo;t write about excitement3 you are writing about how to implement ActivityPub on your site[^4].\nAnd so? I need to integrate this new stuff into my site? No and yes. If you want a presence in the FeedVerse you need to be active also there but no with a integration with the ActivityPub protocol: you can share it like the \u0026ldquo;old days\u0026rdquo;.\nAlso having a ActivityPub implementation somewhere is a resource draining server so you need to think about how much money and time you want to spend on it.\nIn the end Webmention and ActivityPub are two way to have more interaction with your site but you also need to now which interaction is better for your site.\nTwo article about it Federated/Fragmentated and Who is this?\u0026nbsp;\u0026nbsp; \u0026#160;\u0026#x21a9;\u0026#xfe0e;\nPost about it Highlighting journalism on Mastodon\u0026nbsp;\u0026nbsp; \u0026#160;\u0026#x21a9;\u0026#xfe0e;\nSome article about excitement Why I\u0026rsquo;m excited about Ghost getting ActivityPub support\u0026nbsp;\u0026nbsp; The federated One Man \u0026amp; His Blog\u0026nbsp;\u0026nbsp; [^4] For example this article A Guide to Implementing ActivityPub in a Static Site (or Any Website) - Q1 2025 Updates\u0026nbsp;\u0026nbsp; \u0026#160;\u0026#x21a9;\u0026#xfe0e;\n","image":"https://fundor333.com/post/2025/activitypub-vs-webmention-do-you-need-them/cover.png","banner_image":"https://fundor333.com/post/2025/activitypub-vs-webmention-do-you-need-them/cover.png"},{"title":"Csv From Django","date_published":"2025-04-18T12:23:09+02:00","date_modified":"2026-07-16T22:49:21+02:00","id":"https://fundor333.com/post/2025/csv-from-django/","url":"https://fundor333.com/post/2025/csv-from-django/","tags":["csv","django","dev","fingerfood"],"content_html":"\u003cp\u003eSome time you need to export a file into a specific format for some use like upload to the old system.\nIn this case I need to have a CSV file which another software fill.\u003c/p\u003e\n\u003ch2 id=\"the-code\" class=\"no-underline \"\u003e\n  \u003ca href=\"#the-code\"\u003e\n    \u003ci class=\"fa-whiteboard fa-semibold fa-angle-right\"\u003e\u003c/i\u003e\n    The code\n  \u003c/a\u003e\n  \u003c/h2\u003e\n\u003cp\u003eI wrote a ClassView for this case, this class. \u003csup id=\"fnref:1\"\u003e\u003ca href=\"#fn:1\" class=\"footnote-ref\" role=\"doc-noteref\"\u003e1\u003c/a\u003e\u003c/sup\u003e\u003c/p\u003e\n\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;\"\u003e\u003ccode class=\"language-python\" data-lang=\"python\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#66d9ef\"\u003eclass\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003eCsvCarsDownload\u003c/span\u003e(View):\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003edef\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003eget\u003c/span\u003e(self, request, \u003cspan style=\"color:#f92672\"\u003e*\u003c/span\u003eargs, \u003cspan style=\"color:#f92672\"\u003e**\u003c/span\u003ekwargs):\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        response \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e HttpResponse(content_type\u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;text/csv\u0026#34;\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        response[\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;Content-Disposition\u0026#34;\u003c/span\u003e] \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#e6db74\"\u003e\u0026#39;attachment; filename=\u0026#34;cars.csv\u0026#34;\u0026#39;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        my_dict \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e [{\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e          \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;brand\u0026#34;\u003c/span\u003e: \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;Ford\u0026#34;\u003c/span\u003e,\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e          \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;model\u0026#34;\u003c/span\u003e: \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;Mustang\u0026#34;\u003c/span\u003e,\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e          \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;year\u0026#34;\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e1964\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        }]\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        writer \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e csv\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003eDictWriter(\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            response, dialect\u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;excel\u0026#34;\u003c/span\u003e, fieldnames\u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003emy_dict[\u003cspan style=\"color:#ae81ff\"\u003e0\u003c/span\u003e]\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003ekeys()\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        )\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        writer\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003ewriteheader()\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#66d9ef\"\u003efor\u003c/span\u003e element \u003cspan style=\"color:#f92672\"\u003ein\u003c/span\u003e my_dict:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e          writer\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003ewriterow(element)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#66d9ef\"\u003ereturn\u003c/span\u003e response\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003eYou can change the type of the the CSV changing the \u003cstrong\u003edialect\u003c/strong\u003e with one of the type of the CSV dialect (excel, excel_tab, unix_dialect) and changing the \u003cstrong\u003emy_dict\u003c/strong\u003e with any type of list of dict.\u003c/p\u003e\n\u003cp\u003eWith this code you can use any Class Mixin from others module for add other functions like permission supports or loggeer configurations.\u003c/p\u003e\n\u003cdiv class=\"footnotes\" role=\"doc-endnotes\"\u003e\n\u003chr\u003e\n\u003col\u003e\n\u003cli id=\"fn:1\"\u003e\n\u003cp\u003eI don\u0026rsquo;t like coding functional view so I only code ClassViews\u0026#160;\u003ca href=\"#fnref:1\" class=\"footnote-backref\" role=\"doc-backlink\"\u003e\u0026#x21a9;\u0026#xfe0e;\u003c/a\u003e\u003c/p\u003e\n\u003c/li\u003e\n\u003c/ol\u003e\n\u003c/div\u003e\n","content_text":"Some time you need to export a file into a specific format for some use like upload to the old system. In this case I need to have a CSV file which another software fill.\nThe code I wrote a ClassView for this case, this class. 1\nclass CsvCarsDownload(View): def get(self, request, *args, **kwargs): response = HttpResponse(content_type=\u0026#34;text/csv\u0026#34;) response[\u0026#34;Content-Disposition\u0026#34;] = \u0026#39;attachment; filename=\u0026#34;cars.csv\u0026#34;\u0026#39; my_dict = [{ \u0026#34;brand\u0026#34;: \u0026#34;Ford\u0026#34;, \u0026#34;model\u0026#34;: \u0026#34;Mustang\u0026#34;, \u0026#34;year\u0026#34;: 1964 }] writer = csv.DictWriter( response, dialect=\u0026#34;excel\u0026#34;, fieldnames=my_dict[0].keys() ) writer.writeheader() for element in my_dict: writer.writerow(element) return responseYou can change the type of the the CSV changing the dialect with one of the type of the CSV dialect (excel, excel_tab, unix_dialect) and changing the my_dict with any type of list of dict.\nWith this code you can use any Class Mixin from others module for add other functions like permission supports or loggeer configurations.\nI don\u0026rsquo;t like coding functional view so I only code ClassViews\u0026#160;\u0026#x21a9;\u0026#xfe0e;\n","image":"https://fundor333.com/post/2025/csv-from-django/cover.png","banner_image":"https://fundor333.com/post/2025/csv-from-django/cover.png"},{"title":"Re:Using 'Re:' in Blog Titles","date_published":"2025-04-14T21:00:21+02:00","date_modified":"2026-07-16T22:49:21+02:00","id":"https://fundor333.com/post/2025/re-using-re-in-blog-titles/","url":"https://fundor333.com/post/2025/re-using-re-in-blog-titles/","tags":["microformat","indieweb","rant"],"content_html":"\u003cp\u003eFollowing the post from \u003ca class=\"a-post interlink-script\" href=\"https://rubenerd.com/using-re-in-blog-titles/\"   target=\"_blank\"\u003eRuben\u0026nbsp;\u0026nbsp;\u003ci class=\"fa-whiteboard fa-semibold fa-link\"\u003e\u003c/i\u003e\u003c/a\u003e\n I start imitating this idea and expand on it.\u003c/p\u003e\n\u003cblockquote\u003e\n\u003cp\u003e\u0026ldquo;Imitation is the sincerest form of flattery that mediocrity can pay to greatness.\u0026rdquo;\u003c/p\u003e\n\u003cp\u003eOscar Wilde\u003c/p\u003e\n\u003c/blockquote\u003e\n\u003cp\u003eThe basic idea come from a post by \u003ca class=\"a-post interlink-script\" href=\"https://brandons-journal.com/re-im-part-of-the-problem/\"   target=\"_blank\"\u003eBrandon\u0026rsquo;s Journal\u0026nbsp;\u0026nbsp;\u003ci class=\"fa-whiteboard fa-semibold fa-link\"\u003e\u003c/i\u003e\u003c/a\u003e\n where Brandon response to an article and use the \u003cstrong\u003eRe:\u003c/strong\u003e prefix, like a email threads in the title of the post\u0026hellip;\u003c/p\u003e\n\u003cp\u003eAnd I add a microformat following the IndieWeb stuff for the response tags.\nSo my post which are a \u0026ldquo;Re:\u0026rdquo; will have a \u003cstrong\u003eu-in-reply-to\u003c/strong\u003e in the class of the links for implementing the IndieWeb, like in this article.\u003c/p\u003e\n","content_text":"Following the post from Ruben\u0026nbsp;\u0026nbsp; I start imitating this idea and expand on it.\n\u0026ldquo;Imitation is the sincerest form of flattery that mediocrity can pay to greatness.\u0026rdquo;\nOscar Wilde\nThe basic idea come from a post by Brandon\u0026rsquo;s Journal\u0026nbsp;\u0026nbsp; where Brandon response to an article and use the Re: prefix, like a email threads in the title of the post\u0026hellip;\nAnd I add a microformat following the IndieWeb stuff for the response tags. So my post which are a \u0026ldquo;Re:\u0026rdquo; will have a u-in-reply-to in the class of the links for implementing the IndieWeb, like in this article.\n"},{"title":"Pages You Need in Your Blog","date_published":"2025-04-06T13:42:47+02:00","date_modified":"2026-07-16T22:49:21+02:00","id":"https://fundor333.com/post/2025/pages-you-need-in-your-blog/","url":"https://fundor333.com/post/2025/pages-you-need-in-your-blog/","tags":["dev","rant"],"content_html":"\u003cp\u003eMore and more blog I read and more and more I find that a lot of the dev blog and personal blog on the web has a lot of common pages but not the old \u003cem\u003eAbout\u003c/em\u003e or \u003cem\u003eContacts\u003c/em\u003e so I make this list of interesting pages types.\u003c/p\u003e\n\u003ch2 id=\"blogroll\" class=\"no-underline \"\u003e\n  \u003ca href=\"#blogroll\"\u003e\n    \u003ci class=\"fa-whiteboard fa-semibold fa-angle-right\"\u003e\u003c/i\u003e\n    Blogroll\n  \u003c/a\u003e\n  \u003c/h2\u003e\n\u003cp\u003eOne of the best page I find on a blog. This is a page where the blogger show a link of site/blog (a html page or a Opml file) of interesting stuff.\u003c/p\u003e\n\u003cp\u003eI find iteresting because I can have an idea about the blogger interest and I can find new and different source of post.\u003c/p\u003e\n\u003cp\u003eMine is \u003ca class=\"a-post interlink-script\" href=\"/blogroll\"  \u003ehere\u003c/a\u003e\n\u003c/p\u003e\n\u003ch2 id=\"connect\" class=\"no-underline \"\u003e\n  \u003ca href=\"#connect\"\u003e\n    \u003ci class=\"fa-whiteboard fa-semibold fa-angle-right\"\u003e\u003c/i\u003e\n    Connect\n  \u003c/a\u003e\n  \u003c/h2\u003e\n\u003cp\u003eHalf of the old \u003cem\u003eAbout Us\u003c/em\u003e page. In this page the blog put all the link needed to follow and/or contact the author on the classic way (email,\u0026hellip;) and the new social way (mastodon, twitter, etc\u0026hellip;)\u003c/p\u003e\n\u003cp\u003eMine is \u003ca class=\"a-post interlink-script\" href=\"/connect\"  \u003ehere\u003c/a\u003e\n\u003c/p\u003e\n\u003ch2 id=\"feeds\" class=\"no-underline \"\u003e\n  \u003ca href=\"#feeds\"\u003e\n    \u003ci class=\"fa-whiteboard fa-semibold fa-angle-right\"\u003e\u003c/i\u003e\n    Feeds\n  \u003c/a\u003e\n  \u003c/h2\u003e\n\u003cp\u003eInspired by \u003ca class=\"a-post interlink-script\" href=\"https://marcus.io/blog/making-rss-more-visible-again-with-slash-feeds\"   target=\"_blank\"\u003ethis post\u0026nbsp;\u0026nbsp;\u003ci class=\"fa-whiteboard fa-semibold fa-link\"\u003e\u003c/i\u003e\u003c/a\u003e\n the \u003cem\u003efeeds\u003c/em\u003e page is the most functional page for user on a site.\nThis page has all the feeds\u0026rsquo; links for the blog and other service the blogger is showing. Sometime some feeds aren\u0026rsquo;t from the blog but from other platform of the blogger.\u003c/p\u003e\n\u003cp\u003eMine is \u003ca class=\"a-post interlink-script\" href=\"/feeds\"  \u003ehere\u003c/a\u003e\n\u003c/p\u003e\n\u003ch2 id=\"now\" class=\"no-underline \"\u003e\n  \u003ca href=\"#now\"\u003e\n    \u003ci class=\"fa-whiteboard fa-semibold fa-angle-right\"\u003e\u003c/i\u003e\n    Now\n  \u003c/a\u003e\n  \u003c/h2\u003e\n\u003cp\u003eThe other half of the \u003cem\u003eAbout Us\u003c/em\u003e page. It come from an \u003ca class=\"a-post interlink-script\" href=\"https://nownownow.com/about\"   target=\"_blank\"\u003eidea\u0026nbsp;\u0026nbsp;\u003ci class=\"fa-whiteboard fa-semibold fa-link\"\u003e\u003c/i\u003e\u003c/a\u003e\n about having a space (in this case a page on a site) about what are you doing with your life and interest.\nIn this way you can also use it for showing off your little project or have a space for fundraising your project.\u003c/p\u003e\n\u003cp\u003eSometime I search on Google now pages for find new project and others things.\u003c/p\u003e\n\u003cp\u003eMine is \u003ca class=\"a-post interlink-script\" href=\"/now\"  \u003ehere\u003c/a\u003e\n\u003c/p\u003e\n\u003ch2 id=\"uses\" class=\"no-underline \"\u003e\n  \u003ca href=\"#uses\"\u003e\n    \u003ci class=\"fa-whiteboard fa-semibold fa-angle-right\"\u003e\u003c/i\u003e\n    Uses\n  \u003c/a\u003e\n  \u003c/h2\u003e\n\u003cp\u003eThe strange page (for me). There is a \u003ca class=\"a-post interlink-script\" href=\"https://uses.tech/\"   target=\"_blank\"\u003euses site\u0026nbsp;\u0026nbsp;\u003ci class=\"fa-whiteboard fa-semibold fa-link\"\u003e\u003c/i\u003e\u003c/a\u003e\n where you can send your \u003cem\u003eUses\u003c/em\u003e link where you share what tech you use every day or for the project. In this way you can check what tech other people use and for what.\u003c/p\u003e\n\u003cp\u003eIn this type of pages I love to check what kind of coding and photo set up they have.\u003c/p\u003e\n\u003cp\u003eMine is \u003ca class=\"a-post interlink-script\" href=\"/uses\"  \u003ehere\u003c/a\u003e\n\u003c/p\u003e\n\u003ch2 id=\"so\" class=\"no-underline \"\u003e\n  \u003ca href=\"#so\"\u003e\n    \u003ci class=\"fa-whiteboard fa-semibold fa-angle-right\"\u003e\u003c/i\u003e\n    So?\n  \u003c/a\u003e\n  \u003c/h2\u003e\n\u003cp\u003eSo I suggest to have some of this pages on your blog if you thing of your blog as a personal blog. It can be usefull for start a conversation online or for having a place to send people for answer about your works and your stuffs.\u003c/p\u003e\n","content_text":"More and more blog I read and more and more I find that a lot of the dev blog and personal blog on the web has a lot of common pages but not the old About or Contacts so I make this list of interesting pages types.\nBlogroll One of the best page I find on a blog. This is a page where the blogger show a link of site/blog (a html page or a Opml file) of interesting stuff.\nI find iteresting because I can have an idea about the blogger interest and I can find new and different source of post.\nMine is here Connect Half of the old About Us page. In this page the blog put all the link needed to follow and/or contact the author on the classic way (email,\u0026hellip;) and the new social way (mastodon, twitter, etc\u0026hellip;)\nMine is here Feeds Inspired by this post\u0026nbsp;\u0026nbsp; the feeds page is the most functional page for user on a site. This page has all the feeds\u0026rsquo; links for the blog and other service the blogger is showing. Sometime some feeds aren\u0026rsquo;t from the blog but from other platform of the blogger.\nMine is here Now The other half of the About Us page. It come from an idea\u0026nbsp;\u0026nbsp; about having a space (in this case a page on a site) about what are you doing with your life and interest. In this way you can also use it for showing off your little project or have a space for fundraising your project.\nSometime I search on Google now pages for find new project and others things.\nMine is here Uses The strange page (for me). There is a uses site\u0026nbsp;\u0026nbsp; where you can send your Uses link where you share what tech you use every day or for the project. In this way you can check what tech other people use and for what.\nIn this type of pages I love to check what kind of coding and photo set up they have.\nMine is here So? So I suggest to have some of this pages on your blog if you thing of your blog as a personal blog. It can be usefull for start a conversation online or for having a place to send people for answer about your works and your stuffs.\n","image":"https://fundor333.com/post/2025/pages-you-need-in-your-blog/cover.png","banner_image":"https://fundor333.com/post/2025/pages-you-need-in-your-blog/cover.png"},{"title":"An Easy Way to Start a Life in the IndieWeb","date_published":"2025-01-31T12:46:00+01:00","date_modified":"2026-07-16T22:49:21+02:00","id":"https://fundor333.com/post/2025/an-easy-way-to-start-a-life-in-the-indieweb/","url":"https://fundor333.com/post/2025/an-easy-way-to-start-a-life-in-the-indieweb/","tags":["blogging","indiweb","dev"],"content_html":"\u003cp\u003eThere are more and more post about the Indieweb and what you can find in a indiweb site/blog\u003csup id=\"fnref:1\"\u003e\u003ca href=\"#fn:1\" class=\"footnote-ref\" role=\"doc-noteref\"\u003e1\u003c/a\u003e\u003c/sup\u003e but I didn\u0026rsquo;t find an easy tutorial for starting with IndiWeb. But first:\nWhat is the IndieWeb?\u003c/p\u003e\n\u003ch2 id=\"indieweb-the-definition\" class=\"no-underline \"\u003e\n  \u003ca href=\"#indieweb-the-definition\"\u003e\n    \u003ci class=\"fa-whiteboard fa-semibold fa-angle-right\"\u003e\u003c/i\u003e\n    IndieWeb the definition\n  \u003c/a\u003e\n  \u003c/h2\u003e\n\u003cp\u003eI thing that, to explain IndieWeb we need two definition: one from a more \u0026ldquo;anthropological\u0026rdquo; point of view and one from a \u0026ldquo;tecnical/it\u0026rdquo; point of view\u003c/p\u003e\n\u003ch3 id=\"anthropological-definition\" class=\"no-underline \"\u003e\n  \u003ca href=\"#anthropological-definition\"\u003e\n    \u003ci class=\"fa-whiteboard fa-semibold fa-angle-right\"\u003e\u003c/i\u003e\u003ci class=\"fa-whiteboard fa-semibold fa-angle-right\"\u003e\u003c/i\u003e\n    Anthropological definition\n  \u003c/a\u003e\n  \u003c/h3\u003e\n\u003cblockquote\u003e\n\u003cp\u003eThe #IndieWeb is for everyone, everyone who wants to be part of the world-wide-web of interconnected people. The social internet of people, a network of networks of people, connected peer-to-peer in human-scale groups, communities of locality and affinity.\u003c/p\u003e\n\u003c/blockquote\u003e\n\u003ch3 id=\"tecnicalit-definition\" class=\"no-underline \"\u003e\n  \u003ca href=\"#tecnicalit-definition\"\u003e\n    \u003ci class=\"fa-whiteboard fa-semibold fa-angle-right\"\u003e\u003c/i\u003e\u003ci class=\"fa-whiteboard fa-semibold fa-angle-right\"\u003e\u003c/i\u003e\n    Tecnical/It definition\n  \u003c/a\u003e\n  \u003c/h3\u003e\n\u003cblockquote\u003e\n\u003cp\u003eThe IndieWeb is a community of independent and personal websites connected by open standards, based on the principles of: owning your domain and using it as your primary online identity, publishing on your own site first (optionally elsewhere), and owning your content.\u003c/p\u003e\n\u003c/blockquote\u003e\n\u003ch3 id=\"so-why-i-need-to-be-in-the-indieweb\" class=\"no-underline \"\u003e\n  \u003ca href=\"#so-why-i-need-to-be-in-the-indieweb\"\u003e\n    \u003ci class=\"fa-whiteboard fa-semibold fa-angle-right\"\u003e\u003c/i\u003e\u003ci class=\"fa-whiteboard fa-semibold fa-angle-right\"\u003e\u003c/i\u003e\n    So, why I need to be in the Indieweb?\n  \u003c/a\u003e\n  \u003c/h3\u003e\n\u003cp\u003e\u003cimg  class=\"center-img u-photo \"  src=\"pill.png\" alt=\"red pill blue pill\"\u003e\u003c/p\u003e\n\u003cp\u003eYou don\u0026rsquo;t need to be in. You need to choose \u003cstrong\u003ered pill\u003c/strong\u003e or \u003cstrong\u003eblue pill\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eRed Pill\u003c/strong\u003e: If you want to have a look inside the mirror and, because you have something to say online, you need to have a personal domain and a space where you have the control and own your content and\u003c/p\u003e\n\u003cblockquote\u003e\n\u003cp\u003eYou stay in Wonderland and I show you how deep the rabbit hole goes\u003c/p\u003e\n\u003c/blockquote\u003e\n\u003cp\u003e\u003cstrong\u003eBlue Pill\u003c/strong\u003e: You keep the social network account you have and\u003c/p\u003e\n\u003cblockquote\u003e\n\u003cp\u003eThe story ends, you wake up in your bed and believe whatever you want to believe\u003c/p\u003e\n\u003c/blockquote\u003e\n\u003ch2 id=\"red-pill-now-what\" class=\"no-underline \"\u003e\n  \u003ca href=\"#red-pill-now-what\"\u003e\n    \u003ci class=\"fa-whiteboard fa-semibold fa-angle-right\"\u003e\u003c/i\u003e\n    Red Pill, now what?\n  \u003c/a\u003e\n  \u003c/h2\u003e\n\u003cp\u003eThere are multiple things to do and tools to choose for you if you want to start with IndieWeb so I suggest a site which help you understand what you need to do and what to choose.\u003c/p\u003e\n\u003cp\u003eThis site is \u003ca class=\"a-post interlink-script\" href=\"https://unplatform.fromthesuperhighway.com/\"   target=\"_blank\"\u003eUnplatform\u0026nbsp;\u0026nbsp;\u003ci class=\"fa-whiteboard fa-semibold fa-link\"\u003e\u003c/i\u003e\u003c/a\u003e\n from the people of the \u003ca class=\"a-post interlink-script\" href=\"fromthesuperhighway.com\"  \u003efromthesuperhighway\u003c/a\u003e\n.\u003c/p\u003e\n\u003cp\u003eThis is a simple way to understand and start with the \u003cstrong\u003ered pill\u003c/strong\u003e and with a complete explanation for every tool you choose so you can have the easyest way to became an IndieWeb user.\u003c/p\u003e\n\u003cp\u003eHave a nice IndieWeb expirience\u003c/p\u003e\n\u003cdiv class=\"footnotes\" role=\"doc-endnotes\"\u003e\n\u003chr\u003e\n\u003col\u003e\n\u003cli id=\"fn:1\"\u003e\n\u003cp\u003e\u003ca class=\"a-post interlink-script\" href=\"https://indieweb.org/\"   target=\"_blank\"\u003eIndiweb\u0026nbsp;\u0026nbsp;\u003ci class=\"fa-whiteboard fa-semibold fa-link\"\u003e\u003c/i\u003e\u003c/a\u003e\n, \u003ca class=\"a-post interlink-script\" href=\"https://news.ycombinator.com/item?id=26950009\"   target=\"_blank\"\u003eThe IndieWeb is a people-focused alternative to the “corporate web”\u0026nbsp;\u0026nbsp;\u003ci class=\"fa-whiteboard fa-semibold fa-link\"\u003e\u003c/i\u003e\u003c/a\u003e\n, \u003ca class=\"a-post interlink-script\" href=\"https://blog.rubenwardy.com/2023/10/10/hello-indieweb/\"   target=\"_blank\"\u003eI have joined the IndieWeb\u0026nbsp;\u0026nbsp;\u003ci class=\"fa-whiteboard fa-semibold fa-link\"\u003e\u003c/i\u003e\u003c/a\u003e\n, \u003ca class=\"a-post interlink-script\" href=\"https://darthmall.net/2024/indieweb-is-for-devs/\"   target=\"_blank\"\u003eThe IndieWeb is for Developers\u0026nbsp;\u0026nbsp;\u003ci class=\"fa-whiteboard fa-semibold fa-link\"\u003e\u003c/i\u003e\u003c/a\u003e\n, \u003ca class=\"a-post interlink-script\" href=\"https://werd.io/2024/the-indieweb-is-for-everyone\"   target=\"_blank\"\u003eThe indieweb is for everyone\u0026nbsp;\u0026nbsp;\u003ci class=\"fa-whiteboard fa-semibold fa-link\"\u003e\u003c/i\u003e\u003c/a\u003e\n\u0026#160;\u003ca href=\"#fnref:1\" class=\"footnote-backref\" role=\"doc-backlink\"\u003e\u0026#x21a9;\u0026#xfe0e;\u003c/a\u003e\u003c/p\u003e\n\u003c/li\u003e\n\u003c/ol\u003e\n\u003c/div\u003e\n","content_text":"There are more and more post about the Indieweb and what you can find in a indiweb site/blog1 but I didn\u0026rsquo;t find an easy tutorial for starting with IndiWeb. But first: What is the IndieWeb?\nIndieWeb the definition I thing that, to explain IndieWeb we need two definition: one from a more \u0026ldquo;anthropological\u0026rdquo; point of view and one from a \u0026ldquo;tecnical/it\u0026rdquo; point of view\nAnthropological definition The #IndieWeb is for everyone, everyone who wants to be part of the world-wide-web of interconnected people. The social internet of people, a network of networks of people, connected peer-to-peer in human-scale groups, communities of locality and affinity.\nTecnical/It definition The IndieWeb is a community of independent and personal websites connected by open standards, based on the principles of: owning your domain and using it as your primary online identity, publishing on your own site first (optionally elsewhere), and owning your content.\nSo, why I need to be in the Indieweb? You don\u0026rsquo;t need to be in. You need to choose red pill or blue pill\nRed Pill: If you want to have a look inside the mirror and, because you have something to say online, you need to have a personal domain and a space where you have the control and own your content and\nYou stay in Wonderland and I show you how deep the rabbit hole goes\nBlue Pill: You keep the social network account you have and\nThe story ends, you wake up in your bed and believe whatever you want to believe\nRed Pill, now what? There are multiple things to do and tools to choose for you if you want to start with IndieWeb so I suggest a site which help you understand what you need to do and what to choose.\nThis site is Unplatform\u0026nbsp;\u0026nbsp; from the people of the fromthesuperhighway .\nThis is a simple way to understand and start with the red pill and with a complete explanation for every tool you choose so you can have the easyest way to became an IndieWeb user.\nHave a nice IndieWeb expirience\nIndiweb\u0026nbsp;\u0026nbsp; , The IndieWeb is a people-focused alternative to the “corporate web”\u0026nbsp;\u0026nbsp; , I have joined the IndieWeb\u0026nbsp;\u0026nbsp; , The IndieWeb is for Developers\u0026nbsp;\u0026nbsp; , The indieweb is for everyone\u0026nbsp;\u0026nbsp; \u0026#160;\u0026#x21a9;\u0026#xfe0e;\n","image":"https://fundor333.com/post/2025/an-easy-way-to-start-a-life-in-the-indieweb/cover.png","banner_image":"https://fundor333.com/post/2025/an-easy-way-to-start-a-life-in-the-indieweb/cover.png"},{"title":"Substack vs Medium: What Is Better for a Coder?","date_published":"2025-01-27T12:02:52+01:00","date_modified":"2026-07-16T22:49:21+02:00","id":"https://fundor333.com/post/2025/substack-vs-medium-what-is-better-for-a-coder/","url":"https://fundor333.com/post/2025/substack-vs-medium-what-is-better-for-a-coder/","tags":["medium","substack","blogging","dev","rant"],"content_html":"\u003cp\u003eI am first and most a Developer and a Coder and I think that coding and developing software (site, app, AI, etc\u0026hellip;) need to be a share experience.\nSo I think a dev must share knowledge in the web. Somebody help people on StackOverflow and someone (like me) blogs.\u003c/p\u003e\n\u003cp\u003eIn the last \u003cem\u003eX\u003c/em\u003e years\u003csup id=\"fnref:1\"\u003e\u003ca href=\"#fn:1\" class=\"footnote-ref\" role=\"doc-noteref\"\u003e1\u003c/a\u003e\u003c/sup\u003e I understand the important of blogging and why a dev or a coder need to write a blog/newsletter/magazine about what is doing\u003csup id=\"fnref:2\"\u003e\u003ca href=\"#fn:2\" class=\"footnote-ref\" role=\"doc-noteref\"\u003e2\u003c/a\u003e\u003c/sup\u003e and how big time sink is developing and maintaining a custom blog so I have this question:\u003c/p\u003e\n\u003cblockquote\u003e\n\u003cp\u003eFor sharing Dev/Coding experiences is better Medium or StackOverflow?\u003csup id=\"fnref:3\"\u003e\u003ca href=\"#fn:3\" class=\"footnote-ref\" role=\"doc-noteref\"\u003e3\u003c/a\u003e\u003c/sup\u003e\u003c/p\u003e\n\u003c/blockquote\u003e\n\u003ch2 id=\"we-need-a-generic-dev\" class=\"no-underline \"\u003e\n  \u003ca href=\"#we-need-a-generic-dev\"\u003e\n    \u003ci class=\"fa-whiteboard fa-semibold fa-angle-right\"\u003e\u003c/i\u003e\n    We need a \u0026ldquo;generic\u0026rdquo; Dev!\n  \u003c/a\u003e\n  \u003c/h2\u003e\n\u003cp\u003eThis is \u003cem\u003eBob\u003c/em\u003e. \u003cem\u003eBob\u003c/em\u003e is a BackEnd Developer, a Python Developer and he is learning some FrontEnd stuffs. So he wants to write about what he knows, what is learning and his doubts.\u003c/p\u003e\n\u003cp\u003e\u003cimg  class=\"center-img u-photo \"  src=\"bob.png\" alt=\"Bob Avatar\"\u003e\u003c/p\u003e\n\u003ch3 id=\"what-a-dev-need-to-share-in-a-post\" class=\"no-underline \"\u003e\n  \u003ca href=\"#what-a-dev-need-to-share-in-a-post\"\u003e\n    \u003ci class=\"fa-whiteboard fa-semibold fa-angle-right\"\u003e\u003c/i\u003e\u003ci class=\"fa-whiteboard fa-semibold fa-angle-right\"\u003e\u003c/i\u003e\n    What a Dev need to share in a post\n  \u003c/a\u003e\n  \u003c/h3\u003e\n\u003cp\u003e\u003cem\u003eBob\u003c/em\u003e need to share fragments of the code he writes, some screenshot (images) and a lot of texts. The latest are a simple request because it is the minimum requirements for all the blogging platform.\u003c/p\u003e\n\u003cp\u003eThe code part is the \u0026ldquo;difficult\u0026rdquo; one.\u003c/p\u003e\n\u003cp\u003eThe best situation is if the code is highlighted something like this\u003c/p\u003e\n\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;\"\u003e\u003ccode class=\"language-python\" data-lang=\"python\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003eprint(\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;Hello World!\u0026#34;\u003c/span\u003e)\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003eand the platform need to support all the types of the files \u003cem\u003eBob\u003c/em\u003e\u0026rsquo;s code but we only need the highlight for the languages\u0026hellip;\nIf \u003cem\u003eBob\u003c/em\u003e needs to blog about \u003cem\u003eCobol\u003c/em\u003e or \u003cem\u003ePascal\u003c/em\u003e\u003csup id=\"fnref:4\"\u003e\u003ca href=\"#fn:4\" class=\"footnote-ref\" role=\"doc-noteref\"\u003e4\u003c/a\u003e\u003c/sup\u003e\u003c/p\u003e\n\u003ch3 id=\"customing-and-theming\" class=\"no-underline \"\u003e\n  \u003ca href=\"#customing-and-theming\"\u003e\n    \u003ci class=\"fa-whiteboard fa-semibold fa-angle-right\"\u003e\u003c/i\u003e\u003ci class=\"fa-whiteboard fa-semibold fa-angle-right\"\u003e\u003c/i\u003e\n    Customing and theming\n  \u003c/a\u003e\n  \u003c/h3\u003e\n\u003cp\u003e\u003cem\u003eBob\u003c/em\u003e need to have a solid site/blog with a mobile and a desktop layout (more and more people read blog only with the tablet or the phone) and he need to make no changes or as little as possible for making HIS SITE/BLOG.\u003c/p\u003e\n\u003cp\u003eHe also need a notification system for the followers (newsletters, feed, app with notification, \u0026hellip;) and a SEO integration (analytics, meta, etc\u0026hellip;) for becoming someone on the web.\u003c/p\u003e\n\u003cp\u003eLess edit he must do for posting better the platform is.\u003c/p\u003e\n\u003ch3 id=\"money\" class=\"no-underline \"\u003e\n  \u003ca href=\"#money\"\u003e\n    \u003ci class=\"fa-whiteboard fa-semibold fa-angle-right\"\u003e\u003c/i\u003e\u003ci class=\"fa-whiteboard fa-semibold fa-angle-right\"\u003e\u003c/i\u003e\n    Money\n  \u003c/a\u003e\n  \u003c/h3\u003e\n\u003cp\u003e\u003cem\u003eBob\u003c/em\u003e is a developer for money so he doesn\u0026rsquo;t want to spend money so\u0026hellip; The all budget is 10€ (all needed for the domain) so the platform is a good one if it is free but is better if \u003cem\u003epay\u003c/em\u003e \u003cem\u003eBob\u003c/em\u003e.\u003c/p\u003e\n\u003cp\u003eSo he needs a free platform\u003csup id=\"fnref:5\"\u003e\u003ca href=\"#fn:5\" class=\"footnote-ref\" role=\"doc-noteref\"\u003e5\u003c/a\u003e\u003c/sup\u003e and some way to make money from the posts (advertising, subscriptions, etc\u0026hellip;)\u003c/p\u003e\n\u003cp\u003e\u003cimg  class=\"center-img u-photo \"  src=\"newspaper.png\" alt=\"NewsPapers\"\u003e\u003c/p\u003e\n\u003ch2 id=\"and-now-the-platforms\" class=\"no-underline \"\u003e\n  \u003ca href=\"#and-now-the-platforms\"\u003e\n    \u003ci class=\"fa-whiteboard fa-semibold fa-angle-right\"\u003e\u003c/i\u003e\n    And now the platforms\n  \u003c/a\u003e\n  \u003c/h2\u003e\n\u003cp\u003eNow we know what \u003cem\u003eBob\u003c/em\u003e needs and wants, we find some platforms.\u003c/p\u003e\n\u003cp\u003eWordpress, Jekill, Ghost, GoHugo and some other platforms aren\u0026rsquo;t the \u0026ldquo;right one\u0026rdquo; because they aren\u0026rsquo;t a \u0026ldquo;out of the box\u0026rdquo; expirience. You need to customized it and you need to have time for the updating of the platform soo we have SubStack and Medium as the platform.\u003c/p\u003e\n\u003ch3 id=\"medium\" class=\"no-underline \"\u003e\n  \u003ca href=\"#medium\"\u003e\n    \u003ci class=\"fa-whiteboard fa-semibold fa-angle-right\"\u003e\u003c/i\u003e\u003ci class=\"fa-whiteboard fa-semibold fa-angle-right\"\u003e\u003c/i\u003e\n    Medium\n  \u003c/a\u003e\n  \u003c/h3\u003e\n\u003cp\u003eThe old one, \u003cem\u003eMedium\u003c/em\u003e is the platform which is trying to become a blogging space for magazine and journal\u0026rsquo; blogs.\nHe is online from the 2012 and have all the need for a writer, with tool for automatic sharing, automatic posting and seo tools Medium is a complete platform.\u003c/p\u003e\n\u003ch3 id=\"substack\" class=\"no-underline \"\u003e\n  \u003ca href=\"#substack\"\u003e\n    \u003ci class=\"fa-whiteboard fa-semibold fa-angle-right\"\u003e\u003c/i\u003e\u003ci class=\"fa-whiteboard fa-semibold fa-angle-right\"\u003e\u003c/i\u003e\n    SubStack\n  \u003c/a\u003e\n  \u003c/h3\u003e\n\u003cp\u003eThe new one, \u003cem\u003eSubStack\u003c/em\u003e is the platform with two faces: one is a blogging space and the other is the mail-list space.\n\u003cem\u003eSubStack\u003c/em\u003e out of the box way to work is a mail list for your followers, but the site part is not a bad one. It has automatic sharing, automatic posting and a micro-blogging part. But for SEO and promotion it all on you.\u003c/p\u003e\n\u003cp\u003eIt also has one of the better subscribe platform of the web, where you can set some post to \u003cem\u003epay to read\u003c/em\u003e and some \u003cem\u003efree to read\u003c/em\u003e.\u003c/p\u003e\n\u003ch3 id=\"some-other-considerations\" class=\"no-underline \"\u003e\n  \u003ca href=\"#some-other-considerations\"\u003e\n    \u003ci class=\"fa-whiteboard fa-semibold fa-angle-right\"\u003e\u003c/i\u003e\u003ci class=\"fa-whiteboard fa-semibold fa-angle-right\"\u003e\u003c/i\u003e\n    Some other considerations\n  \u003c/a\u003e\n  \u003c/h3\u003e\n\u003cp\u003eAfter all this considerations I need to show somethings behind the curtain : Medium has a lot of negative attention[^mediumproblem] because they have a lot of low quality post\u003csup id=\"fnref:6\"\u003e\u003ca href=\"#fn:6\" class=\"footnote-ref\" role=\"doc-noteref\"\u003e6\u003c/a\u003e\u003c/sup\u003e and SubStack has its share of problem with the paywall on the newsletters and some problems for the authors.\u003csup id=\"fnref:7\"\u003e\u003ca href=\"#fn:7\" class=\"footnote-ref\" role=\"doc-noteref\"\u003e7\u003c/a\u003e\u003c/sup\u003e\u003c/p\u003e\n\u003cp\u003e\u003cimg  class=\"center-img u-photo \"  src=\"oz.png\" alt=\"Oz\"\u003e\u003c/p\u003e\n\u003cp\u003eIn my opinion, if you want to blog about what are you doing, do it and this two platform can be a good starting point for start with your blogging journey but if it become something more you need to invest time in something more tailor to your need and understand what you need and what the platform give you.\u003c/p\u003e\n\u003cp\u003eIf someone make me choose one between Medium and SubStack, I will choose SubStack because I love the idea of having a newsletters but I also feel the limitation of the close platform, bacause I had years and years of blogging on platform I hacked every way.\u003c/p\u003e\n\u003cp\u003eFor example this blog is a GoHugo installation with a \u003cem\u003eout of the box\u003c/em\u003e theme but I put so many changing in the code I have something more similar of the Monster of Frankenstein than a well coded theme\u0026hellip;\u003c/p\u003e\n\u003cdiv class=\"footnotes\" role=\"doc-endnotes\"\u003e\n\u003chr\u003e\n\u003col\u003e\n\u003cli id=\"fn:1\"\u003e\n\u003cp\u003eWhere \u003cem\u003eX\u003c/em\u003e is a big but not too big number\u0026#160;\u003ca href=\"#fnref:1\" class=\"footnote-backref\" role=\"doc-backlink\"\u003e\u0026#x21a9;\u0026#xfe0e;\u003c/a\u003e\u003c/p\u003e\n\u003c/li\u003e\n\u003cli id=\"fn:2\"\u003e\n\u003cp\u003eThis is also explained in one of my \u003ca class=\"a-post interlink-script\" href=\"https://fundor333.com/photos/2025/square-square-square-and-square/\"  \u003eold post\u003c/a\u003e\n\u0026#160;\u003ca href=\"#fnref:2\" class=\"footnote-backref\" role=\"doc-backlink\"\u003e\u0026#x21a9;\u0026#xfe0e;\u003c/a\u003e\u003c/p\u003e\n\u003c/li\u003e\n\u003cli id=\"fn:3\"\u003e\n\u003cp\u003eThis is my blog/webspace so I say \u003cem\u003emy opinion\u003c/em\u003e (coder for more than 5 year)\u0026#160;\u003ca href=\"#fnref:3\" class=\"footnote-backref\" role=\"doc-backlink\"\u003e\u0026#x21a9;\u0026#xfe0e;\u003c/a\u003e\u003c/p\u003e\n\u003c/li\u003e\n\u003cli id=\"fn:4\"\u003e\n\u003cp\u003eCobol and Pascal are two of the oldest languages and almost every highlighter in a generic blogging platform don\u0026rsquo;t support them, so you need to use a more professional blogging platform and lost time with the custumizations\u0026#160;\u003ca href=\"#fnref:4\" class=\"footnote-backref\" role=\"doc-backlink\"\u003e\u0026#x21a9;\u0026#xfe0e;\u003c/a\u003e\u003c/p\u003e\n\u003c/li\u003e\n\u003cli id=\"fn:5\"\u003e\n\u003cp\u003eSome function can be hidden by a paywall but if all the \u003cem\u003eneeded\u003c/em\u003e function are free, the platform is a good one\u0026#160;\u003ca href=\"#fnref:5\" class=\"footnote-backref\" role=\"doc-backlink\"\u003e\u0026#x21a9;\u0026#xfe0e;\u003c/a\u003e\u003c/p\u003e\n\u003c/li\u003e\n\u003cli id=\"fn:6\"\u003e\n\u003cp\u003e\u003ca class=\"a-post interlink-script\" href=\"https://news.ycombinator.com/item?id=24942037\"   target=\"_blank\"\u003ePlease stop writing tutorials/tech articles on Medium\u0026nbsp;\u0026nbsp;\u003ci class=\"fa-whiteboard fa-semibold fa-link\"\u003e\u003c/i\u003e\u003c/a\u003e\n\u0026#160;\u003ca href=\"#fnref:6\" class=\"footnote-backref\" role=\"doc-backlink\"\u003e\u0026#x21a9;\u0026#xfe0e;\u003c/a\u003e\u003c/p\u003e\n\u003c/li\u003e\n\u003cli id=\"fn:7\"\u003e\n\u003cp\u003e\u003ca class=\"a-post interlink-script\" href=\"https://janefriedman.com/substack-is-both-great-and-terrible-for-authors/\"   target=\"_blank\"\u003eSubstack Is Both Great and Terrible for Authors\n\u0026nbsp;\u0026nbsp;\u003ci class=\"fa-whiteboard fa-semibold fa-link\"\u003e\u003c/i\u003e\u003c/a\u003e\n\u0026#160;\u003ca href=\"#fnref:7\" class=\"footnote-backref\" role=\"doc-backlink\"\u003e\u0026#x21a9;\u0026#xfe0e;\u003c/a\u003e\u003c/p\u003e\n\u003c/li\u003e\n\u003c/ol\u003e\n\u003c/div\u003e\n","content_text":"I am first and most a Developer and a Coder and I think that coding and developing software (site, app, AI, etc\u0026hellip;) need to be a share experience. So I think a dev must share knowledge in the web. Somebody help people on StackOverflow and someone (like me) blogs.\nIn the last X years1 I understand the important of blogging and why a dev or a coder need to write a blog/newsletter/magazine about what is doing2 and how big time sink is developing and maintaining a custom blog so I have this question:\nFor sharing Dev/Coding experiences is better Medium or StackOverflow?3\nWe need a \u0026ldquo;generic\u0026rdquo; Dev! This is Bob. Bob is a BackEnd Developer, a Python Developer and he is learning some FrontEnd stuffs. So he wants to write about what he knows, what is learning and his doubts.\nWhat a Dev need to share in a post Bob need to share fragments of the code he writes, some screenshot (images) and a lot of texts. The latest are a simple request because it is the minimum requirements for all the blogging platform.\nThe code part is the \u0026ldquo;difficult\u0026rdquo; one.\nThe best situation is if the code is highlighted something like this\nprint(\u0026#34;Hello World!\u0026#34;)and the platform need to support all the types of the files Bob\u0026rsquo;s code but we only need the highlight for the languages\u0026hellip; If Bob needs to blog about Cobol or Pascal4\nCustoming and theming Bob need to have a solid site/blog with a mobile and a desktop layout (more and more people read blog only with the tablet or the phone) and he need to make no changes or as little as possible for making HIS SITE/BLOG.\nHe also need a notification system for the followers (newsletters, feed, app with notification, \u0026hellip;) and a SEO integration (analytics, meta, etc\u0026hellip;) for becoming someone on the web.\nLess edit he must do for posting better the platform is.\nMoney Bob is a developer for money so he doesn\u0026rsquo;t want to spend money so\u0026hellip; The all budget is 10€ (all needed for the domain) so the platform is a good one if it is free but is better if pay Bob.\nSo he needs a free platform5 and some way to make money from the posts (advertising, subscriptions, etc\u0026hellip;)\nAnd now the platforms Now we know what Bob needs and wants, we find some platforms.\nWordpress, Jekill, Ghost, GoHugo and some other platforms aren\u0026rsquo;t the \u0026ldquo;right one\u0026rdquo; because they aren\u0026rsquo;t a \u0026ldquo;out of the box\u0026rdquo; expirience. You need to customized it and you need to have time for the updating of the platform soo we have SubStack and Medium as the platform.\nMedium The old one, Medium is the platform which is trying to become a blogging space for magazine and journal\u0026rsquo; blogs. He is online from the 2012 and have all the need for a writer, with tool for automatic sharing, automatic posting and seo tools Medium is a complete platform.\nSubStack The new one, SubStack is the platform with two faces: one is a blogging space and the other is the mail-list space. SubStack out of the box way to work is a mail list for your followers, but the site part is not a bad one. It has automatic sharing, automatic posting and a micro-blogging part. But for SEO and promotion it all on you.\nIt also has one of the better subscribe platform of the web, where you can set some post to pay to read and some free to read.\nSome other considerations After all this considerations I need to show somethings behind the curtain : Medium has a lot of negative attention[^mediumproblem] because they have a lot of low quality post6 and SubStack has its share of problem with the paywall on the newsletters and some problems for the authors.7\nIn my opinion, if you want to blog about what are you doing, do it and this two platform can be a good starting point for start with your blogging journey but if it become something more you need to invest time in something more tailor to your need and understand what you need and what the platform give you.\nIf someone make me choose one between Medium and SubStack, I will choose SubStack because I love the idea of having a newsletters but I also feel the limitation of the close platform, bacause I had years and years of blogging on platform I hacked every way.\nFor example this blog is a GoHugo installation with a out of the box theme but I put so many changing in the code I have something more similar of the Monster of Frankenstein than a well coded theme\u0026hellip;\nWhere X is a big but not too big number\u0026#160;\u0026#x21a9;\u0026#xfe0e;\nThis is also explained in one of my old post \u0026#160;\u0026#x21a9;\u0026#xfe0e;\nThis is my blog/webspace so I say my opinion (coder for more than 5 year)\u0026#160;\u0026#x21a9;\u0026#xfe0e;\nCobol and Pascal are two of the oldest languages and almost every highlighter in a generic blogging platform don\u0026rsquo;t support them, so you need to use a more professional blogging platform and lost time with the custumizations\u0026#160;\u0026#x21a9;\u0026#xfe0e;\nSome function can be hidden by a paywall but if all the needed function are free, the platform is a good one\u0026#160;\u0026#x21a9;\u0026#xfe0e;\nPlease stop writing tutorials/tech articles on Medium\u0026nbsp;\u0026nbsp; \u0026#160;\u0026#x21a9;\u0026#xfe0e;\nSubstack Is Both Great and Terrible for Authors \u0026nbsp;\u0026nbsp; \u0026#160;\u0026#x21a9;\u0026#xfe0e;\n","image":"https://fundor333.com/post/2025/substack-vs-medium-what-is-better-for-a-coder/cover.png","banner_image":"https://fundor333.com/post/2025/substack-vs-medium-what-is-better-for-a-coder/cover.png"},{"title":"Github Action for Syndication Links","date_published":"2025-01-23T13:22:54+01:00","date_modified":"2026-07-16T22:49:21+02:00","id":"https://fundor333.com/post/2025/github-action-for-syndication-links/","url":"https://fundor333.com/post/2025/github-action-for-syndication-links/","tags":["hugo","github","github actiom","dev"],"content_html":"\u003cp\u003eA lot of time ago I implement the Webmention in my site following a lot of blogpost.\u003c/p\u003e\n\u003cp\u003eOne of them was a bigger ispiration for my implementation\u003csup id=\"fnref:1\"\u003e\u003ca href=\"#fn:1\" class=\"footnote-ref\" role=\"doc-noteref\"\u003e1\u003c/a\u003e\u003c/sup\u003e and I have some chat with the author of the post over Mastodon for the implementation of the syndications link in a static site\u003csup id=\"fnref:2\"\u003e\u003ca href=\"#fn:2\" class=\"footnote-ref\" role=\"doc-noteref\"\u003e2\u003c/a\u003e\u003c/sup\u003e and how to implement it.\u003c/p\u003e\n\n\n\n\n\n\n\n\n    \n    \n        \n        \n    \n\n    \n        \u003cdiv class=\"toot\"\u003e\n            \u003cdiv class=\"toot-header\"\u003e\n                \u003ca class=\"toot-profile\" href=\"https://mastodon.social/@fundor333\" rel=\"noopener\"\u003e\n                    \u003cimg src=\"https://files.mastodon.social/accounts/avatars/000/030/873/original/67f41e16a70f9ef6.png\"\n                         alt=\"Avatar for @fundor333@mastodon.social\"\n                         loading=\"lazy\"\u003e\n                \u003c/a\u003e\n                \u003cdiv class=\"toot-author\"\u003e\n                    \u003ca class=\"toot-author-name\"\n                       href=\"https://mastodon.social/@fundor333\"\n                       rel=\"noopener\"\u003eFundor333\u003c/a\u003e\n                    \u003ca class=\"toot-author-handle\"\n                       href=\"https://mastodon.social/@fundor333\"\n                       rel=\"noopener\"\u003e@fundor333@mastodon.social\u003c/a\u003e\n                \u003c/div\u003e\n            \u003c/div\u003e\n\n            \u003cdiv class=\"toot-content\"\u003e\u003cp\u003e\u003cspan class=\"h-card\" translate=\"no\"\u003e\u003ca href=\"https://fosstodon.org/@chringel\" class=\"u-url mention\"\u003e@\u003cspan\u003echringel\u003c/span\u003e\u003c/a\u003e\u003c/span\u003e How do you fill the syndications\u0026#39; links? By hand?\u003c/p\u003e\u003c/div\u003e\n\n            \n\n            \u003cdiv class=\"toot-footer\"\u003e\n                \u003ca href=\"https://mastodon.social@fundor333/status/108752916197327869\"\n                   class=\"toot-date\"\n                   rel=\"noopener\"\u003e10:56 AM · Aug 2, 2022\u003c/a\u003e\n            \u003c/div\u003e\n        \u003c/div\u003e\n    \n\n\n\u003cp\u003e\u003c!-- raw HTML omitted --\u003e\u003c!-- raw HTML omitted --\u003e\u003c/p\u003e\n\n\n\n\n\n\n\n\n    \n    \n        \n        \n    \n\n    \n        \u003cdiv class=\"toot\"\u003e\n            \u003cdiv class=\"toot-header\"\u003e\n                \u003ca class=\"toot-profile\" href=\"https://fosstodon.org/@chringel\" rel=\"noopener\"\u003e\n                    \u003cimg src=\"https://cdn.fosstodon.org/accounts/avatars/107/558/501/981/999/210/original/ae7e7ef8e5f9c347.png\"\n                         alt=\"Avatar for @chringel@fosstodon.org\"\n                         loading=\"lazy\"\u003e\n                \u003c/a\u003e\n                \u003cdiv class=\"toot-author\"\u003e\n                    \u003ca class=\"toot-author-name\"\n                       href=\"https://fosstodon.org/@chringel\"\n                       rel=\"noopener\"\u003eChristian 👼\u003c/a\u003e\n                    \u003ca class=\"toot-author-handle\"\n                       href=\"https://fosstodon.org/@chringel\"\n                       rel=\"noopener\"\u003e@chringel@fosstodon.org\u003c/a\u003e\n                \u003c/div\u003e\n            \u003c/div\u003e\n\n            \u003cdiv class=\"toot-content\"\u003e\u003cp\u003e\u003cspan class=\"h-card\" translate=\"no\"\u003e\u003ca href=\"https://mastodon.social/@fundor333\" class=\"u-url mention\"\u003e@\u003cspan\u003efundor333\u003c/span\u003e\u003c/a\u003e\u003c/span\u003e Yeah, unfortunately that‘s how I do it.\u003c/p\u003e\u003cp\u003e1. Publish a post on my blog\u003cbr /\u003e2. Post the link on Twitter/Mastodon/…\u003cbr /\u003e3. Update syndication param in front matter and republish\u003c/p\u003e\u003cp\u003eHaven‘t found another way yet.\u003c/p\u003e\u003c/div\u003e\n\n            \n\n            \u003cdiv class=\"toot-footer\"\u003e\n                \u003ca href=\"https://fosstodon.org@chringel/status/108754642028626230\"\n                   class=\"toot-date\"\n                   rel=\"noopener\"\u003e6:15 PM · Aug 2, 2022\u003c/a\u003e\n            \u003c/div\u003e\n        \u003c/div\u003e\n    \n\n\n\u003cp\u003eAfter 3 years I find the solution in a post about webmetions!\u003c/p\u003e\n\u003ch2 id=\"the-input\" class=\"no-underline \"\u003e\n  \u003ca href=\"#the-input\"\u003e\n    \u003ci class=\"fa-whiteboard fa-semibold fa-angle-right\"\u003e\u003c/i\u003e\n    The input\n  \u003c/a\u003e\n  \u003c/h2\u003e\n\u003cp\u003ePaul Kinlan wrote an article in the 2019 which flow under my radar and I didn\u0026rsquo;read it untile recently\u003csup id=\"fnref:3\"\u003e\u003ca href=\"#fn:3\" class=\"footnote-ref\" role=\"doc-noteref\"\u003e3\u003c/a\u003e\u003c/sup\u003e.\u003c/p\u003e\n\u003cp\u003eIn this post he use a Github action to write the webmention into a data folder for his GoHugo implementation. He has a script which download the data and put into file (the name of the file is the hash of the url of the post) which are use to render the webpage interested by the webmention. And all of this into Github Actions\u0026hellip;\u003c/p\u003e\n\u003cp\u003eSo I start thinking about it more and more\u0026hellip;\nWhat can I have the syndications links into a file for url? Like the webmention in this post? I need to read the urls form the social media and other stuff.\u003c/p\u003e\n\u003cp\u003eBut now with X/Twitter in bad shape and Facebook/Meta only good for share photos I only use Mastodon so it is easy read them and write a file for url\u0026hellip;\u003c/p\u003e\n\u003cp\u003eA implementation I find is this one by Brandon Rozek\u003csup id=\"fnref:4\"\u003e\u003ca href=\"#fn:4\" class=\"footnote-ref\" role=\"doc-noteref\"\u003e4\u003c/a\u003e\u003c/sup\u003e that I like in a lot of way but I change it because I don\u0026rsquo;t use Medium\u0026hellip;\u003c/p\u003e\n\u003ch2 id=\"the-implementation\" class=\"no-underline \"\u003e\n  \u003ca href=\"#the-implementation\"\u003e\n    \u003ci class=\"fa-whiteboard fa-semibold fa-angle-right\"\u003e\u003c/i\u003e\n    The implementation\n  \u003c/a\u003e\n  \u003c/h2\u003e\n\u003cp\u003eSo I start with the development:\u003c/p\u003e\n\u003col\u003e\n\u003cli\u003eI need a file type/data structure standard for the Syndication\u003c/li\u003e\n\u003cli\u003eI need a script (or more) that find the syndication\u0026rsquo;s links\u003c/li\u003e\n\u003cli\u003eI need to edit/add to the template some code for the render of it\u003c/li\u003e\n\u003c/ol\u003e\n\u003ch3 id=\"structure-data\" class=\"no-underline \"\u003e\n  \u003ca href=\"#structure-data\"\u003e\n    \u003ci class=\"fa-whiteboard fa-semibold fa-angle-right\"\u003e\u003c/i\u003e\u003ci class=\"fa-whiteboard fa-semibold fa-angle-right\"\u003e\u003c/i\u003e\n    Structure data\n  \u003c/a\u003e\n  \u003c/h3\u003e\n\u003cp\u003eFirst are the data structure: json, with the name of the file is an hash of the url\u003c/p\u003e\n\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;\"\u003e\u003ccode class=\"language-json\" data-lang=\"json\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e{\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t\u003cspan style=\"color:#f92672\"\u003e\u0026#34;syndication\u0026#34;\u003c/span\u003e: [\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t\t\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;https://mastodon.social/@fundor333/113809667070052761\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\t]\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e}\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003eFor example this is my data for \u003ca class=\"a-post interlink-script\" href=\"https://fundor333.com/photos/2025/square-square-square-and-square/\"  \u003ethis post\u003c/a\u003e\n. I choose Json because I can make check on it and it is a beautiful format for data\u003c/p\u003e\n\u003ch3 id=\"the-scraper-script\" class=\"no-underline \"\u003e\n  \u003ca href=\"#the-scraper-script\"\u003e\n    \u003ci class=\"fa-whiteboard fa-semibold fa-angle-right\"\u003e\u003c/i\u003e\u003ci class=\"fa-whiteboard fa-semibold fa-angle-right\"\u003e\u003c/i\u003e\n    The Scraper script\n  \u003c/a\u003e\n  \u003c/h3\u003e\n\u003cp\u003eIn this case I find that Mastodon generate a feed for every public profile so I only implementa a reader (class MastodonFinder) which read the feed and save the toots url if find a link to my domain, and a writer class (WriterSyndication) which run all the other class (in this case only the Mastodon one) and write the output as a look-a-like of the json show before.\u003c/p\u003e\n\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;\"\u003e\u003ccode class=\"language-python\" data-lang=\"python\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#f92672\"\u003eimport\u003c/span\u003e feedparser\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#f92672\"\u003efrom\u003c/span\u003e pathlib \u003cspan style=\"color:#f92672\"\u003eimport\u003c/span\u003e Path\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#f92672\"\u003eimport\u003c/span\u003e os\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#f92672\"\u003eimport\u003c/span\u003e json\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#f92672\"\u003eimport\u003c/span\u003e hashlib\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003edomain \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;https://fundor333.com\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003erss_url_mastodon \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;https://mastodon.social/@fundor333.rss\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#66d9ef\"\u003edef\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003eclean_slug\u003c/span\u003e(slug: str):\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003ereturn\u003c/span\u003e hashlib\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003emd5(\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        (slug\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003esplit(\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;?\u0026#34;\u003c/span\u003e)[\u003cspan style=\"color:#ae81ff\"\u003e0\u003c/span\u003e])\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003eencode(\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;utf-8\u0026#34;\u003c/span\u003e), usedforsecurity\u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#66d9ef\"\u003eFalse\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    )\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003ehexdigest()\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#66d9ef\"\u003eclass\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003eMastodonFinder\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003edef\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003efind_urls\u003c/span\u003e(self, string):\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        x \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e string\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003esplit(\u003cspan style=\"color:#e6db74\"\u003e\u0026#39;\u0026#34;\u0026#39;\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        res \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e []\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#66d9ef\"\u003efor\u003c/span\u003e i \u003cspan style=\"color:#f92672\"\u003ein\u003c/span\u003e x:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#66d9ef\"\u003eif\u003c/span\u003e i\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003estartswith(\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;https:\u0026#34;\u003c/span\u003e) \u003cspan style=\"color:#f92672\"\u003eor\u003c/span\u003e i\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003estartswith(\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;http:\u0026#34;\u003c/span\u003e):\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                res\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003eappend(i)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#66d9ef\"\u003ereturn\u003c/span\u003e res\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003edef\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003erun\u003c/span\u003e(self, rss_url: str, domain: str, output: dict):\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        feed \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e feedparser\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003eparse(rss_url)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#66d9ef\"\u003eif\u003c/span\u003e feed\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003estatus \u003cspan style=\"color:#f92672\"\u003e==\u003c/span\u003e \u003cspan style=\"color:#ae81ff\"\u003e200\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#66d9ef\"\u003efor\u003c/span\u003e entry \u003cspan style=\"color:#f92672\"\u003ein\u003c/span\u003e feed\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003eentries:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                link \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e entry\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003eget(\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;link\u0026#34;\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                \u003cspan style=\"color:#66d9ef\"\u003efor\u003c/span\u003e e \u003cspan style=\"color:#f92672\"\u003ein\u003c/span\u003e self\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003efind_urls(entry\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003eget(\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;description\u0026#34;\u003c/span\u003e)):\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                    \u003cspan style=\"color:#66d9ef\"\u003eif\u003c/span\u003e domain \u003cspan style=\"color:#f92672\"\u003ein\u003c/span\u003e e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                        e \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e clean_slug(e)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                        \u003cspan style=\"color:#66d9ef\"\u003eif\u003c/span\u003e output\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003eget(e, \u003cspan style=\"color:#66d9ef\"\u003eFalse\u003c/span\u003e):\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                            output[e]\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003eappend(link)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                        \u003cspan style=\"color:#66d9ef\"\u003eelse\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                            output[e] \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e [link\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003estrip()]\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#66d9ef\"\u003eelse\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            print(\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;Failed to get RSS feed. Status code:\u0026#34;\u003c/span\u003e, feed\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003estatus)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#66d9ef\"\u003eclass\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003eWriterSyndication\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003edef\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003e__init__\u003c/span\u003e(self, rss_url_mastodon: str, domain: str):\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        self\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003eoutput \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e {}\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        self\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003erss_url_mastodon \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e rss_url_mastodon\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        self\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003edomain \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e domain\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003edef\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003edata_gathering\u003c/span\u003e(self):\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        m \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e MastodonFinder()\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        m\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003erun(self\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003erss_url_mastodon, self\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003edomain, self\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003eoutput)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003edef\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003ewrite\u003c/span\u003e(self):\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#66d9ef\"\u003efor\u003c/span\u003e key \u003cspan style=\"color:#f92672\"\u003ein\u003c/span\u003e self\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003eoutput\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003ekeys():\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            path_folder \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e os\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003epath\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003ejoin(\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;data\u0026#34;\u003c/span\u003e, \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;syndication\u0026#34;\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            Path(path_folder)\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003emkdir(parents\u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#66d9ef\"\u003eTrue\u003c/span\u003e, exist_ok\u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#66d9ef\"\u003eTrue\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            path_file \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e os\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003epath\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003ejoin(path_folder, key)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            \u003cspan style=\"color:#66d9ef\"\u003ewith\u003c/span\u003e open(path_file \u003cspan style=\"color:#f92672\"\u003e+\u003c/span\u003e \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;.json\u0026#34;\u003c/span\u003e, \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;w\u0026#34;\u003c/span\u003e) \u003cspan style=\"color:#66d9ef\"\u003eas\u003c/span\u003e fp:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e                json\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003edump({\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;syndication\u0026#34;\u003c/span\u003e: self\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003eoutput[key]}, fp)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003edef\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003erun\u003c/span\u003e(self):\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        self\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003edata_gathering()\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        self\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003ewrite()\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003ew \u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e WriterSyndication(rss_url_mastodon, domain)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003ew\u003cspan style=\"color:#f92672\"\u003e.\u003c/span\u003erun()\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003eI wrote in this way because I can change the readers or add new one but all the rest of the code remain the same.\u003c/p\u003e\n\u003ch4 id=\"todo-one-bug\" class=\"no-underline \"\u003e\n  \u003ca href=\"#todo-one-bug\"\u003e\n    \u003ci class=\"fa-whiteboard fa-semibold fa-angle-right\"\u003e\u003c/i\u003e\u003ci class=\"fa-whiteboard fa-semibold fa-angle-right\"\u003e\u003c/i\u003e\u003ci class=\"fa-whiteboard fa-semibold fa-angle-right\"\u003e\u003c/i\u003e\n    TODO one bug\n  \u003c/a\u003e\n  \u003c/h4\u003e\n\u003cp\u003eOnly thing is I need to implement some code for reading all the old file and add to them and not create a new data file if there is an old one.\u003c/p\u003e\n\u003ch3 id=\"the-github-action\" class=\"no-underline \"\u003e\n  \u003ca href=\"#the-github-action\"\u003e\n    \u003ci class=\"fa-whiteboard fa-semibold fa-angle-right\"\u003e\u003c/i\u003e\u003ci class=\"fa-whiteboard fa-semibold fa-angle-right\"\u003e\u003c/i\u003e\n    The GitHub Action\n  \u003c/a\u003e\n  \u003c/h3\u003e\n\u003cp\u003eI run it as a Github Action with this parameters.\u003c/p\u003e\n\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;\"\u003e\u003ccode class=\"language-yaml\" data-lang=\"yaml\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#f92672\"\u003ename\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eSyndication Link\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#f92672\"\u003eon\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#f92672\"\u003eschedule\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    - \u003cspan style=\"color:#f92672\"\u003ecron\u003c/span\u003e: \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;0 */2 * * *\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#f92672\"\u003eworkflow_dispatch\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#f92672\"\u003ejobs\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#f92672\"\u003ewebmentions\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003eruns-on\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eubuntu-latest\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#f92672\"\u003esteps\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      - \u003cspan style=\"color:#f92672\"\u003ename\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eCheck out repository\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#f92672\"\u003euses\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eactions/checkout@master\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      - \u003cspan style=\"color:#f92672\"\u003ename\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eSet up Python\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#f92672\"\u003euses\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eactions/setup-python@v5\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#f92672\"\u003ewith\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e          \u003cspan style=\"color:#f92672\"\u003epython-version\u003c/span\u003e: \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;3.13\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e          \u003cspan style=\"color:#f92672\"\u003ecache\u003c/span\u003e: \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;pip\u0026#34;\u003c/span\u003e \u003cspan style=\"color:#75715e\"\u003e# caching pip dependencies\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      - \u003cspan style=\"color:#f92672\"\u003ename\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eInstall Pip dependencies\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#f92672\"\u003erun\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003epip install -r requirements.txt\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      - \u003cspan style=\"color:#f92672\"\u003ename\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eFetch Syndication\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#f92672\"\u003erun\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003epython ./action_script/syndication-collector.py\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      - \u003cspan style=\"color:#f92672\"\u003ename\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003eCommit to repository\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#f92672\"\u003eenv\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e          \u003cspan style=\"color:#f92672\"\u003eGITHUB_TOKEN\u003c/span\u003e: \u003cspan style=\"color:#ae81ff\"\u003e${{ secrets.TOKEN }}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e          \u003cspan style=\"color:#f92672\"\u003eCOMMIT_MSG\u003c/span\u003e: |\u003cspan style=\"color:#e6db74\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#e6db74\"\u003e            👾Fetch webmentions\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#e6db74\"\u003e            skip-checks: true\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#f92672\"\u003erun\u003c/span\u003e: |\u003cspan style=\"color:#e6db74\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#e6db74\"\u003e          git config user.email \u0026#34;git@fundor333.com\u0026#34;\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#e6db74\"\u003e          git config user.name \u0026#34;fundor333\u0026#34;\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#e6db74\"\u003e          git remote set-url origin https://x-access-token:${GITHUB_TOKEN}@github.com/fundor333/fundor333.github.io.git\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#e6db74\"\u003e          git checkout main\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#e6db74\"\u003e          git add .\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#e6db74\"\u003e          git diff --quiet \u0026amp;\u0026amp; git diff --staged --quiet || (git commit -m \u0026#34;${COMMIT_MSG}\u0026#34;; git push origin main)\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003eI always put \u0026ldquo;workflow_dispatch\u0026rdquo; as one of the running condiction for having a manual button for running it.\u003c/p\u003e\n\u003ch3 id=\"the-template\" class=\"no-underline \"\u003e\n  \u003ca href=\"#the-template\"\u003e\n    \u003ci class=\"fa-whiteboard fa-semibold fa-angle-right\"\u003e\u003c/i\u003e\u003ci class=\"fa-whiteboard fa-semibold fa-angle-right\"\u003e\u003c/i\u003e\n    The template\n  \u003c/a\u003e\n  \u003c/h3\u003e\n\u003cp\u003eThis is the template fragment I use to show the syndication of one of the post.\nIt return a single line of text with all the link of the syndication label as the host of the service (as if it is a mastodon.social/xxxx/xxxx link, the label will be mastodon.social).\u003c/p\u003e\n\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;\"\u003e\u003ccode class=\"language-go-html-template\" data-lang=\"go-html-template\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e{{\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003e$urlized\u003c/span\u003e \u003cspan style=\"color:#f92672\"\u003e:=\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003e.Page.Permalink\u003c/span\u003e \u003cspan style=\"color:#f92672\"\u003e|\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003emd5\u003c/span\u003e \u003cspan style=\"color:#75715e\"\u003e}}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e{{\u003c/span\u003e \u003cspan style=\"color:#66d9ef\"\u003eif\u003c/span\u003e \u003cspan style=\"color:#66d9ef\"\u003eindex\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003e.Site.Data.syndication\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003e$urlized\u003c/span\u003e \u003cspan style=\"color:#75715e\"\u003e}}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u0026lt;\u003cspan style=\"color:#f92672\"\u003ehr\u003c/span\u003e\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u0026lt;\u003cspan style=\"color:#f92672\"\u003ebr\u003c/span\u003e\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u0026lt;\u003cspan style=\"color:#f92672\"\u003ediv\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;syndication\u0026#34;\u003c/span\u003e\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u0026lt;\u003cspan style=\"color:#f92672\"\u003ei\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;fas fa-link\u0026#34;\u003c/span\u003e\u0026gt;\u0026lt;/\u003cspan style=\"color:#f92672\"\u003ei\u003c/span\u003e\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      This post was also syndicated to:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#75715e\"\u003e{{\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003e$data\u003c/span\u003e\u003cspan style=\"color:#f92672\"\u003e:=\u003c/span\u003e  \u003cspan style=\"color:#66d9ef\"\u003eindex\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003e.Site.Data.syndication\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003e$urlized\u003c/span\u003e  \u003cspan style=\"color:#75715e\"\u003e}}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#75715e\"\u003e{{\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003e$data\u003c/span\u003e\u003cspan style=\"color:#f92672\"\u003e:=\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003e$data\u003c/span\u003e\u003cspan style=\"color:#a6e22e\"\u003e.syndication\u003c/span\u003e \u003cspan style=\"color:#75715e\"\u003e}}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#75715e\"\u003e{{\u003c/span\u003e \u003cspan style=\"color:#66d9ef\"\u003erange\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003e$index\u003c/span\u003e\u003cspan style=\"color:#f92672\"\u003e,\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003e$url\u003c/span\u003e \u003cspan style=\"color:#f92672\"\u003e:=\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003e$data\u003c/span\u003e\u003cspan style=\"color:#75715e\"\u003e}}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#75715e\"\u003e{{-\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003e$parsed_url\u003c/span\u003e \u003cspan style=\"color:#f92672\"\u003e:=\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003eurls\u003c/span\u003e\u003cspan style=\"color:#a6e22e\"\u003e.Parse\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003e$url\u003c/span\u003e \u003cspan style=\"color:#75715e\"\u003e-}}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u003cspan style=\"color:#75715e\"\u003e{{-\u003c/span\u003e \u003cspan style=\"color:#66d9ef\"\u003eif\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003e$index\u003c/span\u003e \u003cspan style=\"color:#75715e\"\u003e}}\u003c/span\u003e, \u003cspan style=\"color:#75715e\"\u003e{{-\u003c/span\u003e \u003cspan style=\"color:#66d9ef\"\u003eend\u003c/span\u003e \u003cspan style=\"color:#75715e\"\u003e}}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        \u0026lt;\u003cspan style=\"color:#f92672\"\u003ea\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003eclass\u003c/span\u003e\u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;u-syndication\u0026#34;\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003ehref\u003c/span\u003e\u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;\u003c/span\u003e\u003cspan style=\"color:#75715e\"\u003e{{\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003e$url\u003c/span\u003e \u003cspan style=\"color:#75715e\"\u003e}}\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003erel\u003c/span\u003e\u003cspan style=\"color:#f92672\"\u003e=\u003c/span\u003e\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;syndication\u0026#34;\u003c/span\u003e\u0026gt;\u003cspan style=\"color:#75715e\"\u003e{{\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003e$parsed_url\u003c/span\u003e\u003cspan style=\"color:#a6e22e\"\u003e.Host\u003c/span\u003e \u003cspan style=\"color:#75715e\"\u003e}}\u003c/span\u003e\u0026lt;/\u003cspan style=\"color:#f92672\"\u003ea\u003c/span\u003e\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e      \u003cspan style=\"color:#75715e\"\u003e{{\u003c/span\u003e \u003cspan style=\"color:#66d9ef\"\u003eend\u003c/span\u003e \u003cspan style=\"color:#75715e\"\u003e}}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u0026lt;/\u003cspan style=\"color:#f92672\"\u003ediv\u003c/span\u003e\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u0026lt;\u003cspan style=\"color:#f92672\"\u003ebr\u003c/span\u003e\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e{{\u003c/span\u003e \u003cspan style=\"color:#66d9ef\"\u003eend\u003c/span\u003e \u003cspan style=\"color:#75715e\"\u003e}}\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003eI also add the microformat2 tags because all my site has them.\u003c/p\u003e\n\u003ch2 id=\"conclusion\" class=\"no-underline \"\u003e\n  \u003ca href=\"#conclusion\"\u003e\n    \u003ci class=\"fa-whiteboard fa-semibold fa-angle-right\"\u003e\u003c/i\u003e\n    Conclusion\n  \u003c/a\u003e\n  \u003c/h2\u003e\n\u003cp\u003eI love this way and I am happy because I resolve a problem I had with my blog for 3 years\u003c/p\u003e\n\u003cdiv class=\"footnotes\" role=\"doc-endnotes\"\u003e\n\u003chr\u003e\n\u003col\u003e\n\u003cli id=\"fn:1\"\u003e\n\u003cp\u003e\u003ca class=\"a-post interlink-script\" href=\"https://chringel.dev/2022/07/indiewebify-me-and-dont-forget-my-webmentions/\"   target=\"_blank\"\u003eIndiewebify me! And don\u0026rsquo;t forget my webmentions!\u0026nbsp;\u0026nbsp;\u003ci class=\"fa-whiteboard fa-semibold fa-link\"\u003e\u003c/i\u003e\u003c/a\u003e\n\u0026#160;\u003ca href=\"#fnref:1\" class=\"footnote-backref\" role=\"doc-backlink\"\u003e\u0026#x21a9;\u0026#xfe0e;\u003c/a\u003e\u003c/p\u003e\n\u003c/li\u003e\n\u003cli id=\"fn:2\"\u003e\n\u003cp\u003e\u003ca class=\"a-post interlink-script\" href=\"https://fosstodon.org/@chringel/108754642028626230\"   target=\"_blank\"\u003edev with the same problem\u0026nbsp;\u0026nbsp;\u003ci class=\"fa-whiteboard fa-semibold fa-link\"\u003e\u003c/i\u003e\u003c/a\u003e\n\u0026#160;\u003ca href=\"#fnref:2\" class=\"footnote-backref\" role=\"doc-backlink\"\u003e\u0026#x21a9;\u0026#xfe0e;\u003c/a\u003e\u003c/p\u003e\n\u003c/li\u003e\n\u003cli id=\"fn:3\"\u003e\n\u003cp\u003e\u003ca class=\"a-post interlink-script\" href=\"https://paul.kinlan.me/using-web-mentions-in-a-static-sitehugo/\"   target=\"_blank\"\u003eUsing Web Mentions in a static site (Hugo)\u0026nbsp;\u0026nbsp;\u003ci class=\"fa-whiteboard fa-semibold fa-link\"\u003e\u003c/i\u003e\u003c/a\u003e\n\u0026#160;\u003ca href=\"#fnref:3\" class=\"footnote-backref\" role=\"doc-backlink\"\u003e\u0026#x21a9;\u0026#xfe0e;\u003c/a\u003e\u003c/p\u003e\n\u003c/li\u003e\n\u003cli id=\"fn:4\"\u003e\n\u003cp\u003e\u003ca class=\"a-post interlink-script\" href=\"https://brandonrozek.com/blog/syndicating-hugo-to-medium/\"   target=\"_blank\"\u003eSyndicating Hugo Posts to Medium\u0026nbsp;\u0026nbsp;\u003ci class=\"fa-whiteboard fa-semibold fa-link\"\u003e\u003c/i\u003e\u003c/a\u003e\n\u0026#160;\u003ca href=\"#fnref:4\" class=\"footnote-backref\" role=\"doc-backlink\"\u003e\u0026#x21a9;\u0026#xfe0e;\u003c/a\u003e\u003c/p\u003e\n\u003c/li\u003e\n\u003c/ol\u003e\n\u003c/div\u003e\n","content_text":"A lot of time ago I implement the Webmention in my site following a lot of blogpost.\nOne of them was a bigger ispiration for my implementation1 and I have some chat with the author of the post over Mastodon for the implementation of the syndications link in a static site2 and how to implement it.\nFundor333 @fundor333@mastodon.social @chringel How do you fill the syndications\u0026#39; links? By hand?\n10:56 AM · Aug 2, 2022 Christian 👼 @chringel@fosstodon.org @fundor333 Yeah, unfortunately that‘s how I do it.\n1. Publish a post on my blog\n2. Post the link on Twitter/Mastodon/…\n3. Update syndication param in front matter and republish\nHaven‘t found another way yet.\n6:15 PM · Aug 2, 2022 After 3 years I find the solution in a post about webmetions!\nThe input Paul Kinlan wrote an article in the 2019 which flow under my radar and I didn\u0026rsquo;read it untile recently3.\nIn this post he use a Github action to write the webmention into a data folder for his GoHugo implementation. He has a script which download the data and put into file (the name of the file is the hash of the url of the post) which are use to render the webpage interested by the webmention. And all of this into Github Actions\u0026hellip;\nSo I start thinking about it more and more\u0026hellip; What can I have the syndications links into a file for url? Like the webmention in this post? I need to read the urls form the social media and other stuff.\nBut now with X/Twitter in bad shape and Facebook/Meta only good for share photos I only use Mastodon so it is easy read them and write a file for url\u0026hellip;\nA implementation I find is this one by Brandon Rozek4 that I like in a lot of way but I change it because I don\u0026rsquo;t use Medium\u0026hellip;\nThe implementation So I start with the development:\nI need a file type/data structure standard for the Syndication I need a script (or more) that find the syndication\u0026rsquo;s links I need to edit/add to the template some code for the render of it Structure data First are the data structure: json, with the name of the file is an hash of the url\n{ \u0026#34;syndication\u0026#34;: [ \u0026#34;https://mastodon.social/@fundor333/113809667070052761\u0026#34; ] }For example this is my data for this post . I choose Json because I can make check on it and it is a beautiful format for data\nThe Scraper script In this case I find that Mastodon generate a feed for every public profile so I only implementa a reader (class MastodonFinder) which read the feed and save the toots url if find a link to my domain, and a writer class (WriterSyndication) which run all the other class (in this case only the Mastodon one) and write the output as a look-a-like of the json show before.\nimport feedparser from pathlib import Path import os import json import hashlib domain = \u0026#34;https://fundor333.com\u0026#34; rss_url_mastodon = \u0026#34;https://mastodon.social/@fundor333.rss\u0026#34; def clean_slug(slug: str): return hashlib.md5( (slug.split(\u0026#34;?\u0026#34;)[0]).encode(\u0026#34;utf-8\u0026#34;), usedforsecurity=False ).hexdigest() class MastodonFinder: def find_urls(self, string): x = string.split(\u0026#39;\u0026#34;\u0026#39;) res = [] for i in x: if i.startswith(\u0026#34;https:\u0026#34;) or i.startswith(\u0026#34;http:\u0026#34;): res.append(i) return res def run(self, rss_url: str, domain: str, output: dict): feed = feedparser.parse(rss_url) if feed.status == 200: for entry in feed.entries: link = entry.get(\u0026#34;link\u0026#34;) for e in self.find_urls(entry.get(\u0026#34;description\u0026#34;)): if domain in e: e = clean_slug(e) if output.get(e, False): output[e].append(link) else: output[e] = [link.strip()] else: print(\u0026#34;Failed to get RSS feed. Status code:\u0026#34;, feed.status) class WriterSyndication: def __init__(self, rss_url_mastodon: str, domain: str): self.output = {} self.rss_url_mastodon = rss_url_mastodon self.domain = domain def data_gathering(self): m = MastodonFinder() m.run(self.rss_url_mastodon, self.domain, self.output) def write(self): for key in self.output.keys(): path_folder = os.path.join(\u0026#34;data\u0026#34;, \u0026#34;syndication\u0026#34;) Path(path_folder).mkdir(parents=True, exist_ok=True) path_file = os.path.join(path_folder, key) with open(path_file + \u0026#34;.json\u0026#34;, \u0026#34;w\u0026#34;) as fp: json.dump({\u0026#34;syndication\u0026#34;: self.output[key]}, fp) def run(self): self.data_gathering() self.write() w = WriterSyndication(rss_url_mastodon, domain) w.run()I wrote in this way because I can change the readers or add new one but all the rest of the code remain the same.\nTODO one bug Only thing is I need to implement some code for reading all the old file and add to them and not create a new data file if there is an old one.\nThe GitHub Action I run it as a Github Action with this parameters.\nname: Syndication Link on: schedule: - cron: \u0026#34;0 */2 * * *\u0026#34; workflow_dispatch: jobs: webmentions: runs-on: ubuntu-latest steps: - name: Check out repository uses: actions/checkout@master - name: Set up Python uses: actions/setup-python@v5 with: python-version: \u0026#34;3.13\u0026#34; cache: \u0026#34;pip\u0026#34; # caching pip dependencies - name: Install Pip dependencies run: pip install -r requirements.txt - name: Fetch Syndication run: python ./action_script/syndication-collector.py - name: Commit to repository env: GITHUB_TOKEN: ${{ secrets.TOKEN }} COMMIT_MSG: | 👾Fetch webmentions skip-checks: true run: | git config user.email \u0026#34;git@fundor333.com\u0026#34; git config user.name \u0026#34;fundor333\u0026#34; git remote set-url origin https://x-access-token:${GITHUB_TOKEN}@github.com/fundor333/fundor333.github.io.git git checkout main git add . git diff --quiet \u0026amp;\u0026amp; git diff --staged --quiet || (git commit -m \u0026#34;${COMMIT_MSG}\u0026#34;; git push origin main)I always put \u0026ldquo;workflow_dispatch\u0026rdquo; as one of the running condiction for having a manual button for running it.\nThe template This is the template fragment I use to show the syndication of one of the post. It return a single line of text with all the link of the syndication label as the host of the service (as if it is a mastodon.social/xxxx/xxxx link, the label will be mastodon.social).\n{{ $urlized := .Page.Permalink | md5 }} {{ if index .Site.Data.syndication $urlized }} \u0026lt;hr\u0026gt; \u0026lt;br\u0026gt; \u0026lt;div class=\u0026#34;syndication\u0026#34;\u0026gt; \u0026lt;i class=\u0026#34;fas fa-link\u0026#34;\u0026gt;\u0026lt;/i\u0026gt; This post was also syndicated to: {{ $data:= index .Site.Data.syndication $urlized }} {{ $data:= $data.syndication }} {{ range $index, $url := $data}} {{- $parsed_url := urls.Parse $url -}} {{- if $index }}, {{- end }} \u0026lt;a class=\u0026#34;u-syndication\u0026#34; href=\u0026#34;{{ $url }}\u0026#34; rel=\u0026#34;syndication\u0026#34;\u0026gt;{{ $parsed_url.Host }}\u0026lt;/a\u0026gt; {{ end }} \u0026lt;/div\u0026gt; \u0026lt;br\u0026gt; {{ end }}I also add the microformat2 tags because all my site has them.\nConclusion I love this way and I am happy because I resolve a problem I had with my blog for 3 years\nIndiewebify me! And don\u0026rsquo;t forget my webmentions!\u0026nbsp;\u0026nbsp; \u0026#160;\u0026#x21a9;\u0026#xfe0e;\ndev with the same problem\u0026nbsp;\u0026nbsp; \u0026#160;\u0026#x21a9;\u0026#xfe0e;\nUsing Web Mentions in a static site (Hugo)\u0026nbsp;\u0026nbsp; \u0026#160;\u0026#x21a9;\u0026#xfe0e;\nSyndicating Hugo Posts to Medium\u0026nbsp;\u0026nbsp; \u0026#160;\u0026#x21a9;\u0026#xfe0e;\n","image":"https://fundor333.com/post/2025/github-action-for-syndication-links/cover.png","banner_image":"https://fundor333.com/post/2025/github-action-for-syndication-links/cover.png"}]}