<?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: Michael Nyawade</title>
    <description>The latest articles on DEV Community by Michael Nyawade (@mnyawade).</description>
    <link>https://dev.to/mnyawade</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%2F3839529%2Fb336d897-0a7d-4a18-84b5-124af989e837.png</url>
      <title>DEV Community: Michael Nyawade</title>
      <link>https://dev.to/mnyawade</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/mnyawade"/>
    <language>en</language>
    <item>
      <title>I Thought My Machine Learning Project Was Finished. Then I Asked One Question.</title>
      <dc:creator>Michael Nyawade</dc:creator>
      <pubDate>Mon, 13 Jul 2026 14:15:28 +0000</pubDate>
      <link>https://dev.to/mnyawade/i-thought-my-machine-learning-project-was-finished-then-i-asked-one-question-496o</link>
      <guid>https://dev.to/mnyawade/i-thought-my-machine-learning-project-was-finished-then-i-asked-one-question-496o</guid>
      <description>&lt;p&gt;When I completed my &lt;a href="https://github.com/Michael-Nyawade/customer-segmentation-rfm" rel="noopener noreferrer"&gt;customer segmentation project&lt;/a&gt;, I felt proud of what I had built.&lt;/p&gt;

&lt;p&gt;I had worked with nearly half a million retail transactions from the UCI Online Retail dataset. After cleaning the data, I engineered Recency, Frequency, and Monetary (RFM) features, applied K-Means clustering, experimented with different numbers of clusters using the Elbow and Silhouette methods, and visualized the results using PCA.&lt;/p&gt;

&lt;p&gt;The outcome made sense.&lt;/p&gt;

&lt;p&gt;I could identify VIP customers, loyal high-spenders, mid-value customers, and customers who were at risk of becoming inactive. Better yet, I could explain how each segment could help a business improve marketing, customer retention, and loyalty programs.&lt;/p&gt;

&lt;p&gt;I wrote a detailed README, pushed everything to GitHub, and considered the project complete.&lt;/p&gt;

&lt;p&gt;Or so I thought.&lt;/p&gt;

&lt;h2&gt;
  
  
  One Question Changed How I Saw the Project
&lt;/h2&gt;

&lt;p&gt;A few months later, I looked at the repository again and asked myself a question I hadn't considered before.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;If I gave this project to a business today, could they actually use it?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The answer was no.&lt;/p&gt;

&lt;p&gt;Not because the model was inaccurate.&lt;/p&gt;

&lt;p&gt;Not because the clustering was poor.&lt;/p&gt;

&lt;p&gt;Simply because everything lived inside a Jupyter notebook.&lt;/p&gt;

&lt;p&gt;The only person who could use the project was the person who built it.&lt;/p&gt;

&lt;p&gt;Me.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Notebook Was Never the Product
&lt;/h2&gt;

&lt;p&gt;I think this is a stage many aspiring data scientists go through.&lt;/p&gt;

&lt;p&gt;We spend hours cleaning messy datasets, engineering features, comparing models, tuning hyperparameters, and producing visualizations. Once the metrics look good and the notebook runs from top to bottom without errors, it feels like the project is finished.&lt;/p&gt;

&lt;p&gt;That's exactly how I approached my customer segmentation project.&lt;/p&gt;

&lt;p&gt;From a machine learning perspective, I had done what I set out to do.&lt;/p&gt;

&lt;p&gt;From a user's perspective, though, nothing had been built.&lt;/p&gt;

&lt;p&gt;Imagine you're the owner of a retail business.&lt;/p&gt;

&lt;p&gt;You don't want to open a notebook.&lt;/p&gt;

&lt;p&gt;You don't want to install Python or understand K-Means clustering.&lt;/p&gt;

&lt;p&gt;You probably don't even care how the customers are segmented.&lt;/p&gt;

&lt;p&gt;You simply want to upload your latest sales data and receive a list of VIP customers, loyal customers, and customers who might need a re-engagement campaign.&lt;/p&gt;

&lt;p&gt;My project couldn't do that.&lt;/p&gt;

&lt;p&gt;It produced useful insights, but only if someone opened the notebook and reran the analysis.&lt;/p&gt;

&lt;p&gt;That realization forced me to rethink what "finished" really means.&lt;/p&gt;

&lt;h2&gt;
  
  
  I Discovered a Gap in My Learning
&lt;/h2&gt;

&lt;p&gt;For a long time, I believed the next step in improving as a data scientist was learning another algorithm.&lt;/p&gt;

&lt;p&gt;Maybe I should study gradient boosting more deeply.&lt;/p&gt;

&lt;p&gt;Maybe I should explore deep learning.&lt;/p&gt;

&lt;p&gt;Maybe I should improve my feature engineering.&lt;/p&gt;

&lt;p&gt;Those are valuable skills, but they weren't the gap I had uncovered.&lt;/p&gt;

&lt;p&gt;The real gap was everything that happens after the notebook.&lt;/p&gt;

&lt;p&gt;How do you package a model?&lt;/p&gt;

&lt;p&gt;How do you let someone interact with it without touching your code?&lt;/p&gt;

&lt;p&gt;How do you turn analysis into something another person can actually use?&lt;/p&gt;

&lt;p&gt;Those weren't questions I had been asking.&lt;/p&gt;

&lt;p&gt;Now they seem impossible to ignore.&lt;/p&gt;

&lt;h2&gt;
  
  
  A Project Isn't Finished Just Because the Analysis Is
&lt;/h2&gt;

&lt;p&gt;Looking back, I don't think my customer segmentation project was a failure.&lt;/p&gt;

&lt;p&gt;Far from it.&lt;/p&gt;

&lt;p&gt;It taught me how to work with real-world transactional data, engineer meaningful business features, apply unsupervised learning techniques, and communicate insights through visualizations.&lt;/p&gt;

&lt;p&gt;Those are valuable skills.&lt;/p&gt;

&lt;p&gt;But I've stopped thinking of the notebook as the final product.&lt;/p&gt;

&lt;p&gt;I now see it as a prototype.&lt;/p&gt;

&lt;p&gt;A place where ideas are tested before they become something useful.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Comes Next
&lt;/h2&gt;

&lt;p&gt;I'm not writing this as someone who has mastered deployment or MLOps.&lt;/p&gt;

&lt;p&gt;I haven't.&lt;/p&gt;

&lt;p&gt;In fact, that's exactly why I'm writing this.&lt;/p&gt;

&lt;p&gt;I've realized that every machine learning project I've completed has stopped at the notebook stage, and I don't want the next one to end there.&lt;/p&gt;

&lt;p&gt;My next challenge isn't building a model with a slightly better score.&lt;/p&gt;

&lt;p&gt;It's learning how to take one of the projects I've already built and make it accessible to someone who has never written a line of Python.&lt;/p&gt;

&lt;p&gt;Maybe that means exposing it through an API.&lt;/p&gt;

&lt;p&gt;Maybe it becomes a simple web application.&lt;/p&gt;

&lt;p&gt;Maybe it evolves into something I haven't even considered yet.&lt;/p&gt;

&lt;p&gt;I don't know exactly what that journey will look like.&lt;/p&gt;

&lt;p&gt;But I know where it starts.&lt;/p&gt;

&lt;p&gt;It starts by recognizing that a notebook is an excellent place to build a model.&lt;/p&gt;

&lt;p&gt;It just isn't always where the project should end.&lt;/p&gt;




&lt;p&gt;Have you ever looked back at one of your machine learning projects and realized it wasn't as "finished" as you first thought? I'd love to hear how you've approached moving beyond the notebook—or whether you're figuring it out too.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>I Kept Recreating My Django Superuser Every Time I Switched Computers — Until I Finally Understood What Was Happening</title>
      <dc:creator>Michael Nyawade</dc:creator>
      <pubDate>Tue, 02 Jun 2026 12:24:36 +0000</pubDate>
      <link>https://dev.to/mnyawade/i-kept-recreating-my-django-superuser-every-time-i-switched-computers-until-i-finally-understood-2col</link>
      <guid>https://dev.to/mnyawade/i-kept-recreating-my-django-superuser-every-time-i-switched-computers-until-i-finally-understood-2col</guid>
      <description>&lt;p&gt;I’ve been building a Django project called &lt;strong&gt;SmartDuka&lt;/strong&gt;, a smart shop management system for small retailers and shop owners. It handles inventory tracking, low stock alerts, dead stock detection, sales tracking, credit sales, and daily business insights.&lt;/p&gt;

&lt;p&gt;This is also my first serious Django project.&lt;/p&gt;

&lt;p&gt;And for a while, every time I switched from my home laptop to my work laptop, I went through the exact same process:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git clone
python &lt;span class="nt"&gt;-m&lt;/span&gt; venv venv
pip &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-r&lt;/span&gt; requirements.txt
python manage.py migrate
python manage.py createsuperuser
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then I would open the admin panel and start entering products, customers, and sample sales all over again.&lt;/p&gt;

&lt;p&gt;Every. Single. Time.&lt;/p&gt;

&lt;p&gt;At first, I thought this was just part of working with Django. But eventually I realized I wasn’t actually understanding the relationship between:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;my code&lt;/li&gt;
&lt;li&gt;migrations&lt;/li&gt;
&lt;li&gt;and the database itself&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This article is basically the explanation I wish someone had given me earlier.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Mistake I Wasn’t Really Making
&lt;/h2&gt;

&lt;p&gt;To be fair, I &lt;em&gt;was&lt;/em&gt; doing one important thing correctly:&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;



&lt;p&gt;was inside my &lt;code&gt;.gitignore&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;For a good reason SQLite databases are local files and usually shouldn’t be committed to Git.&lt;/p&gt;

&lt;p&gt;So technically my workflow looked “correct.”&lt;/p&gt;

&lt;p&gt;The problem was this:&lt;/p&gt;

&lt;p&gt;I assumed migrations would somehow preserve my data across machines.&lt;/p&gt;

&lt;p&gt;They don’t.&lt;/p&gt;




&lt;h2&gt;
  
  
  What Django Migrations Actually Do
&lt;/h2&gt;

&lt;p&gt;This part finally clicked for me after some frustration.&lt;/p&gt;

&lt;p&gt;When you run:&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;



&lt;p&gt;Django recreates the &lt;strong&gt;database structure&lt;/strong&gt;, not the actual records inside it.&lt;/p&gt;

&lt;p&gt;So migrations restore things like:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;tables&lt;/li&gt;
&lt;li&gt;columns&lt;/li&gt;
&lt;li&gt;relationships&lt;/li&gt;
&lt;li&gt;constraints&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;But they do &lt;em&gt;not&lt;/em&gt; restore:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;superusers&lt;/li&gt;
&lt;li&gt;products&lt;/li&gt;
&lt;li&gt;inventory&lt;/li&gt;
&lt;li&gt;sales records&lt;/li&gt;
&lt;li&gt;customers&lt;/li&gt;
&lt;li&gt;suppliers&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That data lives inside the database itself.&lt;/p&gt;

&lt;p&gt;And in SQLite, that database is literally one file:&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;



&lt;p&gt;Once I understood that, everything made sense.&lt;/p&gt;




&lt;h2&gt;
  
  
  Why I Had to Keep Recreating My Superuser
&lt;/h2&gt;

&lt;p&gt;Because every new machine was getting:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;fresh empty database
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After migrations, Django had the tables it needed, but there were no actual records inside them yet.&lt;/p&gt;

&lt;p&gt;So naturally:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;no users existed&lt;/li&gt;
&lt;li&gt;no inventory existed&lt;/li&gt;
&lt;li&gt;no sales existed&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I wasn’t losing my code.&lt;/p&gt;

&lt;p&gt;I was losing my database state.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Different Solutions I Considered
&lt;/h2&gt;

&lt;p&gt;Once I understood the problem properly, I realized there are several ways developers approach this.&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Recreate Everything Every Time
&lt;/h3&gt;

&lt;p&gt;This was my original workflow.&lt;/p&gt;

&lt;p&gt;It technically works, but only for tiny projects.&lt;/p&gt;

&lt;p&gt;Once your app starts accumulating meaningful data, this becomes painful very quickly.&lt;/p&gt;




&lt;h3&gt;
  
  
  2. Commit &lt;code&gt;db.sqlite3&lt;/code&gt; to Git
&lt;/h3&gt;

&lt;p&gt;I considered this briefly.&lt;/p&gt;

&lt;p&gt;It solves the syncing issue, but introduces other problems:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;binary file conflicts&lt;/li&gt;
&lt;li&gt;messy Git history&lt;/li&gt;
&lt;li&gt;merge problems&lt;/li&gt;
&lt;li&gt;potential security risks&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For a real project, this didn’t feel right.&lt;/p&gt;




&lt;h3&gt;
  
  
  3. Use Fixtures
&lt;/h3&gt;

&lt;p&gt;Django supports:&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;



&lt;p&gt;which export and import data as JSON fixtures.&lt;/p&gt;

&lt;p&gt;This is actually pretty useful for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;demo data&lt;/li&gt;
&lt;li&gt;seed data&lt;/li&gt;
&lt;li&gt;lookup tables&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;But for constantly changing business data like inventory and sales, it felt awkward as the main solution.&lt;/p&gt;




&lt;h3&gt;
  
  
  4. Copy &lt;code&gt;db.sqlite3&lt;/code&gt; Between Machines
&lt;/h3&gt;

&lt;p&gt;This ended up being the most practical short-term solution for me.&lt;/p&gt;

&lt;p&gt;Instead of recreating everything, I simply keep the latest SQLite database and transfer it between machines manually.&lt;/p&gt;

&lt;p&gt;That preserves:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;my superuser&lt;/li&gt;
&lt;li&gt;inventory records&lt;/li&gt;
&lt;li&gt;customers&lt;/li&gt;
&lt;li&gt;sales history&lt;/li&gt;
&lt;li&gt;everything else&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The workflow now looks more like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git pull
pip &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-r&lt;/span&gt; requirements.txt
&lt;span class="c"&gt;# copy latest db.sqlite3&lt;/span&gt;
python manage.py migrate
python manage.py runserver
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Much better.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Important Detail About Migrations
&lt;/h2&gt;

&lt;p&gt;One thing I learned here:&lt;/p&gt;

&lt;p&gt;The correct order is:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;copy &lt;code&gt;db.sqlite3&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;then run migrations&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Not the other way around.&lt;/p&gt;

&lt;p&gt;Why?&lt;/p&gt;

&lt;p&gt;Because migrations should update your &lt;em&gt;existing&lt;/em&gt; database schema if new model changes were added.&lt;/p&gt;

&lt;p&gt;For example, if yesterday my &lt;code&gt;Product&lt;/code&gt; model had:&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;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;models&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;CharField&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;max_length&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;and today I added:&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;price&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;models&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;DecimalField&lt;/span&gt;&lt;span class="p"&gt;(...)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;then running:&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;



&lt;p&gt;updates the copied database safely.&lt;/p&gt;

&lt;p&gt;That’s exactly what migrations are designed for.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Bigger Realization
&lt;/h2&gt;

&lt;p&gt;At some point, I realized SmartDuka started behaving like a real system.&lt;/p&gt;

&lt;p&gt;And once that happens, things like:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;persistence&lt;/li&gt;
&lt;li&gt;synchronization&lt;/li&gt;
&lt;li&gt;database strategy&lt;/li&gt;
&lt;li&gt;backups&lt;/li&gt;
&lt;li&gt;scalability&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;suddenly become important.&lt;/p&gt;

&lt;p&gt;That transition caught me by surprise a little.&lt;/p&gt;




&lt;h2&gt;
  
  
  What I’m Planning Next
&lt;/h2&gt;

&lt;p&gt;Right now I’m still using SQLite during development because it’s simple and fast.&lt;/p&gt;

&lt;p&gt;But I can already see that eventually I’ll need to move toward PostgreSQL, especially because SmartDuka deals with:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;transactions&lt;/li&gt;
&lt;li&gt;inventory&lt;/li&gt;
&lt;li&gt;analytics&lt;/li&gt;
&lt;li&gt;credit management&lt;/li&gt;
&lt;li&gt;reporting&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;At that point, having a shared database instead of manually copying SQLite files will make much more sense.&lt;/p&gt;

&lt;p&gt;But honestly, understanding &lt;em&gt;why&lt;/em&gt; I was recreating my superuser every time was already a huge learning moment.&lt;/p&gt;




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

&lt;p&gt;One thing I’m learning while building real projects is that software development isn’t only about writing features.&lt;/p&gt;

&lt;p&gt;Sometimes the biggest lessons come from workflow problems.&lt;/p&gt;

&lt;p&gt;This was one of them for me.&lt;/p&gt;

&lt;p&gt;If you’re new to Django and you’ve ever wondered:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;“Why do I keep losing my data even after running migrations?”&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;hopefully this article saves you a few hours of confusion.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Why Adding a Unique SKU Field Broke My Django Migration</title>
      <dc:creator>Michael Nyawade</dc:creator>
      <pubDate>Sun, 10 May 2026 08:05:18 +0000</pubDate>
      <link>https://dev.to/mnyawade/why-adding-a-unique-sku-field-broke-my-django-migration-3bk8</link>
      <guid>https://dev.to/mnyawade/why-adding-a-unique-sku-field-broke-my-django-migration-3bk8</guid>
      <description>&lt;p&gt;In building projects using Django, one thing that I have realized about database migrations is that things may appear simple until the moment one alters an existing model.&lt;/p&gt;

&lt;p&gt;For example, in developing an inventory management app for my project recently, I experienced a migration problem, which, although small, helped me understand how migrations work within Django and in particular, when adding unique constraints to existing databases.&lt;/p&gt;

&lt;p&gt;I would like to document this problem since someone else may have experienced the same thing.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Initial Inventory Model
&lt;/h2&gt;

&lt;p&gt;At the beginning, my &lt;code&gt;Product&lt;/code&gt; model was 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="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;django.db&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;models&lt;/span&gt;


&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Product&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;models&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Model&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="n"&gt;models&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;CharField&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;max_length&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;buying_price&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;models&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;DecimalField&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;max_digits&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;decimal_places&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;selling_price&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;models&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;DecimalField&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;max_digits&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;decimal_places&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;stock_quantity&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;models&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;PositiveIntegerField&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;default&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;low_stock_threshold&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;models&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;PositiveIntegerField&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;default&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;created_at&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;models&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;DateTimeField&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;auto_now_add&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;def&lt;/span&gt; &lt;span class="nf"&gt;__str__&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="k"&gt;return&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;name&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After creating the model, I generated and applied migrations:&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;



&lt;p&gt;I also registered the model in &lt;code&gt;admin.py&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.contrib&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;admin&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;.models&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Product&lt;/span&gt;


&lt;span class="n"&gt;admin&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;site&lt;/span&gt;&lt;span class="p"&gt;.&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;Product&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Everything worked perfectly.&lt;/p&gt;

&lt;p&gt;I created a superuser, logged into the Django admin panel, tested the model, and there were no issues.&lt;/p&gt;




&lt;h2&gt;
  
  
  Updating the Inventory App
&lt;/h2&gt;

&lt;p&gt;As the project evolved, I realized the inventory system needed product categories and SKU support.&lt;/p&gt;

&lt;p&gt;So I updated &lt;code&gt;models.py&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&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;models&lt;/span&gt;


&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Category&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;models&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Model&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="n"&gt;models&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;CharField&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;max_length&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;unique&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;verbose_name_plural&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Categories&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;__str__&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="k"&gt;return&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;name&lt;/span&gt;


&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Product&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;models&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Model&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;category&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;models&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;ForeignKey&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;Category&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;on_delete&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;models&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;CASCADE&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;related_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;products&lt;/span&gt;&lt;span class="sh"&gt;'&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="n"&gt;models&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;CharField&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;max_length&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;sku&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;models&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;CharField&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;max_length&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="n"&gt;unique&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;buying_price&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;models&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;DecimalField&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;max_digits&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;decimal_places&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;selling_price&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;models&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;DecimalField&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;max_digits&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;decimal_places&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;stock_quantity&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;models&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;PositiveIntegerField&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;default&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;low_stock_threshold&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;models&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;PositiveIntegerField&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;default&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;created_at&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;models&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;DateTimeField&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;auto_now_add&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;def&lt;/span&gt; &lt;span class="nf"&gt;profit_per_item&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="k"&gt;return&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;selling_price&lt;/span&gt; &lt;span class="o"&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;buying_price&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;is_low_stock&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="k"&gt;return&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;stock_quantity&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&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;low_stock_threshold&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;__str__&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="k"&gt;return&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;name&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I also updated &lt;code&gt;admin.py&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.contrib&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;admin&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;.models&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Category&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Product&lt;/span&gt;


&lt;span class="n"&gt;admin&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;site&lt;/span&gt;&lt;span class="p"&gt;.&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;Category&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;admin&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;site&lt;/span&gt;&lt;span class="p"&gt;.&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;Product&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then I created new migrations.&lt;/p&gt;

&lt;p&gt;At this point, I expected everything to work normally.&lt;/p&gt;

&lt;p&gt;Instead, Django threw a migration error.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Error I Encountered
&lt;/h2&gt;

&lt;p&gt;When I ran:&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;



&lt;p&gt;I got this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;django.db.utils.IntegrityError:
UNIQUE constraint failed: new__inventory_product.sku
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;At first, I was confused.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;sku&lt;/code&gt; field looked correct:&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;sku&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;models&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;CharField&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;max_length&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="n"&gt;unique&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;p&gt;So why was the migration failing?&lt;/p&gt;




&lt;h2&gt;
  
  
  What Was Actually Happening
&lt;/h2&gt;

&lt;p&gt;After looking into it more carefully, I realized the issue was related to existing database records.&lt;/p&gt;

&lt;p&gt;Before adding the &lt;code&gt;sku&lt;/code&gt; field, the &lt;code&gt;Product&lt;/code&gt; table already existed in the database.&lt;/p&gt;

&lt;p&gt;When Django attempted to apply the migration, SQLite internally tried to:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Create a new version of the table&lt;/li&gt;
&lt;li&gt;Copy the old data into the new table&lt;/li&gt;
&lt;li&gt;Apply the new constraints&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The problem was that the new &lt;code&gt;sku&lt;/code&gt; field had &lt;code&gt;unique=True&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Existing records in the database didn’t have SKU values yet.&lt;/p&gt;

&lt;p&gt;As SQLite tried moving data into the new table structure, duplicate empty values conflicted with the unique constraint.&lt;/p&gt;

&lt;p&gt;That’s why the migration failed.&lt;/p&gt;




&lt;h2&gt;
  
  
  How I Fixed It
&lt;/h2&gt;

&lt;p&gt;Since I was still in the development stage of the project, I decided to reset the database completely.&lt;/p&gt;

&lt;p&gt;Here’s what I did:&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Stopped the Development Server
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;CTRL + C
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  2. Deleted the SQLite Database
&lt;/h3&gt;



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

&lt;/div&gt;



&lt;h3&gt;
  
  
  3. Deleted Old Migration Files
&lt;/h3&gt;

&lt;p&gt;I deleted the migration files inside the app’s &lt;code&gt;migrations&lt;/code&gt; folder, except:&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;



&lt;h3&gt;
  
  
  4. Recreated Migrations
&lt;/h3&gt;



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

&lt;/div&gt;



&lt;h3&gt;
  
  
  5. Applied Migrations Again
&lt;/h3&gt;



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

&lt;/div&gt;



&lt;h3&gt;
  
  
  6. Recreated the Superuser
&lt;/h3&gt;



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

&lt;/div&gt;



&lt;p&gt;After that, everything worked correctly.&lt;/p&gt;




&lt;h2&gt;
  
  
  What I Learned
&lt;/h2&gt;

&lt;p&gt;This experience taught me an important lesson:&lt;/p&gt;

&lt;p&gt;Adding unique fields to existing Django models can break migrations if the database already contains records.&lt;/p&gt;

&lt;p&gt;Even though the code itself may look correct, the migration process also depends on the current database state.&lt;/p&gt;

&lt;p&gt;I also learned that:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Resetting the database is acceptable during early development&lt;/li&gt;
&lt;li&gt;It is not a good solution for production systems&lt;/li&gt;
&lt;li&gt;Database schema changes should be planned carefully&lt;/li&gt;
&lt;li&gt;Unique constraints require special attention when existing data is involved&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  A Better Production Approach
&lt;/h2&gt;

&lt;p&gt;If this were a production project, deleting the database would obviously be a bad idea.&lt;/p&gt;

&lt;p&gt;A safer approach would be:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Add the field without &lt;code&gt;unique=True&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Populate existing rows with unique values&lt;/li&gt;
&lt;li&gt;Then apply the unique constraint in a later migration&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That prevents conflicts with existing records.&lt;/p&gt;




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

&lt;p&gt;This wasn’t the biggest bug I’ve encountered in Django, but it was one of those moments that helped me understand migrations better.&lt;/p&gt;

&lt;p&gt;Sometimes small errors teach the most useful lessons.&lt;/p&gt;

&lt;p&gt;If you’re learning Django and run into migration issues after modifying models, don’t panic immediately. In many cases, the problem is related to how existing database records interact with the new schema changes.&lt;/p&gt;

&lt;p&gt;Hopefully this saves someone else a few hours of confusion.&lt;/p&gt;

</description>
      <category>backend</category>
      <category>database</category>
      <category>django</category>
      <category>python</category>
    </item>
  </channel>
</rss>
