<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Sreethul</title>
    <description>The latest articles on DEV Community by Sreethul (@ksreethul).</description>
    <link>https://dev.to/ksreethul</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3572587%2Fe7f5c02b-47a4-46cb-b0cf-6c94025909f5.jpeg</url>
      <title>DEV Community: Sreethul</title>
      <link>https://dev.to/ksreethul</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/ksreethul"/>
    <language>en</language>
    <item>
      <title>Building a Scalable Sidebar Architecture in Django Using Decorators, Registries, and Context Processors</title>
      <dc:creator>Sreethul</dc:creator>
      <pubDate>Sun, 10 May 2026 07:06:06 +0000</pubDate>
      <link>https://dev.to/ksreethul/building-a-scalable-sidebar-architecture-in-django-using-decorators-registries-and-context-3bf5</link>
      <guid>https://dev.to/ksreethul/building-a-scalable-sidebar-architecture-in-django-using-decorators-registries-and-context-3bf5</guid>
      <description>&lt;p&gt;When building large Django applications, one problem slowly becomes painful:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;sidebar management
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Especially in modular systems like:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;HRMS&lt;/li&gt;
&lt;li&gt;CRM&lt;/li&gt;
&lt;li&gt;ERP&lt;/li&gt;
&lt;li&gt;Admin panels&lt;/li&gt;
&lt;li&gt;Multi-app dashboards&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;At first, updating the sidebar feels simple.&lt;/p&gt;

&lt;p&gt;But once your project grows to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;10+ apps&lt;/li&gt;
&lt;li&gt;multiple contributors&lt;/li&gt;
&lt;li&gt;role-based permissions&lt;/li&gt;
&lt;li&gt;dynamic navigation&lt;/li&gt;
&lt;li&gt;HTMX interactions&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;your &lt;code&gt;sidebar.html&lt;/code&gt; quickly becomes a maintenance nightmare.&lt;/p&gt;




&lt;h1&gt;
  
  
  The Problem I Faced
&lt;/h1&gt;

&lt;p&gt;In my Django CRM project, every new app required updating:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;sidebar.html
sub_sidebar.html
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;li&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;a&lt;/span&gt; &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;"/accounts/"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Accounts&lt;span class="nt"&gt;&amp;lt;/a&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/li&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;li&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;a&lt;/span&gt; &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;"/contacts/"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Contacts&lt;span class="nt"&gt;&amp;lt;/a&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/li&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This caused several problems:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Every contributor had to modify core sidebar templates&lt;/li&gt;
&lt;li&gt;Frequent Git merge conflicts&lt;/li&gt;
&lt;li&gt;Sidebar logic became centralized and difficult to maintain&lt;/li&gt;
&lt;li&gt;Permission handling became repetitive&lt;/li&gt;
&lt;li&gt;Adding new apps required touching unrelated files&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The bigger the project became, the worse it felt.&lt;/p&gt;




&lt;h1&gt;
  
  
  The Idea
&lt;/h1&gt;

&lt;p&gt;Instead of manually editing central sidebar templates, I wanted:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Each app should register its own menu items.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;So I created a small registry-based menu system using:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;decorators&lt;/li&gt;
&lt;li&gt;registries&lt;/li&gt;
&lt;li&gt;context processors&lt;/li&gt;
&lt;li&gt;app auto-discovery&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Now every app owns its own sidebar configuration.&lt;/p&gt;




&lt;h1&gt;
  
  
  Final Project Structure
&lt;/h1&gt;

&lt;p&gt;Example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;horilla_crm/
├── accounts/
│   ├── menu.py
│   ├── views.py
│   ├── urls.py
│   └── apps.py
│
├── activity/
│   ├── menu.py
│   ├── views.py
│   ├── urls.py
│   └── apps.py
│
├── project/
│   ├── menus/
│   │   ├── main.py
│   │   ├── sub.py
│   │   └── context_processors.py
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h1&gt;
  
  
  Step 1 — Creating Menu Registries
&lt;/h1&gt;

&lt;h2&gt;
  
  
  Main Sidebar Registry
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# project/menus/main.py
&lt;/span&gt;
&lt;span class="n"&gt;main_section_menu&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;register&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cls&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;main_section_menu&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cls&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;cls&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Sub Sidebar Registry
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# project/menus/sub.py
&lt;/span&gt;
&lt;span class="n"&gt;sub_section_menu&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;register&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cls&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;sub_section_menu&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cls&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;cls&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h1&gt;
  
  
  Step 2 — Registering Menus Inside Apps
&lt;/h1&gt;

&lt;p&gt;Now every app can define its own menus.&lt;/p&gt;

&lt;p&gt;Example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# accounts/menu.py
&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;django.utils.translation&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;gettext_lazy&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;django.urls&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;reverse_lazy&lt;/span&gt;

&lt;span class="n"&gt;MAIN_CONTENT_HX_ATTRS&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;hx-boost&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;true&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;hx-target&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;#mainContent&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;hx-select&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;#mainContent&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;hx-swap&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;outerHTML&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Main Section
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="nd"&gt;@main_section_menu.register&lt;/span&gt;
&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;AccountsSection&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;section&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;accounts&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;_&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Accounts&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;icon&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;/assets/icons/accounts.svg&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="n"&gt;position&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Sub Section
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="nd"&gt;@sub_section_menu.register&lt;/span&gt;
&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;AccountsSubSection&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;section&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;accounts&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="n"&gt;app_label&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;accounts&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;

    &lt;span class="n"&gt;verbose_name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;_&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Accounts&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;icon&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;/assets/icons/accounts.svg&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;

    &lt;span class="n"&gt;position&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;

    &lt;span class="n"&gt;url&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;reverse_lazy&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;accounts:list&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;attrs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;MAIN_CONTENT_HX_ATTRS&lt;/span&gt;

    &lt;span class="n"&gt;perm&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;accounts.view_accounts&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;accounts.view_own_accounts&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now the app becomes completely self-contained.&lt;/p&gt;




&lt;h1&gt;
  
  
  Step 3 — Dynamic Menu Loading
&lt;/h1&gt;

&lt;p&gt;I created an &lt;code&gt;AppLauncher&lt;/code&gt; system to auto-import modules like:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;menu&lt;/li&gt;
&lt;li&gt;signals&lt;/li&gt;
&lt;li&gt;dashboard&lt;/li&gt;
&lt;li&gt;registrations&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;AccountsConfig&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;AppLauncher&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;

    &lt;span class="n"&gt;auto_import_modules&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;registration&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;signals&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;menu&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;dashboard&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This automatically imports &lt;code&gt;menu.py&lt;/code&gt; during startup.&lt;/p&gt;

&lt;p&gt;So developers never need to manually import menus.&lt;/p&gt;




&lt;h1&gt;
  
  
  Step 4 — Building Menu Objects
&lt;/h1&gt;

&lt;p&gt;I created helper functions like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;get_sub_section_menu&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;which:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;validates permissions&lt;/li&gt;
&lt;li&gt;groups menus by section&lt;/li&gt;
&lt;li&gt;sorts menus using position&lt;/li&gt;
&lt;li&gt;validates missing sections&lt;/li&gt;
&lt;li&gt;prepares final menu dictionaries&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Example validation:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;raise&lt;/span&gt; &lt;span class="nc"&gt;ImproperlyConfigured&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Sub section uses section &lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;section_name&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt; &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;but no matching main section exists.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This prevented silent configuration errors.&lt;/p&gt;




&lt;h1&gt;
  
  
  Step 5 — Using Context Processors
&lt;/h1&gt;

&lt;p&gt;Then I exposed menus globally using a context processor.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;menu_context_processor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;main_section_menu&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;get_main_section_menu&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;sub_section_menu&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;get_sub_section_menu&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now every template automatically receives menu data.&lt;/p&gt;




&lt;h1&gt;
  
  
  Step 6 — Rendering Menus in Templates
&lt;/h1&gt;

&lt;h2&gt;
  
  
  Main Sidebar
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jinja"&gt;&lt;code&gt;&lt;span class="cp"&gt;{%&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="nv"&gt;item&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nv"&gt;main_section_menu&lt;/span&gt; &lt;span class="cp"&gt;%}&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;a&lt;/span&gt; &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="cp"&gt;{{&lt;/span&gt; &lt;span class="nv"&gt;item.url&lt;/span&gt; &lt;span class="cp"&gt;}}&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="cp"&gt;{{&lt;/span&gt; &lt;span class="nv"&gt;item.name&lt;/span&gt; &lt;span class="cp"&gt;}}&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/a&amp;gt;&lt;/span&gt;
&lt;span class="cp"&gt;{%&lt;/span&gt; &lt;span class="k"&gt;endfor&lt;/span&gt; &lt;span class="cp"&gt;%}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Sub Sidebar
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jinja"&gt;&lt;code&gt;&lt;span class="cp"&gt;{%&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="nv"&gt;item&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nv"&gt;current_items&lt;/span&gt; &lt;span class="cp"&gt;%}&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;a&lt;/span&gt; &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="cp"&gt;{{&lt;/span&gt; &lt;span class="nv"&gt;item.url&lt;/span&gt; &lt;span class="cp"&gt;}}&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="cp"&gt;{{&lt;/span&gt; &lt;span class="nv"&gt;item.label&lt;/span&gt; &lt;span class="cp"&gt;}}&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/a&amp;gt;&lt;/span&gt;
&lt;span class="cp"&gt;{%&lt;/span&gt; &lt;span class="k"&gt;endfor&lt;/span&gt; &lt;span class="cp"&gt;%}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now templates became extremely small and clean.&lt;/p&gt;




&lt;h1&gt;
  
  
  Why This Architecture Helped
&lt;/h1&gt;

&lt;p&gt;This solved multiple problems immediately.&lt;/p&gt;

&lt;h2&gt;
  
  
  Contributors No Longer Modify Core Sidebar Templates
&lt;/h2&gt;

&lt;p&gt;They only create:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;menu.py
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;inside their app.&lt;/p&gt;




&lt;h2&gt;
  
  
  No More Merge Conflicts
&lt;/h2&gt;

&lt;p&gt;Huge improvement for collaborative development.&lt;/p&gt;




&lt;h2&gt;
  
  
  Permissions Became Centralized
&lt;/h2&gt;

&lt;p&gt;Each menu controls its own permissions.&lt;/p&gt;




&lt;h2&gt;
  
  
  HTMX Integration Became Easy
&lt;/h2&gt;

&lt;p&gt;Each menu can define custom HTMX attributes:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;attrs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;MAIN_CONTENT_HX_ATTRS&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Apps Became Plug-and-Play
&lt;/h2&gt;

&lt;p&gt;A new app can register itself automatically.&lt;/p&gt;




&lt;h1&gt;
  
  
  Things I Learned
&lt;/h1&gt;

&lt;p&gt;While building this, I realized:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Sidebar systems are actually plugin systems.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Once apps can contribute:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;menus&lt;/li&gt;
&lt;li&gt;dashboard widgets&lt;/li&gt;
&lt;li&gt;settings pages&lt;/li&gt;
&lt;li&gt;navigation items&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;your architecture becomes much more scalable.&lt;/p&gt;




&lt;h1&gt;
  
  
  Future Improvements
&lt;/h1&gt;

&lt;p&gt;Some ideas I plan to add later:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;menu caching&lt;/li&gt;
&lt;li&gt;badge counts&lt;/li&gt;
&lt;li&gt;nested menus&lt;/li&gt;
&lt;li&gt;feature flags&lt;/li&gt;
&lt;li&gt;dynamic visibility&lt;/li&gt;
&lt;li&gt;app-level menu ordering&lt;/li&gt;
&lt;li&gt;reusable Django package&lt;/li&gt;
&lt;/ul&gt;




&lt;h1&gt;
  
  
  Final Thoughts
&lt;/h1&gt;

&lt;p&gt;This started as:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;"I don't want to edit sidebar.html repeatedly."
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;But eventually evolved into a modular registry-based navigation architecture.&lt;/p&gt;

&lt;p&gt;For large Django projects, this approach made the codebase:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;cleaner&lt;/li&gt;
&lt;li&gt;contributor-friendly&lt;/li&gt;
&lt;li&gt;scalable&lt;/li&gt;
&lt;li&gt;easier to maintain&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;especially in multi-app systems like HRMS and CRM platforms.&lt;/p&gt;




&lt;h1&gt;
  
  
  Tech Stack
&lt;/h1&gt;

&lt;ul&gt;
&lt;li&gt;Django&lt;/li&gt;
&lt;li&gt;HTMX&lt;/li&gt;
&lt;li&gt;Tailwind CSS&lt;/li&gt;
&lt;li&gt;Python decorators&lt;/li&gt;
&lt;li&gt;Context processors&lt;/li&gt;
&lt;li&gt;Dynamic registries&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>python</category>
      <category>django</category>
      <category>opensource</category>
      <category>contributorswanted</category>
    </item>
    <item>
      <title>Integrating ETimeOffice Attendance API with Python and Django</title>
      <dc:creator>Sreethul</dc:creator>
      <pubDate>Sun, 10 May 2026 06:14:51 +0000</pubDate>
      <link>https://dev.to/ksreethul/integrating-etimeoffice-attendance-api-with-python-and-django-20hl</link>
      <guid>https://dev.to/ksreethul/integrating-etimeoffice-attendance-api-with-python-and-django-20hl</guid>
      <description>&lt;p&gt;If you’ve worked with biometric attendance systems, you already know the hardest part usually isn’t the device itself — it’s the integration layer.&lt;/p&gt;

&lt;p&gt;Different vendors expose different APIs, date formats, authentication methods, and response structures. One of the systems I recently worked with was &lt;strong&gt;ETimeOffice&lt;/strong&gt;, and I wanted a cleaner way to interact with its attendance APIs directly from Python and Django applications.&lt;/p&gt;

&lt;p&gt;So I built:&lt;/p&gt;

&lt;h2&gt;
  
  
  pyetimeoffice
&lt;/h2&gt;

&lt;p&gt;A lightweight Python integration library for working with the ETimeOffice API.&lt;/p&gt;

&lt;p&gt;GitHub: &lt;a href="https://github.com/KSreethul/pyetimeoffice" rel="noopener noreferrer"&gt;https://github.com/KSreethul/pyetimeoffice&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;PyPI: &lt;a href="https://pypi.org/project/pyetimeoffice/" rel="noopener noreferrer"&gt;https://pypi.org/project/pyetimeoffice/&lt;/a&gt;&lt;/p&gt;




&lt;h1&gt;
  
  
  Why I Built It
&lt;/h1&gt;

&lt;p&gt;In HRMS and attendance systems, we often need to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Download punch records&lt;/li&gt;
&lt;li&gt;Process in/out attendance logs&lt;/li&gt;
&lt;li&gt;Sync attendance with HRMS platforms&lt;/li&gt;
&lt;li&gt;Handle employee punch data programmatically&lt;/li&gt;
&lt;li&gt;Normalize inconsistent API response formats&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;While integrating ETimeOffice into Django-based HRMS systems, I noticed the same boilerplate code being repeated everywhere:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;HTTP Basic authentication setup&lt;/li&gt;
&lt;li&gt;Date formatting&lt;/li&gt;
&lt;li&gt;API request handling&lt;/li&gt;
&lt;li&gt;Response parsing&lt;/li&gt;
&lt;li&gt;Datetime normalization&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So I wrapped those operations into a reusable Python package.&lt;/p&gt;




&lt;h1&gt;
  
  
  Features
&lt;/h1&gt;

&lt;p&gt;&lt;code&gt;pyetimeoffice&lt;/code&gt; currently supports:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;DownloadPunchData API&lt;/li&gt;
&lt;li&gt;DownloadPunchDataMCID API&lt;/li&gt;
&lt;li&gt;DownloadInOutPunchData API&lt;/li&gt;
&lt;li&gt;Automatic datetime parsing&lt;/li&gt;
&lt;li&gt;Date range validation&lt;/li&gt;
&lt;li&gt;HTTP Basic authentication&lt;/li&gt;
&lt;li&gt;Easy integration with Django applications&lt;/li&gt;
&lt;/ul&gt;




&lt;h1&gt;
  
  
  Installation
&lt;/h1&gt;

&lt;p&gt;Install directly from PyPI:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pip &lt;span class="nb"&gt;install &lt;/span&gt;pyetimeoffice
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h1&gt;
  
  
  Quick Example
&lt;/h1&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;pyetimeoffice&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;ETimeOfficeAPI&lt;/span&gt;

&lt;span class="n"&gt;api&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;ETimeOfficeAPI&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;username&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;your_username&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;password&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;your_password&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;base_url&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;https://api.etimeoffice.com/api/&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;api&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;download_punch_data&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;from_date&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;25/03/2025_00:00&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;to_date&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;25/03/2025_12:22&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;emp_code&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;ALL&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h1&gt;
  
  
  Example Use Cases
&lt;/h1&gt;

&lt;p&gt;This library can be useful for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Django HRMS integrations&lt;/li&gt;
&lt;li&gt;Attendance synchronization&lt;/li&gt;
&lt;li&gt;Payroll processing systems&lt;/li&gt;
&lt;li&gt;Employee tracking systems&lt;/li&gt;
&lt;li&gt;ERP integrations&lt;/li&gt;
&lt;li&gt;Attendance analytics dashboards&lt;/li&gt;
&lt;/ul&gt;




&lt;h1&gt;
  
  
  Built for Django &amp;amp; HRMS Workflows
&lt;/h1&gt;

&lt;p&gt;I mainly work with Django-based HRMS and CRM systems, so the library was designed to fit naturally into backend workflows.&lt;/p&gt;

&lt;p&gt;Typical integration flow:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Fetch attendance logs from ETimeOffice&lt;/li&gt;
&lt;li&gt;Normalize punch timestamps&lt;/li&gt;
&lt;li&gt;Map employee codes&lt;/li&gt;
&lt;li&gt;Store records in Django models&lt;/li&gt;
&lt;li&gt;Generate attendance reports&lt;/li&gt;
&lt;/ol&gt;




&lt;h1&gt;
  
  
  Future Plans
&lt;/h1&gt;

&lt;p&gt;Some features planned for future releases:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Async API support&lt;/li&gt;
&lt;li&gt;Retry mechanisms&lt;/li&gt;
&lt;li&gt;Pagination helpers&lt;/li&gt;
&lt;li&gt;Webhook/event support&lt;/li&gt;
&lt;li&gt;Better filtering utilities&lt;/li&gt;
&lt;li&gt;Additional biometric vendor integrations&lt;/li&gt;
&lt;/ul&gt;




&lt;h1&gt;
  
  
  Open Source
&lt;/h1&gt;

&lt;p&gt;The project is fully open source and contributions are welcome.&lt;/p&gt;

&lt;p&gt;GitHub Repository:&lt;br&gt;
&lt;a href="https://github.com/KSreethul/pyetimeoffice" rel="noopener noreferrer"&gt;https://github.com/KSreethul/pyetimeoffice&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you’re working on attendance systems, HRMS platforms, or biometric integrations, I’d love feedback and suggestions.&lt;/p&gt;

&lt;h1&gt;
  
  
  django #hrms #attendance
&lt;/h1&gt;

</description>
      <category>python</category>
      <category>biometric</category>
      <category>opensource</category>
      <category>api</category>
    </item>
    <item>
      <title>Integrating Biometric Devices with Django: ZKTeco, Anviz, Dahua &amp; COSEC Made Simple (With Python SDKs)</title>
      <dc:creator>Sreethul</dc:creator>
      <pubDate>Fri, 24 Apr 2026 09:54:44 +0000</pubDate>
      <link>https://dev.to/ksreethul/integrating-biometric-devices-with-django-zkteco-anviz-dahua-cosec-made-simple-with-python-4em</link>
      <guid>https://dev.to/ksreethul/integrating-biometric-devices-with-django-zkteco-anviz-dahua-cosec-made-simple-with-python-4em</guid>
      <description>&lt;p&gt;If you’ve ever tried integrating biometric devices into a real-world system like an HRMS or attendance platform, you already know:&lt;/p&gt;

&lt;p&gt;It’s never just &lt;em&gt;“connect → fetch logs → done”&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;Instead, you end up dealing with:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Different APIs for each vendor&lt;/li&gt;
&lt;li&gt;Authentication nightmares (tokens, digest auth, basic auth)&lt;/li&gt;
&lt;li&gt;XML, JSON, and sometimes unreadable raw responses&lt;/li&gt;
&lt;li&gt;Pagination and large log handling&lt;/li&gt;
&lt;li&gt;Device-specific quirks and undocumented behavior&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I ran into all of this while building production systems.&lt;/p&gt;

&lt;p&gt;So instead of solving the same problems again and again, I built reusable Python libraries to simplify integrations across multiple biometric platforms.&lt;/p&gt;




&lt;h2&gt;
  
  
  🧠 The Reality of Biometric Integrations
&lt;/h2&gt;

&lt;p&gt;Every vendor works differently:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Device&lt;/th&gt;
&lt;th&gt;Challenge&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;ZKTeco&lt;/td&gt;
&lt;td&gt;SDK limitations, network sync issues&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Anviz (CrossChex Cloud)&lt;/td&gt;
&lt;td&gt;Token lifecycle + pagination&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Dahua&lt;/td&gt;
&lt;td&gt;Digest auth + complex HTTP APIs&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Matrix COSEC&lt;/td&gt;
&lt;td&gt;XML responses + cryptic codes&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;There’s no standard.&lt;br&gt;
And that’s the real problem.&lt;/p&gt;


&lt;h2&gt;
  
  
  🔧 My Approach: Build Once, Reuse Everywhere
&lt;/h2&gt;

&lt;p&gt;While working on HRMS systems, I realized:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;“Why am I rewriting the same integration logic for every project?”&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;So I created lightweight Python libraries for each major system I worked with.&lt;/p&gt;


&lt;h1&gt;
  
  
  ☁️ 1. Simplifying Anviz CrossChex Cloud (crosschexcloudapi)
&lt;/h1&gt;

&lt;p&gt;If you've used CrossChex Cloud API, you’ve probably struggled with:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Token generation &amp;amp; expiration&lt;/li&gt;
&lt;li&gt;Pagination loops&lt;/li&gt;
&lt;li&gt;Complex request structures&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;
  
  
  ✅ Solution: &lt;code&gt;crosschexcloudapi&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;A Python SDK that abstracts all of that.&lt;/p&gt;

&lt;p&gt;👉 GitHub: &lt;a href="https://github.com/KSreethul/crosschexcloudapi" rel="noopener noreferrer"&gt;https://github.com/KSreethul/crosschexcloudapi&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  Quick Example
&lt;/h3&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;crosschexcloudapi&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;CrossChexCloudAPI&lt;/span&gt;

&lt;span class="n"&gt;api&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;CrossChexCloudAPI&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;api_url&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;https://api.crosschexcloud.com&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;api_key&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;YOUR_API_KEY&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;api_secret&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;YOUR_API_SECRET&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;anviz_request_id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;REQUEST_ID&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;records&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;api&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get_attendance_records&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;records&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h3&gt;
  
  
  What It Handles
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Automatic token generation &amp;amp; refresh&lt;/li&gt;
&lt;li&gt;Pagination internally&lt;/li&gt;
&lt;li&gt;Clean structured response&lt;/li&gt;
&lt;li&gt;Retry on token expiry&lt;/li&gt;
&lt;/ul&gt;


&lt;h1&gt;
  
  
  🔌 2. Dahua Device Integration Made Easy (pydahua)
&lt;/h1&gt;

&lt;p&gt;Dahua APIs are powerful—but painful.&lt;/p&gt;

&lt;p&gt;You typically deal with:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;HTTP Digest authentication&lt;/li&gt;
&lt;li&gt;Raw key-value responses&lt;/li&gt;
&lt;li&gt;Manual parsing&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;
  
  
  ✅ Solution: &lt;code&gt;pydahua&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;👉 GitHub: &lt;a href="https://github.com/KSreethul/pydahua" rel="noopener noreferrer"&gt;https://github.com/KSreethul/pydahua&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  Quick Example
&lt;/h3&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;pydahua&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;DahuaAPI&lt;/span&gt;

&lt;span class="n"&gt;dahua&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;DahuaAPI&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;ip&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;http://192.168.1.100&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;username&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;admin&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;password&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;password&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;dahua&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get_system_info&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;dahua&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;fetch_attendance_logs&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h3&gt;
  
  
  Features
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Built-in digest authentication&lt;/li&gt;
&lt;li&gt;Clean Python responses&lt;/li&gt;
&lt;li&gt;Attendance logs parsing&lt;/li&gt;
&lt;li&gt;User &amp;amp; access control management&lt;/li&gt;
&lt;li&gt;Device control (reboot, config, etc.)&lt;/li&gt;
&lt;/ul&gt;


&lt;h1&gt;
  
  
  🏢 3. Matrix COSEC Integration Without XML Pain (pycosec)
&lt;/h1&gt;

&lt;p&gt;COSEC devices are reliable—but developer experience?&lt;/p&gt;

&lt;p&gt;Not great.&lt;/p&gt;

&lt;p&gt;Problems include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;XML responses everywhere&lt;/li&gt;
&lt;li&gt;Manual URL construction&lt;/li&gt;
&lt;li&gt;Confusing response codes&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;
  
  
  ✅ Solution: &lt;code&gt;pycosec&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;👉 GitHub: &lt;a href="https://github.com/KSreethul/pycosec" rel="noopener noreferrer"&gt;https://github.com/KSreethul/pycosec&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  Example
&lt;/h3&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;pycosec&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;COSECBiometric&lt;/span&gt;

&lt;span class="n"&gt;device&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;COSECBiometric&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;machine_ip&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;192.168.1.100&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;port&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;80&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;username&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;admin&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;password&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;admin123&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;events&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;device&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get_attendance_events&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;roll_over_count&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;seq_num&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;no_of_events&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;50&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;events&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h3&gt;
  
  
  What It Fixes
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;XML → Python dict conversion&lt;/li&gt;
&lt;li&gt;Response code mapping&lt;/li&gt;
&lt;li&gt;Authentication handling&lt;/li&gt;
&lt;li&gt;Clean reusable methods&lt;/li&gt;
&lt;/ul&gt;


&lt;h2&gt;
  
  
  ⚙️ Django Integration: The Real Goal
&lt;/h2&gt;

&lt;p&gt;All these libraries were built for one purpose:&lt;/p&gt;

&lt;p&gt;👉 &lt;strong&gt;Seamless integration into Django-based systems&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Typical flow:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Biometric Device → Python SDK → Django Service → Database → HRMS UI
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Example Workflow
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;Fetch logs from device&lt;/li&gt;
&lt;li&gt;Normalize data&lt;/li&gt;
&lt;li&gt;Store in Django models&lt;/li&gt;
&lt;li&gt;Trigger attendance processing&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  🚀 Real-World Use Cases
&lt;/h2&gt;

&lt;p&gt;These integrations power:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;HRMS platforms&lt;/li&gt;
&lt;li&gt;Payroll automation&lt;/li&gt;
&lt;li&gt;Attendance sync systems&lt;/li&gt;
&lt;li&gt;Access control dashboards&lt;/li&gt;
&lt;li&gt;SaaS workforce tools&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  💡 Key Lessons Learned
&lt;/h2&gt;

&lt;p&gt;After working with multiple biometric systems:&lt;/p&gt;

&lt;h3&gt;
  
  
  1. There is no standard
&lt;/h3&gt;

&lt;p&gt;Every device behaves differently—design abstraction layers.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Always normalize data
&lt;/h3&gt;

&lt;p&gt;Unify formats before saving to DB.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Handle scale early
&lt;/h3&gt;

&lt;p&gt;Attendance logs grow fast—optimize queries and batching.&lt;/p&gt;

&lt;h3&gt;
  
  
  4. Expect failures
&lt;/h3&gt;

&lt;p&gt;Devices disconnect. APIs break. Plan retries.&lt;/p&gt;




&lt;h2&gt;
  
  
  🔥 Why This Matters
&lt;/h2&gt;

&lt;p&gt;Biometric integration is a niche—but high-impact skill.&lt;/p&gt;

&lt;p&gt;Most developers avoid it because it's messy.&lt;/p&gt;

&lt;p&gt;But if you solve it well, you can build:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Enterprise-grade HR systems&lt;/li&gt;
&lt;li&gt;Scalable attendance platforms&lt;/li&gt;
&lt;li&gt;Integration-heavy SaaS products&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  📦 Open Source — Contributions Welcome
&lt;/h2&gt;

&lt;p&gt;All libraries are open source:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;CrossChex Cloud → &lt;a href="https://github.com/KSreethul/crosschexcloudapi" rel="noopener noreferrer"&gt;https://github.com/KSreethul/crosschexcloudapi&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Dahua → &lt;a href="https://github.com/KSreethul/pydahua" rel="noopener noreferrer"&gt;https://github.com/KSreethul/pydahua&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;COSEC → &lt;a href="https://github.com/KSreethul/pycosec" rel="noopener noreferrer"&gt;https://github.com/KSreethul/pycosec&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Feel free to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Report issues&lt;/li&gt;
&lt;li&gt;Suggest features&lt;/li&gt;
&lt;li&gt;Contribute improvements&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  🧾 Final Thoughts
&lt;/h2&gt;

&lt;p&gt;Biometric integrations don’t have to be painful.&lt;/p&gt;

&lt;p&gt;Instead of fighting APIs every time, you can:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Abstract complexity&lt;/li&gt;
&lt;li&gt;Build reusable SDKs&lt;/li&gt;
&lt;li&gt;Focus on business logic&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That’s exactly what I aimed to do with these libraries.&lt;/p&gt;




&lt;p&gt;If this helped you or saved you time, consider ⭐ starring the repos — it really supports open source.&lt;/p&gt;

</description>
      <category>django</category>
      <category>python</category>
      <category>opensource</category>
      <category>api</category>
    </item>
    <item>
      <title>Simplifying Anviz CrossChex Cloud Integration in Python (crosschexcloudapi)</title>
      <dc:creator>Sreethul</dc:creator>
      <pubDate>Tue, 21 Apr 2026 10:53:57 +0000</pubDate>
      <link>https://dev.to/ksreethul/simplifying-anviz-crosschex-cloud-integration-in-python-crosschexcloudapi-3dlj</link>
      <guid>https://dev.to/ksreethul/simplifying-anviz-crosschex-cloud-integration-in-python-crosschexcloudapi-3dlj</guid>
      <description>&lt;p&gt;If you’ve worked with the Anviz CrossChex Cloud API, you’ve probably faced this:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt; Token-based authentication complexity&lt;/li&gt;
&lt;li&gt; Token expiration handling&lt;/li&gt;
&lt;li&gt; Pagination headaches&lt;/li&gt;
&lt;li&gt; Complex request/response formats&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It’s powerful—but not exactly developer-friendly.&lt;/p&gt;

&lt;p&gt;So I built something to make it simple &lt;/p&gt;




&lt;h2&gt;
  
  
  Introducing &lt;strong&gt;crosschexcloudapi&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;A lightweight Python SDK that simplifies working with the CrossChex Cloud API.&lt;/p&gt;

&lt;p&gt;GitHub: &lt;a href="https://github.com/KSreethul/crosschexcloudapi" rel="noopener noreferrer"&gt;https://github.com/KSreethul/crosschexcloudapi&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  What This Library Fixes
&lt;/h2&gt;

&lt;p&gt;Instead of:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Manually generating tokens&lt;/li&gt;
&lt;li&gt;Tracking expiry time&lt;/li&gt;
&lt;li&gt;Writing pagination loops&lt;/li&gt;
&lt;li&gt;Handling retry logic&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You can just call one method and get everything.&lt;/p&gt;




&lt;h2&gt;
  
  
  Quick Example
&lt;/h2&gt;



&lt;p&gt;```python id="z1q0py"&lt;br&gt;
from crosschexcloudapi import CrossChexCloudAPI&lt;/p&gt;

&lt;p&gt;api = CrossChexCloudAPI(&lt;br&gt;
    api_url="&lt;a href="https://api.crosschexcloud.com" rel="noopener noreferrer"&gt;https://api.crosschexcloud.com&lt;/a&gt;",&lt;br&gt;
    api_key="YOUR_API_KEY",&lt;br&gt;
    api_secret="YOUR_API_SECRET",&lt;br&gt;
    anviz_request_id="REQUEST_ID"&lt;br&gt;
)&lt;/p&gt;

&lt;h1&gt;
  
  
  Fetch attendance records
&lt;/h1&gt;

&lt;p&gt;records = api.get_attendance_records()&lt;/p&gt;

&lt;p&gt;print(records)&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;


No manual token handling. No pagination loops.

---

##  Key Features

*  Automatic token generation &amp;amp; refresh
*  Built-in pagination handling
*  Fetch attendance logs easily
*  Clean and structured responses
*  Smart retry on token expiry
*  Minimal dependency (`requests`)

---

##  Real Example: Fetch Records with Date Range



```python id="y5w8r3"
from datetime import datetime

records = api.get_attendance_records(
    begin_time=datetime(2025, 10, 1, 0, 0, 0),
    end_time=datetime(2025, 10, 18, 23, 59, 59)
)

print(records)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Example Output
&lt;/h2&gt;



&lt;p&gt;```json id="3g1wvn"&lt;br&gt;
{&lt;br&gt;
  "token": "abc123",&lt;br&gt;
  "expires": "2025-10-20T10:00:00",&lt;br&gt;
  "count": 2,&lt;br&gt;
  "list": [&lt;br&gt;
    {&lt;br&gt;
      "employee_id": "E1001",&lt;br&gt;
      "check_time": "2025-10-18T09:00:00",&lt;br&gt;
      "type": "checkin"&lt;br&gt;
    }&lt;br&gt;
  ]&lt;br&gt;
}&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;


Everything is already combined and structured for you.

---

##  How It Works

* Generates token using API key &amp;amp; secret
* Stores token and expiry internally
* Automatically refreshes expired tokens
* Fetches all paginated records behind the scenes
* Returns a single clean response

---

##  Real-World Use Cases

This library is useful if you’re building:

* HRMS systems
* Payroll automation
* Attendance sync tools
* SaaS platforms integrating biometric data

---

##  Installation



```bash id="3v6q7d"
pip install crosschexcloudapi
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Open Source — Contributions Welcome
&lt;/h2&gt;

&lt;p&gt;If you’re working with Anviz devices:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Report issues&lt;/li&gt;
&lt;li&gt;Suggest features&lt;/li&gt;
&lt;li&gt;Contribute improvements&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Let’s make biometric integrations easier for everyone.&lt;/p&gt;




&lt;h2&gt;
  
  
  Final Thoughts
&lt;/h2&gt;

&lt;p&gt;CrossChex Cloud API is powerful—but working with it directly is time-consuming.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;crosschexcloudapi removes the complexity and lets you focus on building.&lt;/strong&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Links
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;GitHub: &lt;a href="https://github.com/KSreethul/crosschexcloudapi" rel="noopener noreferrer"&gt;https://github.com/KSreethul/crosschexcloudapi&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Issues: &lt;a href="https://github.com/KSreethul/crosschexcloudapi/issues" rel="noopener noreferrer"&gt;https://github.com/KSreethul/crosschexcloudapi/issues&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;If this helped you, consider starring the repo — it really supports open source!&lt;/p&gt;

</description>
      <category>api</category>
      <category>opensource</category>
      <category>python</category>
      <category>showdev</category>
    </item>
    <item>
      <title>Simplifying Dahua Biometric Integration with Python (pydahua)</title>
      <dc:creator>Sreethul</dc:creator>
      <pubDate>Tue, 21 Apr 2026 10:51:17 +0000</pubDate>
      <link>https://dev.to/ksreethul/simplifying-dahua-biometric-integration-with-python-pydahua-40fc</link>
      <guid>https://dev.to/ksreethul/simplifying-dahua-biometric-integration-with-python-pydahua-40fc</guid>
      <description>&lt;p&gt;If you've ever worked with Dahua biometric or access control devices, you already know the pain:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt; Complex HTTP APIs&lt;/li&gt;
&lt;li&gt; Digest authentication headaches&lt;/li&gt;
&lt;li&gt; Raw, unreadable responses&lt;/li&gt;
&lt;li&gt; Manual pagination &amp;amp; parsing&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I faced the same challenges while building real-world HRMS and attendance systems.&lt;br&gt;
So I built something to fix it &lt;/p&gt;




&lt;h2&gt;
  
  
  Introducing &lt;strong&gt;pydahua&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;pydahua&lt;/strong&gt; is a Python library that makes interacting with Dahua biometric devices simple, clean, and developer-friendly.&lt;/p&gt;

&lt;p&gt;GitHub: &lt;a href="https://github.com/KSreethul/pydahua" rel="noopener noreferrer"&gt;https://github.com/KSreethul/pydahua&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  What Problems Does It Solve?
&lt;/h2&gt;

&lt;p&gt;Instead of writing low-level API calls like this:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Constructing URLs manually&lt;/li&gt;
&lt;li&gt;Handling HTTP Digest authentication&lt;/li&gt;
&lt;li&gt;Parsing raw key-value responses&lt;/li&gt;
&lt;li&gt;Managing logs manually&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You can now do everything with simple Python methods.&lt;/p&gt;




&lt;h2&gt;
  
  
  Quick Example
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;pydahua&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;DahuaAPI&lt;/span&gt;

&lt;span class="n"&gt;dahua&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;DahuaAPI&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;ip&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;http://192.168.1.100&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;username&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;admin&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;password&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;password&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;# Get system info
&lt;/span&gt;&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;dahua&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get_system_info&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;

&lt;span class="c1"&gt;# Fetch attendance logs
&lt;/span&gt;&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;dahua&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;fetch_attendance_logs&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That’s it. No complexity.&lt;/p&gt;




&lt;h2&gt;
  
  
  Key Features
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt; Built-in HTTP Digest authentication&lt;/li&gt;
&lt;li&gt; Clean and structured API responses&lt;/li&gt;
&lt;li&gt; User management (add, delete, fetch)&lt;/li&gt;
&lt;li&gt; Access card enrollment&lt;/li&gt;
&lt;li&gt; Attendance log retrieval (with parsing)&lt;/li&gt;
&lt;li&gt; Device configuration support&lt;/li&gt;
&lt;li&gt; Device control (reboot, shutdown)&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Real-World Use Cases
&lt;/h2&gt;

&lt;p&gt;I built this while working on:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;HRMS systems&lt;/li&gt;
&lt;li&gt;Attendance automation&lt;/li&gt;
&lt;li&gt;Biometric integrations&lt;/li&gt;
&lt;li&gt;Access control solutions&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you're building something similar, this will save you &lt;strong&gt;hours (or days)&lt;/strong&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  Example: Fetch Attendance Logs
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;datetime&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;datetime&lt;/span&gt;

&lt;span class="n"&gt;logs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;dahua&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get_control_card_rec&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;card_no&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;123456&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;start_time&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nf"&gt;datetime&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2025&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="n"&gt;end_time&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nf"&gt;datetime&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2025&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;18&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;23&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;59&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;59&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;logs&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Output (clean &amp;amp; structured)
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"records"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"card_no"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"123456"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"card_name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"John Doe"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"attendance_state"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"CheckIn"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"door"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"1"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"create_time"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"2025-01-18T09:12:33"&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"count"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Why I Built This
&lt;/h2&gt;

&lt;p&gt;Most biometric SDKs are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Either poorly documented&lt;/li&gt;
&lt;li&gt;Or locked behind enterprise systems&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I wanted a &lt;strong&gt;simple, open-source solution&lt;/strong&gt; that developers can plug into any system.&lt;/p&gt;




&lt;h2&gt;
  
  
  Installation
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pip &lt;span class="nb"&gt;install &lt;/span&gt;pydahua
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Supported Devices
&lt;/h2&gt;

&lt;p&gt;Works with Dahua devices that support:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;magicBox.cgi&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;configManager.cgi&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;userManager.cgi&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;recordFinder.cgi&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Open Source — Contributions Welcome
&lt;/h2&gt;

&lt;p&gt;If you're working with biometric systems, I'd love your feedback.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Found a bug? Open an issue&lt;/li&gt;
&lt;li&gt;Need a feature? Suggest it&lt;/li&gt;
&lt;li&gt;Want to contribute? PRs are welcome&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Final Thoughts
&lt;/h2&gt;

&lt;p&gt;If you're building:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;HR software&lt;/li&gt;
&lt;li&gt;Attendance systems&lt;/li&gt;
&lt;li&gt;Access control tools&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;pydahua can save you a lot of time and frustration.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Give it a try and let me know what you think &lt;/p&gt;




&lt;h2&gt;
  
  
  Links
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;GitHub: &lt;a href="https://github.com/KSreethul/pydahua" rel="noopener noreferrer"&gt;https://github.com/KSreethul/pydahua&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Issues: &lt;a href="https://github.com/KSreethul/pydahua/issues" rel="noopener noreferrer"&gt;https://github.com/KSreethul/pydahua/issues&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;If you found this useful, consider starring the repo — it really helps!&lt;/p&gt;

</description>
      <category>api</category>
      <category>iot</category>
      <category>python</category>
      <category>showdev</category>
    </item>
    <item>
      <title>I Built a Python Library for Matrix COSEC Biometric Devices (So You Don’t Have To)</title>
      <dc:creator>Sreethul</dc:creator>
      <pubDate>Tue, 21 Apr 2026 10:31:32 +0000</pubDate>
      <link>https://dev.to/ksreethul/i-built-a-python-library-for-matrix-cosec-biometric-devices-so-you-dont-have-to-f8k</link>
      <guid>https://dev.to/ksreethul/i-built-a-python-library-for-matrix-cosec-biometric-devices-so-you-dont-have-to-f8k</guid>
      <description>&lt;p&gt;If you’ve ever worked with COSEC biometric devices, you probably already know…&lt;/p&gt;

&lt;p&gt;It’s not as simple as:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;“Connect device → Fetch attendance → Done”&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;In reality, it looks more like:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Confusing APIs&lt;/li&gt;
&lt;li&gt;XML responses everywhere&lt;/li&gt;
&lt;li&gt;Authentication quirks&lt;/li&gt;
&lt;li&gt;Trial-and-error debugging for hours&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I ran into all of this while building an HRMS system.&lt;/p&gt;

&lt;p&gt;So instead of repeating the same pain in every project, I built a reusable solution:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;pycosec&lt;/strong&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Why I Built This
&lt;/h2&gt;

&lt;p&gt;While working on biometric integration, I expected a clean API experience.&lt;/p&gt;

&lt;p&gt;But what I got was:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Raw XML responses&lt;/li&gt;
&lt;li&gt;Hard-to-understand response codes&lt;/li&gt;
&lt;li&gt;Manual URL construction for every request&lt;/li&gt;
&lt;li&gt;Repetitive integration code across projects&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;At some point, it became clear:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;“This shouldn’t be this hard every single time.”&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;So I created a Python library to simplify everything.&lt;/p&gt;




&lt;h2&gt;
  
  
  What is pycosec?
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;pycosec&lt;/strong&gt; is a lightweight Python package that helps you interact with COSEC biometric devices in a clean and structured way.&lt;/p&gt;

&lt;p&gt;It takes care of:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt; Authentication (Basic Auth)&lt;/li&gt;
&lt;li&gt; API communication&lt;/li&gt;
&lt;li&gt; XML parsing → Python dictionaries&lt;/li&gt;
&lt;li&gt; Response code mapping&lt;/li&gt;
&lt;li&gt; Argument validation&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So you can focus on your application instead of fighting the device API.&lt;/p&gt;




&lt;h2&gt;
  
  
  Installation
&lt;/h2&gt;

&lt;p&gt;You can install it directly from PyPI:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://pypi.org/project/pycosec/" rel="noopener noreferrer"&gt;https://pypi.org/project/pycosec/&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pip &lt;span class="nb"&gt;install &lt;/span&gt;pycosec
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Or explore the source code:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/KSreethul/pycosec" rel="noopener noreferrer"&gt;https://github.com/KSreethul/pycosec&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Real Usage (Based on Actual Implementation)
&lt;/h2&gt;

&lt;p&gt;Here’s a real example based on how the library actually works:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;pycosec&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;COSECBiometric&lt;/span&gt;

&lt;span class="c1"&gt;# Initialize device connection
&lt;/span&gt;&lt;span class="n"&gt;device&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;COSECBiometric&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;machine_ip&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;192.168.1.100&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;port&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;80&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;username&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;admin&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;password&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;admin123&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;#  Get basic device configuration
&lt;/span&gt;&lt;span class="n"&gt;basic_config&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;device&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;basic_config&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Device Config:&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;basic_config&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;


&lt;span class="c1"&gt;#  Fetch attendance events
&lt;/span&gt;&lt;span class="n"&gt;events&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;device&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get_attendance_events&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;roll_over_count&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;seq_num&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;no_of_events&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;50&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Attendance Events:&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;events&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;


&lt;span class="c1"&gt;#  Create or update a user
&lt;/span&gt;&lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;device&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;set_cosec_user&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;user_id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;EMP001&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;ref_user_id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;John Doe&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;user_active&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;user_group&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;User Response:&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;


&lt;span class="c1"&gt;#  Get user details
&lt;/span&gt;&lt;span class="n"&gt;user&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;device&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get_cosec_user&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;EMP001&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;User Details:&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;


&lt;span class="c1"&gt;#  Delete user
&lt;/span&gt;&lt;span class="n"&gt;delete_response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;device&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;delete_cosec_user&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;EMP001&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Delete Response:&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;delete_response&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Device Configuration Example
&lt;/h2&gt;

&lt;p&gt;You can also configure device settings easily:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# Set device date &amp;amp; time
&lt;/span&gt;&lt;span class="n"&gt;device&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;date_and_time_configuration&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;action&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;set&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;date_dd&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;21&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;date_mm&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;date_yyyy&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;2026&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;time_hh&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;15&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;time_mm&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;30&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;# Configure access settings
&lt;/span&gt;&lt;span class="n"&gt;device&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;access_settings_configuration&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;action&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;set&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;auto_relock&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;alarm&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  What’s Happening Behind the Scenes?
&lt;/h2&gt;

&lt;p&gt;This is where the library actually saves you a ton of effort:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Automatically builds correct API URLs&lt;/li&gt;
&lt;li&gt;Handles authentication headers (Base64 encoded)&lt;/li&gt;
&lt;li&gt;Converts XML → Python dictionaries&lt;/li&gt;
&lt;li&gt;Filters and parses attendance events&lt;/li&gt;
&lt;li&gt;Maps response codes to readable messages&lt;/li&gt;
&lt;li&gt;Validates supported arguments before sending requests&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Instead of writing all this logic repeatedly, you just call methods.&lt;/p&gt;




&lt;h2&gt;
  
  
  Real Use Case
&lt;/h2&gt;

&lt;p&gt;I built this while working on an HRMS system where:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Employees check in via biometric devices&lt;/li&gt;
&lt;li&gt;Attendance logs need to sync with the backend&lt;/li&gt;
&lt;li&gt;The system handles large volumes of data&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This library acts as a &lt;strong&gt;bridge between COSEC devices and your application&lt;/strong&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  Before vs After
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Before pycosec:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Manual API calls&lt;/li&gt;
&lt;li&gt;XML parsing everywhere&lt;/li&gt;
&lt;li&gt;Duplicate code in every project&lt;/li&gt;
&lt;li&gt;Hard debugging&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  After pycosec:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Clean Python methods &lt;/li&gt;
&lt;li&gt;Faster integration &lt;/li&gt;
&lt;li&gt;Reusable code &lt;/li&gt;
&lt;li&gt;Easier debugging &lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Future Improvements
&lt;/h2&gt;

&lt;p&gt;I’m actively working on improving the library. Some ideas:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Async support&lt;/li&gt;
&lt;li&gt;More endpoint wrappers&lt;/li&gt;
&lt;li&gt;Better error handling&lt;/li&gt;
&lt;li&gt;Webhook-based event sync&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Contributions Welcome
&lt;/h2&gt;

&lt;p&gt;If you’ve worked with COSEC devices, you know there’s always something new to figure out.&lt;/p&gt;

&lt;p&gt;Feel free to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Open issues&lt;/li&gt;
&lt;li&gt;Suggest improvements&lt;/li&gt;
&lt;li&gt;Contribute&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Let’s make biometric integrations easier for everyone.&lt;/p&gt;




&lt;h2&gt;
  
  
  Final Thoughts
&lt;/h2&gt;

&lt;p&gt;This library came out of a real problem I faced while building production systems.&lt;/p&gt;

&lt;p&gt;It’s not just a wrapper—it’s a way to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Reduce repetitive work&lt;/li&gt;
&lt;li&gt;Simplify integrations&lt;/li&gt;
&lt;li&gt;Build faster and cleaner systems&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you’re working with COSEC devices, this might save you hours (or even days).&lt;/p&gt;

</description>
      <category>api</category>
      <category>opensource</category>
      <category>python</category>
      <category>showdev</category>
    </item>
    <item>
      <title>How to Convert a Django App into a Pip-Installable Package</title>
      <dc:creator>Sreethul</dc:creator>
      <pubDate>Wed, 22 Oct 2025 11:43:34 +0000</pubDate>
      <link>https://dev.to/ksreethul/how-to-convert-a-django-app-into-a-pip-installable-package-5c2</link>
      <guid>https://dev.to/ksreethul/how-to-convert-a-django-app-into-a-pip-installable-package-5c2</guid>
      <description>&lt;p&gt;Sometimes you develop a reusable Django app in your project and want to share it across multiple projects—or even publicly via PyPI. Here’s a step-by-step guide on how to convert your Django app into a pip-installable package.&lt;/p&gt;




&lt;h2&gt;
  
  
  Step 1: Create a Dedicated Django App
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Inside your Django project, create a new app for your reusable functionality:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;python manage.py startapp your_app_name
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Do &lt;strong&gt;all your coding only inside this app&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Outside the app, only update &lt;code&gt;settings.py&lt;/code&gt; → &lt;code&gt;INSTALLED_APPS&lt;/code&gt; if needed.&lt;/li&gt;
&lt;li&gt;Keep the app self-contained so that it can work independently when installed in other projects.&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  Step 2: Prepare Your App for Packaging
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Once your app is ready, &lt;strong&gt;create a new folder outside your Django project&lt;/strong&gt; with the same name as your app:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;mkdir &lt;/span&gt;your_app_name
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Copy your Django app into this folder.&lt;/li&gt;
&lt;li&gt;Add the following files to the folder:&lt;/li&gt;
&lt;/ol&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;LICENSE&lt;/code&gt; – your license file&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;README.md&lt;/code&gt; – a brief description of your app&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;MANIFEST.in&lt;/code&gt; – to include non-Python files&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;setup.py&lt;/code&gt; – packaging script&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;pyproject.toml&lt;/code&gt; – build configuration&lt;/li&gt;
&lt;/ul&gt;




&lt;h3&gt;
  
  
  Example &lt;code&gt;setup.py&lt;/code&gt;
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;setuptools&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;setup&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;find_packages&lt;/span&gt;

&lt;span class="nf"&gt;setup&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;your_app_name&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;version&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;0.1.0&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;packages&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nf"&gt;find_packages&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
    &lt;span class="n"&gt;include_package_data&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;install_requires&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Django&amp;gt;=4.2&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;  &lt;span class="c1"&gt;# specify dependencies
&lt;/span&gt;    &lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="n"&gt;license&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;MIT&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;description&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;A reusable Django app&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;long_description&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nf"&gt;open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;README.md&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;read&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
    &lt;span class="n"&gt;long_description_content_type&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;text/markdown&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;https://github.com/yourusername/your_app_name&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Step 3: Build the Package
&lt;/h2&gt;

&lt;p&gt;Run the following command in your app folder:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;python &lt;span class="nt"&gt;-m&lt;/span&gt; build
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This will create a &lt;code&gt;dist/&lt;/code&gt; folder containing &lt;code&gt;.whl&lt;/code&gt; and &lt;code&gt;.tar.gz&lt;/code&gt; files.&lt;/p&gt;




&lt;h2&gt;
  
  
  Step 4: Install Locally
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Go back to your Django project.&lt;/li&gt;
&lt;li&gt;Remove the old app from your project.&lt;/li&gt;
&lt;li&gt;Install the package from the &lt;code&gt;dist&lt;/code&gt; folder:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pip &lt;span class="nb"&gt;install&lt;/span&gt; ../your_app_name/dist/your_app_name-0.1.0-py3-none-any.whl
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;4.Now your app is installed into your virtual environment and can be used like any other installed package.&lt;/p&gt;




&lt;h2&gt;
  
  
  Step 5: Publish to PyPI
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Go back to your django app standalone folder,Same folder that you run python -m build.&lt;/li&gt;
&lt;li&gt;Upload to PyPI using Twine:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;python &lt;span class="nt"&gt;-m&lt;/span&gt; twine upload dist/&lt;span class="k"&gt;*&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;It will prompt for your &lt;strong&gt;PyPI API token&lt;/strong&gt;. Generate one from your PyPI account.&lt;/li&gt;
&lt;li&gt;After a successful upload, your app is publicly available! Anyone can install it with:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pip &lt;span class="nb"&gt;install &lt;/span&gt;your_app_name
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;ul&gt;
&lt;li&gt;Build and test locally before uploading to PyPI.&lt;/li&gt;
&lt;li&gt;After publishing, your app can be reused across projects or shared with the community.&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>django</category>
      <category>python</category>
      <category>programming</category>
      <category>coding</category>
    </item>
  </channel>
</rss>
