<?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: Saleh Azimidokht</title>
    <description>The latest articles on DEV Community by Saleh Azimidokht (@cyberhuginn).</description>
    <link>https://dev.to/cyberhuginn</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.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3409751%2Fdcee882c-84e5-44eb-ad1d-a3037b029a45.png</url>
      <title>DEV Community: Saleh Azimidokht</title>
      <link>https://dev.to/cyberhuginn</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/cyberhuginn"/>
    <language>en</language>
    <item>
      <title>The Hidden Cost of Django REST Framework Serializers</title>
      <dc:creator>Saleh Azimidokht</dc:creator>
      <pubDate>Mon, 07 Sep 2026 08:21:04 +0000</pubDate>
      <link>https://dev.to/cyberhuginn/the-hidden-cost-of-django-rest-framework-serializers-1d0c</link>
      <guid>https://dev.to/cyberhuginn/the-hidden-cost-of-django-rest-framework-serializers-1d0c</guid>
      <description>&lt;p&gt;Your Django REST Framework API can have fast database queries and still be slow.&lt;/p&gt;

&lt;p&gt;That's one of the most confusing performance problems in Django applications.&lt;/p&gt;

&lt;p&gt;You check PostgreSQL.&lt;/p&gt;

&lt;p&gt;The queries look fast.&lt;/p&gt;

&lt;p&gt;You optimize your views.&lt;/p&gt;

&lt;p&gt;Everything seems fine.&lt;/p&gt;

&lt;p&gt;But the endpoint is still taking hundreds of milliseconds—or even seconds.&lt;/p&gt;

&lt;p&gt;One place developers often forget to investigate is the &lt;strong&gt;Django REST Framework serializer&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;A serializer is not always just converting Python objects into JSON.&lt;/p&gt;

&lt;p&gt;It can trigger database queries, access relationships, execute Python code, calculate fields, and recursively serialize nested objects.&lt;/p&gt;

&lt;p&gt;And that's where things can get expensive.&lt;/p&gt;

&lt;h2&gt;
  
  
  The N+1 Query Problem Hiding Inside a Serializer
&lt;/h2&gt;

&lt;p&gt;Consider a simple serializer:&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;VehicleSerializer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;serializers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ModelSerializer&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;customer_name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;serializers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;SerializerMethodField&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Meta&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;model&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Vehicle&lt;/span&gt;
        &lt;span class="n"&gt;fields&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;id&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;plate_number&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;customer_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;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;get_customer_name&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;obj&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;obj&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;customer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Looks perfectly reasonable.&lt;/p&gt;

&lt;p&gt;But where does &lt;code&gt;obj.customer&lt;/code&gt; come from?&lt;/p&gt;

&lt;p&gt;If the &lt;code&gt;customer&lt;/code&gt; relationship hasn't been loaded, Django may execute another SQL query.&lt;/p&gt;

&lt;p&gt;With 100 vehicles, you could end up with:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;1 query   → fetch vehicles
100 queries → fetch customers

Total: 101 queries
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That's the classic &lt;strong&gt;N+1 query problem&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;And the dangerous part is that the serializer itself doesn't look like a database operation.&lt;/p&gt;

&lt;h2&gt;
  
  
  SerializerMethodField Is Not Free
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;SerializerMethodField&lt;/code&gt; is one of my favorite DRF features.&lt;/p&gt;

&lt;p&gt;It's also one of the easiest ways to accidentally create expensive APIs.&lt;/p&gt;

&lt;p&gt;Consider:&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;ServiceSerializer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;serializers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ModelSerializer&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;last_service&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;serializers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;SerializerMethodField&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;get_last_service&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;obj&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="nf"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="n"&gt;Service&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;objects&lt;/span&gt;
            &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;filter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ownership&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;obj&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ownership&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;order_by&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;-created_at&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;first&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 performs a database query every time &lt;code&gt;get_last_service()&lt;/code&gt; is called.&lt;/p&gt;

&lt;p&gt;Serialize 500 services?&lt;/p&gt;

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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;1 main query
+
500 additional queries
=
501 queries
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The code is readable.&lt;/p&gt;

&lt;p&gt;The API is correct.&lt;/p&gt;

&lt;p&gt;And yet the performance can be terrible.&lt;/p&gt;

&lt;p&gt;This is why &lt;strong&gt;correct code isn't necessarily efficient code&lt;/strong&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Fix Usually Isn't Inside the Serializer
&lt;/h2&gt;

&lt;p&gt;One of the most important lessons I've learned when optimizing Django APIs is this:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;The serializer should not be responsible for discovering data that the database could have prepared.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Instead of querying for every object, move the work into the QuerySet.&lt;/p&gt;

&lt;p&gt;For example, you can use &lt;code&gt;Subquery&lt;/code&gt;:&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;django.db.models&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;OuterRef&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Subquery&lt;/span&gt;

&lt;span class="n"&gt;last_service&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Service&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;objects&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;filter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;ownership&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nc"&gt;OuterRef&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;ownership&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;order_by&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;-created_at&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;queryset&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Vehicle&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;objects&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;annotate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;last_service_id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nc"&gt;Subquery&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;last_service&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;values&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;id&lt;/span&gt;&lt;span class="sh"&gt;"&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="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 database prepares the information as part of the main query.&lt;/p&gt;

&lt;p&gt;Your serializer becomes simpler:&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;VehicleSerializer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;serializers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ModelSerializer&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;last_service_id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;serializers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;IntegerField&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;read_only&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="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Meta&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;model&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Vehicle&lt;/span&gt;
        &lt;span class="n"&gt;fields&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;id&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;plate_number&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;last_service_id&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;The architecture becomes:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Database
    ↓
Optimized QuerySet
    ↓
Annotations
    ↓
Serializer
    ↓
JSON
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Database
    ↓
Serializer
    ↓
"Let's query something"
    ↓
Another query
    ↓
Another query
    ↓
Another query
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  select_related() vs prefetch_related()
&lt;/h2&gt;

&lt;p&gt;When working with Django REST Framework serializers, you should always pay attention to the relationships being accessed.&lt;/p&gt;

&lt;p&gt;For single-valued relationships:&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;ForeignKey&lt;/span&gt;
&lt;span class="n"&gt;OneToOneField&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;use:&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="nf"&gt;select_related&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For 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="n"&gt;vehicles&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Vehicle&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;objects&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;select_related&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;customer&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;Now Django can retrieve the vehicle and customer using a SQL JOIN.&lt;/p&gt;

&lt;p&gt;For collections such as:&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;ManyToManyField&lt;/span&gt;
&lt;span class="n"&gt;Reverse&lt;/span&gt; &lt;span class="n"&gt;ForeignKey&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;use:&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="nf"&gt;prefetch_related&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For 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="n"&gt;services&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;Service&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;objects&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;prefetch_related&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;products&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;A simple rule to remember:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ForeignKey / OneToOne
        ↓
select_related()

ManyToMany / Reverse FK
        ↓
prefetch_related()
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;These two methods are some of the most important tools for preventing N+1 queries in Django APIs. (&lt;a href="https://dev.to/highcenburg/how-i-caught-and-fixed-an-n1-query-in-my-django-rest-api-36p5?utm_source=chatgpt.com"&gt;DEV Community&lt;/a&gt;)&lt;/p&gt;

&lt;h2&gt;
  
  
  Nested Serializers Make Things Worse
&lt;/h2&gt;

&lt;p&gt;Nested serializers are convenient.&lt;/p&gt;

&lt;p&gt;But convenience can hide expensive database access.&lt;/p&gt;

&lt;p&gt;Imagine:&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;ProductSerializer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;serializers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ModelSerializer&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Meta&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;model&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Product&lt;/span&gt;
        &lt;span class="n"&gt;fields&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;id&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;name&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;


&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ServiceSerializer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;serializers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ModelSerializer&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;products&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;ProductSerializer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;many&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="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Meta&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;model&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Service&lt;/span&gt;
        &lt;span class="n"&gt;fields&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;id&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;products&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 imagine your API returns 1,000 services.&lt;/p&gt;

&lt;p&gt;Every service needs its products.&lt;/p&gt;

&lt;p&gt;Without prefetching, your API can start generating queries like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Service query
Product query
Product query
Product query
...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And nested relationships can go even deeper:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Service
 ├── Customer
 │    └── Address
 └── Products
      └── Category
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A response that looks innocent in JSON can represent a surprisingly expensive data-access pattern.&lt;/p&gt;

&lt;h2&gt;
  
  
  Don't Build One Giant Serializer
&lt;/h2&gt;

&lt;p&gt;Another common mistake is trying to use one serializer for everything.&lt;/p&gt;

&lt;p&gt;For example:&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;



&lt;p&gt;gets used for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;List endpoints&lt;/li&gt;
&lt;li&gt;Detail endpoints&lt;/li&gt;
&lt;li&gt;Create endpoints&lt;/li&gt;
&lt;li&gt;Update endpoints&lt;/li&gt;
&lt;li&gt;Admin endpoints&lt;/li&gt;
&lt;li&gt;Search endpoints&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Eventually, the serializer becomes huge.&lt;/p&gt;

&lt;p&gt;A list endpoint might only need:&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;VehicleListSerializer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;serializers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ModelSerializer&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Meta&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;model&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Vehicle&lt;/span&gt;
        &lt;span class="n"&gt;fields&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;id&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;plate_number&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;color&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;While a detail endpoint can provide more information:&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;VehicleDetailSerializer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;serializers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ModelSerializer&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;customer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;CustomerSerializer&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Meta&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;model&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Vehicle&lt;/span&gt;
        &lt;span class="n"&gt;fields&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;id&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;plate_number&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;color&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;customer&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 isn't unnecessary duplication.&lt;/p&gt;

&lt;p&gt;It's API design.&lt;/p&gt;

&lt;p&gt;A list endpoint shouldn't return an entire object graph just because the detail endpoint needs it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Smaller Responses Are Usually Better
&lt;/h2&gt;

&lt;p&gt;More data isn't always better.&lt;/p&gt;

&lt;p&gt;Consider an API response containing:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Customer
 ├── Vehicles
 ├── Services
 ├── Invoices
 ├── Payments
 ├── Addresses
 └── Orders
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It might look impressive.&lt;/p&gt;

&lt;p&gt;But every additional relationship can increase:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Database work&lt;/li&gt;
&lt;li&gt;Serialization time&lt;/li&gt;
&lt;li&gt;Response size&lt;/li&gt;
&lt;li&gt;Memory usage&lt;/li&gt;
&lt;li&gt;Network transfer&lt;/li&gt;
&lt;li&gt;Frontend processing&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The API should return the data the client needs—not everything the database knows.&lt;/p&gt;

&lt;h2&gt;
  
  
  Measure Before Optimizing
&lt;/h2&gt;

&lt;p&gt;This is probably the most important rule.&lt;/p&gt;

&lt;p&gt;Don't look at a serializer and say:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"This probably causes performance problems."&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Measure it.&lt;/p&gt;

&lt;p&gt;For Django APIs, useful things to measure include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;SQL query count&lt;/li&gt;
&lt;li&gt;SQL query duration&lt;/li&gt;
&lt;li&gt;Serializer execution time&lt;/li&gt;
&lt;li&gt;Total request duration&lt;/li&gt;
&lt;li&gt;Response size&lt;/li&gt;
&lt;li&gt;CPU usage&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Tools such as Django Debug Toolbar, Django Silk, and APM platforms can help you find where the time is actually going.&lt;/p&gt;

&lt;p&gt;Because sometimes the database isn't the bottleneck.&lt;/p&gt;

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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Database:       40 ms
View logic:     30 ms
Serialization: 650 ms
JSON rendering: 80 ms

Total:          800 ms
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Optimizing a 40 ms database query isn't going to solve your 800 ms API response.&lt;/p&gt;

&lt;p&gt;Profile the entire request.&lt;/p&gt;

&lt;h2&gt;
  
  
  A Simple DRF Performance Checklist
&lt;/h2&gt;

&lt;p&gt;When a Django REST Framework endpoint becomes slow, I usually start here:&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Count the queries
&lt;/h3&gt;

&lt;p&gt;How many SQL queries does the endpoint execute?&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Inspect SerializerMethodField
&lt;/h3&gt;

&lt;p&gt;Look for database access inside:&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;get_&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;field_name&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  3. Inspect relationship access
&lt;/h3&gt;

&lt;p&gt;Look for:&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;obj&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;customer&lt;/span&gt;
&lt;span class="n"&gt;obj&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;owner&lt;/span&gt;
&lt;span class="n"&gt;obj&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;category&lt;/span&gt;
&lt;span class="n"&gt;obj&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;products&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;all&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  4. Check select_related()
&lt;/h3&gt;

&lt;p&gt;Are your &lt;code&gt;ForeignKey&lt;/code&gt; and &lt;code&gt;OneToOneField&lt;/code&gt; relationships loaded efficiently?&lt;/p&gt;

&lt;h3&gt;
  
  
  5. Check prefetch_related()
&lt;/h3&gt;

&lt;p&gt;Are your &lt;code&gt;ManyToMany&lt;/code&gt; and reverse relationships prefetched?&lt;/p&gt;

&lt;h3&gt;
  
  
  6. Look at annotations
&lt;/h3&gt;

&lt;p&gt;Can a calculation be performed by the database instead of repeatedly inside Python?&lt;/p&gt;

&lt;h3&gt;
  
  
  7. Reduce nested data
&lt;/h3&gt;

&lt;p&gt;Does the frontend actually need all those nested objects?&lt;/p&gt;

&lt;h3&gt;
  
  
  8. Separate serializers
&lt;/h3&gt;

&lt;p&gt;Does the list endpoint really need the same serializer as the detail endpoint?&lt;/p&gt;

&lt;h3&gt;
  
  
  9. Measure again
&lt;/h3&gt;

&lt;p&gt;Never assume the optimization worked.&lt;/p&gt;

&lt;p&gt;Measure before and after.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Real Cost of a Serializer
&lt;/h2&gt;

&lt;p&gt;Django REST Framework serializers aren't inherently slow.&lt;/p&gt;

&lt;p&gt;The problem is what we ask them to do.&lt;/p&gt;

&lt;p&gt;A serializer becomes expensive when it:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Executes database queries repeatedly&lt;/li&gt;
&lt;li&gt;Accesses unloaded relationships&lt;/li&gt;
&lt;li&gt;Performs expensive Python calculations&lt;/li&gt;
&lt;li&gt;Uses deeply nested serializers&lt;/li&gt;
&lt;li&gt;Returns unnecessary data&lt;/li&gt;
&lt;li&gt;Hides database access inside &lt;code&gt;SerializerMethodField&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The best optimization is often not changing the serializer.&lt;/p&gt;

&lt;p&gt;It's changing the &lt;strong&gt;QuerySet behind it&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Think about your API like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Request
   ↓
View
   ↓
Optimized QuerySet
   ↓
Database
   ↓
Serializer
   ↓
Minimal JSON Response
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Request
   ↓
View
   ↓
Huge QuerySet
   ↓
Serializer
   ↓
Query
   ↓
Query
   ↓
Query
   ↓
N+1
   ↓
Slow API
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Final Thought
&lt;/h2&gt;

&lt;p&gt;The next time you see a slow Django REST Framework endpoint, don't only inspect the SQL.&lt;/p&gt;

&lt;p&gt;Inspect what happens &lt;strong&gt;after the QuerySet is evaluated&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Your database query might be fast.&lt;/p&gt;

&lt;p&gt;Your serializer might be the expensive part.&lt;/p&gt;

&lt;p&gt;And that hidden cost becomes much more visible as your dataset grows.&lt;/p&gt;

&lt;p&gt;I wrote a deeper technical breakdown with more examples, optimization strategies, &lt;code&gt;select_related()&lt;/code&gt;, &lt;code&gt;prefetch_related()&lt;/code&gt;, annotations, nested serializers, and practical debugging techniques:&lt;/p&gt;

&lt;p&gt;👉 &lt;strong&gt;&lt;a href="https://cyberhuginn.com/notes/the-hidden-cost-of-django-rest-framework-serializers" rel="noopener noreferrer"&gt;The Hidden Cost of Django REST Framework Serializers&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;If you're building production Django APIs, understanding the relationship between &lt;strong&gt;QuerySets, serializers, and database queries&lt;/strong&gt; can make a huge difference.&lt;/p&gt;




&lt;h1&gt;
  
  
  django #python #djangorestframework #drf #backend #api #webdevelopment #performance #database #programming
&lt;/h1&gt;

</description>
      <category>python</category>
      <category>django</category>
      <category>drf</category>
      <category>performance</category>
    </item>
    <item>
      <title>I Built a Signed Webhook Receiver for Cross-Server Communication</title>
      <dc:creator>Saleh Azimidokht</dc:creator>
      <pubDate>Tue, 11 Aug 2026 12:05:48 +0000</pubDate>
      <link>https://dev.to/cyberhuginn/building-a-secure-webhook-receiver-for-server-to-server-communication-23d7</link>
      <guid>https://dev.to/cyberhuginn/building-a-secure-webhook-receiver-for-server-to-server-communication-23d7</guid>
      <description>&lt;p&gt;Sometimes your application can reach an external service from one server, but not from another.&lt;/p&gt;

&lt;p&gt;I ran into this problem while working on one of my projects. I needed my server in Iran to communicate with Telegram, but the connection wasn't reliable from inside Iran.&lt;/p&gt;

&lt;p&gt;Instead of moving the whole application, I built a small intermediate service:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Signed Webhook Receiver&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;It is a lightweight &lt;strong&gt;FastAPI&lt;/strong&gt; service that receives requests signed with an RSA private key and verifies them using the corresponding public key before processing them.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Your Server
     |
     | RSA Signed Request
     v
Webhook Receiver
     |
     | HTTP Request
     v
External Service
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The receiver can be useful for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Secure server-to-server communication&lt;/li&gt;
&lt;li&gt;Webhooks and internal APIs&lt;/li&gt;
&lt;li&gt;Acting as a controlled proxy/gateway&lt;/li&gt;
&lt;li&gt;Connecting servers across different network environments&lt;/li&gt;
&lt;li&gt;Payment integrations where a provider requires requests from an Iranian IP&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For example, if your main application is hosted outside Iran but a payment gateway only accepts requests from Iranian IP addresses, an Iranian server can act as the intermediate gateway:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Foreign Server
      |
      | Signed Request
      v
Iranian Gateway Server
      |
      v
Payment Gateway
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The important part is that this isn't an open proxy. Requests can be authenticated and the gateway can be restricted to specific operations and destinations.&lt;/p&gt;

&lt;p&gt;The project is built with &lt;strong&gt;Python, FastAPI, Cryptography, Docker, and Traefik&lt;/strong&gt; and is open source.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/cyberhuginn/signed-webhook-receiver" rel="noopener noreferrer"&gt;View the project on GitHub&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I also wrote more technical notes and development articles on my website:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://cyberhuginn.com/notes/building-secure-webhook-receiver-server-to-server-communication" rel="noopener noreferrer"&gt;Building a Secure Webhook Receiver for Server-to-Server Communication | CyberHuginn&lt;/a&gt;&lt;/p&gt;

</description>
      <category>python</category>
      <category>fastapi</category>
      <category>webhooks</category>
      <category>security</category>
    </item>
    <item>
      <title>Designing a Gold Jewelry E-Commerce Database with Django</title>
      <dc:creator>Saleh Azimidokht</dc:creator>
      <pubDate>Tue, 04 Aug 2026 05:04:51 +0000</pubDate>
      <link>https://dev.to/cyberhuginn/designing-a-gold-jewelry-e-commerce-database-with-django-16lc</link>
      <guid>https://dev.to/cyberhuginn/designing-a-gold-jewelry-e-commerce-database-with-django-16lc</guid>
      <description>&lt;p&gt;When I accepted a project to build an online gold jewelry store, I thought it would be just another e-commerce platform.&lt;/p&gt;

&lt;p&gt;Products. Orders. Payments.&lt;/p&gt;

&lt;p&gt;Nothing unusual.&lt;/p&gt;

&lt;p&gt;I couldn't have been more wrong.&lt;/p&gt;

&lt;p&gt;A few hours into the database design, I realized the real challenge wasn't Django—it was understanding the business.&lt;/p&gt;

&lt;p&gt;Unlike a regular online store, customers aren't buying a generic product. They're buying a very specific variation of that product.&lt;/p&gt;

&lt;p&gt;A single ring, for example, can exist in multiple versions:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Different weights&lt;/li&gt;
&lt;li&gt;Different karats&lt;/li&gt;
&lt;li&gt;Different sizes&lt;/li&gt;
&lt;li&gt;Different gemstones&lt;/li&gt;
&lt;li&gt;Different making fees&lt;/li&gt;
&lt;li&gt;Different prices&lt;/li&gt;
&lt;li&gt;Different inventory&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That simple observation completely changes how your database should be designed.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Common Mistake
&lt;/h2&gt;

&lt;p&gt;Many developers model their orders like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Order
 └── Product
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That works perfectly for books, digital products, or simple inventory.&lt;/p&gt;

&lt;p&gt;It completely falls apart for jewelry.&lt;/p&gt;

&lt;p&gt;Because the customer isn't purchasing the &lt;strong&gt;Product&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;They're purchasing one specific &lt;strong&gt;variation&lt;/strong&gt; of that product.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Missing Model
&lt;/h2&gt;

&lt;p&gt;Instead of attaching orders directly to &lt;code&gt;Product&lt;/code&gt;, I introduced another layer:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Product
    └── ProductVariable
            ├── Price
            ├── Stock
            ├── Making Fee
            ├── Weight
            ├── Karat
            └── Attributes
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now every purchasable item has its own inventory, pricing, and specifications while still belonging to the same parent product.&lt;/p&gt;

&lt;p&gt;This approach also makes searching and filtering much easier because attributes become reusable across multiple products.&lt;/p&gt;

&lt;h2&gt;
  
  
  Start From Business Scenarios
&lt;/h2&gt;

&lt;p&gt;Before writing models, I always walk through real business scenarios.&lt;/p&gt;

&lt;p&gt;Questions like:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;What exactly is the customer buying?&lt;/li&gt;
&lt;li&gt;Can inventory differ between variations?&lt;/li&gt;
&lt;li&gt;Can price change based on weight?&lt;/li&gt;
&lt;li&gt;What happens when an item is out of stock?&lt;/li&gt;
&lt;li&gt;Can customers order custom-made jewelry?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Those questions usually define your entities long before you write your first Django model.&lt;/p&gt;




&lt;p&gt;This article only scratches the surface.&lt;/p&gt;

&lt;p&gt;In the full version, I explain:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;How to identify entities using Use Cases&lt;/li&gt;
&lt;li&gt;Building an ER Diagram&lt;/li&gt;
&lt;li&gt;Designing Django models&lt;/li&gt;
&lt;li&gt;Modeling &lt;code&gt;ProductVariable&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Categories vs Tags&lt;/li&gt;
&lt;li&gt;Product Attributes&lt;/li&gt;
&lt;li&gt;Inventory management&lt;/li&gt;
&lt;li&gt;Ordering and payment architecture&lt;/li&gt;
&lt;li&gt;Real-world jewelry business scenarios&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;👉 &lt;strong&gt;Read the complete article here:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;a href="https://cyberhuginn.com/notes/designing-a-gold-jewelry-ecommerce-database-with-django" rel="noopener noreferrer"&gt;https://cyberhuginn.com/notes/designing-a-gold-jewelry-ecommerce-database-with-django&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;If you're building an e-commerce platform with Django, especially one that sells configurable products, this design pattern can save you from painful database refactoring later.&lt;/p&gt;

</description>
      <category>django</category>
      <category>database</category>
      <category>ecommerce</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Why Every Small SaaS Needs Uptime Monitoring</title>
      <dc:creator>Saleh Azimidokht</dc:creator>
      <pubDate>Sat, 01 Aug 2026 17:34:22 +0000</pubDate>
      <link>https://dev.to/cyberhuginn/why-every-small-saas-needs-uptime-monitoring-387j</link>
      <guid>https://dev.to/cyberhuginn/why-every-small-saas-needs-uptime-monitoring-387j</guid>
      <description>&lt;p&gt;Building software has never been easier.&lt;/p&gt;

&lt;p&gt;Keeping it online is the hard part.&lt;/p&gt;

&lt;p&gt;Whether you're running a personal project, an internal API, a startup MVP, or a growing SaaS business, downtime can quickly become expensive. Users lose trust, support requests increase, and revenue disappears while you're unaware that something has gone wrong.&lt;/p&gt;

&lt;p&gt;The worst part?&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Most outages aren't discovered by monitoring systems.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;They're discovered by users.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;That realization is exactly what led me to build &lt;strong&gt;Bidar&lt;/strong&gt;—a lightweight uptime monitoring platform focused on one simple goal:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Notify developers as soon as their services become unavailable.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  The Hidden Cost of Downtime
&lt;/h2&gt;

&lt;p&gt;It's easy to think of downtime as "just a server issue."&lt;/p&gt;

&lt;p&gt;In reality, the impact is much broader.&lt;/p&gt;

&lt;p&gt;Even a short outage can affect:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;User trust&lt;/li&gt;
&lt;li&gt;Customer satisfaction&lt;/li&gt;
&lt;li&gt;Conversion rates&lt;/li&gt;
&lt;li&gt;Search rankings&lt;/li&gt;
&lt;li&gt;Team productivity&lt;/li&gt;
&lt;li&gt;Brand reputation&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Your users don't care whether the issue was caused by a failed deployment, DNS problem, database outage, or cloud provider incident.&lt;/p&gt;

&lt;p&gt;They only know one thing:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Your service wasn't available when they needed it.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  Why Manual Monitoring Doesn't Scale
&lt;/h2&gt;

&lt;p&gt;In the beginning, many developers rely on manual checks.&lt;/p&gt;

&lt;p&gt;They refresh the website.&lt;/p&gt;

&lt;p&gt;They test an API endpoint.&lt;/p&gt;

&lt;p&gt;They occasionally check server metrics.&lt;/p&gt;

&lt;p&gt;That works for hobby projects.&lt;/p&gt;

&lt;p&gt;It stops working when real users depend on your application.&lt;/p&gt;

&lt;p&gt;You can't monitor your services 24 hours a day.&lt;/p&gt;

&lt;p&gt;You can't wake up every hour to verify your API is still responding.&lt;/p&gt;

&lt;p&gt;Automation eventually becomes a necessity.&lt;/p&gt;




&lt;h2&gt;
  
  
  What Should You Monitor?
&lt;/h2&gt;

&lt;p&gt;A good monitoring solution should cover more than just your homepage.&lt;/p&gt;

&lt;p&gt;Some of the most valuable things to monitor include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Website availability&lt;/li&gt;
&lt;li&gt;REST API endpoints&lt;/li&gt;
&lt;li&gt;SSL certificate expiration&lt;/li&gt;
&lt;li&gt;Response time&lt;/li&gt;
&lt;li&gt;HTTP status codes&lt;/li&gt;
&lt;li&gt;Critical customer-facing pages&lt;/li&gt;
&lt;li&gt;Internal services&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Monitoring the right endpoints allows you to detect problems before your customers notice them.&lt;/p&gt;




&lt;h2&gt;
  
  
  What Makes a Good Monitoring Tool?
&lt;/h2&gt;

&lt;p&gt;After working on several backend systems, I've found that a monitoring solution doesn't need hundreds of features.&lt;/p&gt;

&lt;p&gt;It needs to do a few things really well.&lt;/p&gt;

&lt;h3&gt;
  
  
  Fast Detection
&lt;/h3&gt;

&lt;p&gt;The sooner you're notified, the sooner you can fix the issue.&lt;/p&gt;

&lt;h3&gt;
  
  
  Reliable Alerts
&lt;/h3&gt;

&lt;p&gt;Notifications should arrive immediately through the channels you actually use.&lt;/p&gt;

&lt;h3&gt;
  
  
  Easy Setup
&lt;/h3&gt;

&lt;p&gt;Monitoring should take minutes—not hours.&lt;/p&gt;

&lt;h3&gt;
  
  
  Clear Results
&lt;/h3&gt;

&lt;p&gt;The goal isn't generating pretty dashboards.&lt;/p&gt;

&lt;p&gt;The goal is answering one question:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Is my service healthy?&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;




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

&lt;p&gt;While working on Django projects and APIs, I wanted a monitoring service that focused on uptime instead of trying to be a complete observability platform.&lt;/p&gt;

&lt;p&gt;Many existing tools are incredibly powerful.&lt;/p&gt;

&lt;p&gt;They also come with dozens of dashboards, metrics, traces, and features that smaller teams often don't need.&lt;/p&gt;

&lt;p&gt;So I built &lt;strong&gt;Bidar&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Its philosophy is simple:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Add your website or API.&lt;/li&gt;
&lt;li&gt;Configure monitoring.&lt;/li&gt;
&lt;li&gt;Get notified when something goes wrong.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;That's it.&lt;/p&gt;

&lt;p&gt;No unnecessary complexity.&lt;/p&gt;

&lt;p&gt;Just reliable uptime monitoring.&lt;/p&gt;




&lt;h2&gt;
  
  
  Who Is It For?
&lt;/h2&gt;

&lt;p&gt;Bidar is especially useful for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Indie Hackers&lt;/li&gt;
&lt;li&gt;SaaS founders&lt;/li&gt;
&lt;li&gt;Freelancers managing client websites&lt;/li&gt;
&lt;li&gt;Small development teams&lt;/li&gt;
&lt;li&gt;Backend developers&lt;/li&gt;
&lt;li&gt;Anyone running production APIs&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If uptime matters to your users, monitoring should matter to you.&lt;/p&gt;




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

&lt;p&gt;Reliable software isn't just about writing good code.&lt;/p&gt;

&lt;p&gt;It's also about knowing when things stop working.&lt;/p&gt;

&lt;p&gt;Monitoring helps you detect issues faster, reduce downtime, and respond before your users start sending emails asking if your service is down.&lt;/p&gt;

&lt;p&gt;If you're looking for a lightweight uptime monitoring platform, I'd love for you to check out &lt;strong&gt;Bidar&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;🌐 &lt;strong&gt;Website:&lt;/strong&gt; &lt;a href="https://bidarhq.ir" rel="noopener noreferrer"&gt;https://bidarhq.ir&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I'm always looking for feedback from developers.&lt;/p&gt;

&lt;p&gt;If there's a feature you'd like to see, let me know!&lt;/p&gt;




&lt;h2&gt;
  
  
  About the Author
&lt;/h2&gt;

&lt;p&gt;I'm a backend developer focused on Django, distributed systems, developer tools, and open-source software.&lt;/p&gt;

&lt;p&gt;Website: &lt;a href="https://cyberhuginn.com" rel="noopener noreferrer"&gt;https://cyberhuginn.com&lt;/a&gt;&lt;/p&gt;

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

</description>
      <category>django</category>
      <category>python</category>
      <category>saas</category>
      <category>devops</category>
    </item>
    <item>
      <title>I Built a Lightweight Health Check Package for Django</title>
      <dc:creator>Saleh Azimidokht</dc:creator>
      <pubDate>Sat, 01 Aug 2026 17:30:06 +0000</pubDate>
      <link>https://dev.to/cyberhuginn/i-built-a-lightweight-health-check-package-for-django-1nj7</link>
      <guid>https://dev.to/cyberhuginn/i-built-a-lightweight-health-check-package-for-django-1nj7</guid>
      <description>&lt;p&gt;While working on several Django projects, I often needed a simple endpoint to verify that the application was actually healthy—not just running.&lt;/p&gt;

&lt;p&gt;Most existing solutions were either too heavy, required extra configuration, or didn’t provide the flexibility I wanted.&lt;/p&gt;

&lt;p&gt;So I built &lt;strong&gt;django-healthkit&lt;/strong&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  What it does
&lt;/h2&gt;

&lt;p&gt;The package lets you expose a health endpoint that can verify different parts of your application.&lt;/p&gt;

&lt;p&gt;Current checks include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Database connectivity&lt;/li&gt;
&lt;li&gt;Cache availability&lt;/li&gt;
&lt;li&gt;Disk usage&lt;/li&gt;
&lt;li&gt;Memory usage&lt;/li&gt;
&lt;li&gt;CPU usage&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Configuration is intentionally simple:&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;HEALTH_CHECKS&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;database&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;cache&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;disk&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;memory&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;cpu&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;Then expose the endpoint and you're ready to use it with:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Docker health checks&lt;/li&gt;
&lt;li&gt;Kubernetes probes&lt;/li&gt;
&lt;li&gt;Traefik&lt;/li&gt;
&lt;li&gt;Nginx&lt;/li&gt;
&lt;li&gt;Monitoring systems&lt;/li&gt;
&lt;li&gt;Uptime monitoring services&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Why I built it
&lt;/h2&gt;

&lt;p&gt;My goal wasn't to create another monitoring platform.&lt;/p&gt;

&lt;p&gt;I wanted a small package that answers one simple question:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Is my Django application actually healthy?&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;No dashboards.&lt;/p&gt;

&lt;p&gt;No unnecessary dependencies.&lt;/p&gt;

&lt;p&gt;Just a clean JSON response that can be consumed by automation.&lt;/p&gt;

&lt;h2&gt;
  
  
  What's next?
&lt;/h2&gt;

&lt;p&gt;This is only the first release.&lt;/p&gt;

&lt;p&gt;Some ideas planned for future versions:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Custom health checks&lt;/li&gt;
&lt;li&gt;Async support&lt;/li&gt;
&lt;li&gt;Response customization&lt;/li&gt;
&lt;li&gt;More built-in system checks&lt;/li&gt;
&lt;li&gt;Better integrations with monitoring tools&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  I'd love your feedback
&lt;/h2&gt;

&lt;p&gt;If you're using Django, I'd really appreciate your thoughts.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;What health checks are missing?&lt;/li&gt;
&lt;li&gt;What features would make this useful in production?&lt;/li&gt;
&lt;li&gt;Any ideas for improving the API?&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Links
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;GitHub: &lt;a href="https://github.com/cyberhuginn/django-healthkit" rel="noopener noreferrer"&gt;https://github.com/cyberhuginn/django-healthkit&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;PyPI: &lt;a href="https://pypi.org/project/django-healthkit/" rel="noopener noreferrer"&gt;https://pypi.org/project/django-healthkit/&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Feedback and contributions are always welcome.&lt;/p&gt;




&lt;h2&gt;
  
  
  About the author
&lt;/h2&gt;

&lt;p&gt;I'm a backend developer focused on Django, distributed systems, developer tools, and open-source software.&lt;/p&gt;

&lt;p&gt;Website: &lt;a href="https://cyberhuginn.com" rel="noopener noreferrer"&gt;https://cyberhuginn.com&lt;/a&gt;&lt;/p&gt;

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

</description>
      <category>django</category>
      <category>python</category>
      <category>opensource</category>
      <category>webdev</category>
    </item>
  </channel>
</rss>
