<?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: dan</title>
    <description>The latest articles on DEV Community by dan (@dangote).</description>
    <link>https://dev.to/dangote</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3302668%2Fecc5553c-0fde-45d0-a46c-627e50e3049a.png</url>
      <title>DEV Community: dan</title>
      <link>https://dev.to/dangote</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/dangote"/>
    <language>en</language>
    <item>
      <title>Why You Can’t Skip a Custom Backend—Even With AI-Powered Frontends</title>
      <dc:creator>dan</dc:creator>
      <pubDate>Sun, 18 Jan 2026 13:44:33 +0000</pubDate>
      <link>https://dev.to/dangote/why-you-cant-skip-a-custom-backend-even-with-ai-powered-frontends-2ibf</link>
      <guid>https://dev.to/dangote/why-you-cant-skip-a-custom-backend-even-with-ai-powered-frontends-2ibf</guid>
      <description>&lt;p&gt;When I first started experimenting with TypeScript React frameworks like V0, I felt like I had discovered a cheat code for development. In minutes, I could spin up components, forms, and even API calls. AI was doing the heavy lifting, scaffolding hooks and UI components that used to take hours to write manually.&lt;/p&gt;

&lt;p&gt;It’s exhilarating. It’s fast. It feels almost… magical.&lt;/p&gt;

&lt;p&gt;But here’s the reality every developer runs into eventually: integration with your backend can quietly, painfully break your app.&lt;/p&gt;

&lt;p&gt;The Hidden Integration Problem&lt;/p&gt;

&lt;p&gt;Let me give you a real example. Suppose your V0 frontend scaffolds an API call to &lt;code&gt;/api/bookings&lt;/code&gt; and expects this JSON structure:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{
  "id": 1,
  "user": "Alice",
  "seats": 3
}


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Your frontend then uses:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;console.log(data.seats); // Expected: 3
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;But your Flask backend—either because of legacy database naming or your own logic—returns:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{
  "booking_id": 1,
  "username": "Alice",
  "seat_count": 3
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Boom. &lt;code&gt;data.seats&lt;/code&gt; is &lt;code&gt;undefined&lt;/code&gt;. Forms break. Lists render incorrectly. Payment flows fail. And here’s the kicker: V0 didn’t warn you. The AI assumes the backend is perfect and that its generated frontend matches it exactly.&lt;/p&gt;

&lt;p&gt;This is the exact moment I realized: AI may speed up frontend development, but your &lt;strong&gt;backend is the real source of truth&lt;/strong&gt;. Without control over it, you’re walking blind.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why a Custom Backend Is Non-Negotiable
&lt;/h2&gt;

&lt;p&gt;Building a custom backend—like a Flask API—is essential for several reasons:&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Consistent Data Contracts
&lt;/h3&gt;

&lt;p&gt;You define exactly how JSON is structured, what fields exist, and what types they are. The frontend no longer has to guess.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Business Logic Enforcement
&lt;/h3&gt;

&lt;p&gt;The AI-generated frontend won’t know your rules. If a booking exceeds available seats, or a payment amount doesn’t match, your backend must handle it.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Security and Validation
&lt;/h3&gt;

&lt;p&gt;AI can’t magically secure endpoints or validate user input. Without a custom backend, your app is vulnerable.&lt;/p&gt;

&lt;h3&gt;
  
  
  4. Scalability
&lt;/h3&gt;

&lt;p&gt;When your app grows, you’ll need endpoints that handle multiple routes, user roles, or third-party integrations. A custom backend gives you the flexibility to evolve.&lt;/p&gt;

&lt;h3&gt;
  
  
  5. How to Avoid the &lt;code&gt;Undefined&lt;/code&gt; Problem
&lt;/h3&gt;

&lt;p&gt;Here’s a simple Flask example to normalize backend responses for AI-powered frontends:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;from flask import Flask, jsonify

app = Flask(__name__)

# Sample data from your database
booking_db = {
    "booking_id": 1,
    "username": "Alice",
    "seat_count": 3
}

@app.route("/api/bookings")
def get_booking():
    # Normalize keys to match frontend expectation
    response = {
        "id": booking_db["booking_id"],
        "user": booking_db["username"],
        "seats": booking_db["seat_count"]
    }
    return jsonify(response)

if __name__ == "__main__":
    app.run(debug=True)

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now your frontend gets exactly what it expects:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{
  "id": 1,
  "user": "Alice",
  "seats": 3
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;No surprises. No undefined values. No broken forms.&lt;/p&gt;

&lt;h2&gt;
  
  
  Bottom Line
&lt;/h2&gt;

&lt;p&gt;AI-powered frontends like V0 are amazing—they can dramatically shorten development time, generate boilerplate, and even suggest best practices. But they cannot replace a robust backend.&lt;/p&gt;

&lt;p&gt;Think of it like this: AI is a jet engine—it’ll get you moving fast, but you still need a pilot. That pilot is your custom backend. Without it, subtle bugs, unexpected data mismatches, and security holes will sneak in—and fixing them after the fact is far more painful than building it correctly from the start.&lt;/p&gt;

&lt;p&gt;So, if you’re thinking about skipping a custom backend because AI is &lt;em&gt;&lt;strong&gt;doing everything for you&lt;/strong&gt;&lt;/em&gt;—don’t. Build your backend first, define your contracts, enforce your rules, and then let AI supercharge your frontend.&lt;/p&gt;

&lt;p&gt;Trust me: your future self (and your users) will thank you.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>architecture</category>
      <category>backend</category>
      <category>frontend</category>
    </item>
    <item>
      <title>Understanding the {backpopulate} Parameter in SQLAlchemy Relationships</title>
      <dc:creator>dan</dc:creator>
      <pubDate>Fri, 05 Dec 2025 12:04:57 +0000</pubDate>
      <link>https://dev.to/dangote/understanding-the-backpopulate-parameter-in-sqlalchemy-relationships-2m95</link>
      <guid>https://dev.to/dangote/understanding-the-backpopulate-parameter-in-sqlalchemy-relationships-2m95</guid>
      <description>&lt;p&gt;If you've worked with SQLAlchemy's ORM, you've likely encountered the &lt;code&gt;backpopulate&lt;/code&gt; parameter when defining relationships between database models. While it might seem like just another configuration option, understanding &lt;code&gt;backpopulate&lt;/code&gt; is crucial for creating clean, maintainable bidirectional relationships in your applications.&lt;/p&gt;

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

&lt;p&gt;The &lt;code&gt;backpopulate&lt;/code&gt; parameter in SQLAlchemy's &lt;code&gt;relationship()&lt;/code&gt; function establishes a bidirectional relationship between two models. When you set &lt;code&gt;backpopulate&lt;/code&gt; on one side of a relationship, SQLAlchemy automatically manages both sides of the association, keeping them synchronized.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Do We Need It?
&lt;/h2&gt;

&lt;p&gt;In relational databases, relationships naturally work in both directions. If a User has many Posts, then each Post belongs to a User. Without &lt;code&gt;backpopulate&lt;/code&gt;, you'd need to manually manage both sides of this relationship, which is error-prone and verbose.&lt;/p&gt;

&lt;h2&gt;
  
  
  Basic Example
&lt;/h2&gt;

&lt;p&gt;Let's look at a simple one-to-many relationship between users and posts:&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;sqlalchemy&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Column&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Integer&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;String&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ForeignKey&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;sqlalchemy.orm&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;relationship&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;DeclarativeBase&lt;/span&gt;

&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Base&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;DeclarativeBase&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;pass&lt;/span&gt;

&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;User&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Base&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;__tablename__&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;users&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;

    &lt;span class="nb"&gt;id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Column&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Integer&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;primary_key&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;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Column&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;String&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c1"&gt;# Define the relationship with backpopulate
&lt;/span&gt;    &lt;span class="n"&gt;posts&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;relationship&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Post&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;backpopulate&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;author&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;Post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Base&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;__tablename__&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;posts&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;

    &lt;span class="nb"&gt;id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Column&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Integer&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;primary_key&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;title&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Column&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;String&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;user_id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Column&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Integer&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="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;users.id&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;

    &lt;span class="c1"&gt;# The other side of the relationship
&lt;/span&gt;    &lt;span class="n"&gt;author&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;relationship&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;User&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;backpopulate&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;posts&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;h2&gt;
  
  
  How It Works
&lt;/h2&gt;

&lt;p&gt;When you use &lt;code&gt;backpopulate&lt;/code&gt;, SQLAlchemy handles the synchronization automatically:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# Create a user and a post
&lt;/span&gt;&lt;span class="n"&gt;user&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;User&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Alice&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;post&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;title&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;My First Post&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;# Set the relationship from one side
&lt;/span&gt;&lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;posts&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;post&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;# SQLAlchemy automatically sets the other side
&lt;/span&gt;&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;post&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;author&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  &lt;span class="c1"&gt;# Output: Alice
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You could also set it from the other direction:&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;post&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;author&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;user&lt;/span&gt;
&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;posts&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;  &lt;span class="c1"&gt;# Output: 1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  backpopulate vs back_populates vs backref
&lt;/h2&gt;

&lt;p&gt;You might encounter similar-looking parameters and wonder about the differences:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;code&gt;backpopulate&lt;/code&gt;&lt;/strong&gt;: Explicitly defines both sides of the relationship. You need to specify it on both models, which makes the relationship clear and explicit.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;code&gt;back_populates&lt;/code&gt;&lt;/strong&gt;: This is actually the same as &lt;code&gt;backpopulate&lt;/code&gt; - just an alternative spelling. SQLAlchemy accepts both.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;code&gt;backref&lt;/code&gt;&lt;/strong&gt;: An older approach that automatically creates the reverse relationship. While convenient, it's less explicit:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# Using backref (older style)
&lt;/span&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;User&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Base&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;posts&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;relationship&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Post&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;backref&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;author&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;# Only need to define on one side
# The "author" attribute is automatically created on Post
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The modern best practice is to use &lt;code&gt;backpopulate&lt;/code&gt; because it's more explicit and easier to understand when reading code.&lt;/p&gt;

&lt;h2&gt;
  
  
  Many-to-Many Relationships
&lt;/h2&gt;

&lt;p&gt;The &lt;code&gt;backpopulate&lt;/code&gt; parameter works with many-to-many relationships too:&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;sqlalchemy&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Table&lt;/span&gt;

&lt;span class="c1"&gt;# Association table
&lt;/span&gt;&lt;span class="n"&gt;student_course&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Table&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;student_course&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;Base&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;metadata&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nc"&gt;Column&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;student_id&lt;/span&gt;&lt;span class="sh"&gt;'&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="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;students.id&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)),&lt;/span&gt;
    &lt;span class="nc"&gt;Column&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;course_id&lt;/span&gt;&lt;span class="sh"&gt;'&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="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;courses.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;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Student&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Base&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;__tablename__&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;students&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;
    &lt;span class="nb"&gt;id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Column&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Integer&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;primary_key&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;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Column&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;String&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;courses&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;relationship&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Course&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;secondary&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;student_course&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;backpopulate&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;students&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;Course&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Base&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;__tablename__&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;courses&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;
    &lt;span class="nb"&gt;id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Column&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Integer&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;primary_key&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;title&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Column&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;String&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;students&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;relationship&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Student&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;secondary&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;student_course&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;backpopulate&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;courses&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;h2&gt;
  
  
  Common Pitfalls
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;1. Mismatched Names&lt;/strong&gt;: The string you pass to &lt;code&gt;backpopulate&lt;/code&gt; must exactly match the attribute name on the other model:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# Wrong - will cause an error
&lt;/span&gt;&lt;span class="n"&gt;posts&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;relationship&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Post&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;backpopulate&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;user&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  &lt;span class="c1"&gt;# Should be "author"
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;2. Forgetting to Define Both Sides&lt;/strong&gt;: When using &lt;code&gt;backpopulate&lt;/code&gt;, you must define the relationship on both models.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. Circular Imports&lt;/strong&gt;: When models are in different files, you might encounter circular import issues. Use string references for the model class:&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;posts&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;relationship&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Post&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;backpopulate&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;author&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  &lt;span class="c1"&gt;# String reference
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Benefits of Using backpopulate
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Automatic Synchronization&lt;/strong&gt;: Changes on one side automatically reflect on the other&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cleaner Code&lt;/strong&gt;: No need to manually manage both sides of relationships&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Type Safety&lt;/strong&gt;: Modern IDEs can better understand your relationships&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Explicit Intent&lt;/strong&gt;: Makes your data model's structure clear to other developers&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cascade Operations&lt;/strong&gt;: Works seamlessly with SQLAlchemy's cascade options&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Best Practices
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Always use &lt;code&gt;backpopulate&lt;/code&gt; for bidirectional relationships&lt;/li&gt;
&lt;li&gt;Be consistent with naming conventions across your models&lt;/li&gt;
&lt;li&gt;Place foreign keys on the "many" side of one-to-many relationships&lt;/li&gt;
&lt;li&gt;Use type hints with modern SQLAlchemy for better IDE support&lt;/li&gt;
&lt;li&gt;Document complex relationships with comments&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;The &lt;code&gt;backpopulate&lt;/code&gt; parameter is a powerful feature that simplifies working with bidirectional relationships in SQLAlchemy. By understanding how it works and following best practices, you can create cleaner, more maintainable database models that accurately represent the relationships in your application's domain.&lt;/p&gt;

&lt;p&gt;Whether you're building a simple blog system or a complex enterprise application, mastering &lt;code&gt;backpopulate&lt;/code&gt; will make your SQLAlchemy code more robust and easier to work with.&lt;/p&gt;

</description>
      <category>python</category>
      <category>database</category>
      <category>backend</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Making React Apps Delightful with Confetti Effects</title>
      <dc:creator>dan</dc:creator>
      <pubDate>Sat, 26 Jul 2025 12:59:31 +0000</pubDate>
      <link>https://dev.to/dangote/making-react-apps-delightful-with-confetti-effects-1ag5</link>
      <guid>https://dev.to/dangote/making-react-apps-delightful-with-confetti-effects-1ag5</guid>
      <description>&lt;p&gt;React is powerful  but sometimes, even with beautiful logic and data flow, the &lt;strong&gt;user experience can feel dry&lt;/strong&gt;. What if we could add a little &lt;em&gt;joy&lt;/em&gt; when users complete tasks?&lt;/p&gt;

&lt;p&gt;Let’s explore how to make your React apps more &lt;strong&gt;delightful&lt;/strong&gt; using a simple &lt;strong&gt;confetti explosion&lt;/strong&gt; when users achieve something awesome!&lt;/p&gt;




&lt;h2&gt;
  
  
  Why Add Delight?
&lt;/h2&gt;

&lt;p&gt;Think about the last time you saw fireworks in an app maybe when you finished a task in Duolingo or submitted a form in Notion. These tiny micro-interactions:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Reinforce user progress
&lt;/li&gt;
&lt;li&gt;Add emotional engagement
&lt;/li&gt;
&lt;li&gt;Encourage repeat use
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;With React, you can do this &lt;em&gt;easily&lt;/em&gt; using &lt;code&gt;react-confetti&lt;/code&gt; or &lt;code&gt;canvas-confetti&lt;/code&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  Setup: Using &lt;code&gt;canvas-confetti&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;Let’s create a &lt;strong&gt;Task Completion Confetti Effect&lt;/strong&gt; in a React app:&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Install the library
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install &lt;/span&gt;canvas-confetti
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  2. Import and trigger confetti
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import confetti from "canvas-confetti";

function celebrate() {
  confetti({
    particleCount: 100,
    spread: 70,
    origin: { y: 0.6 },
  });
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;You can trigger this function when:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;A task is marked complete&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;A quiz is passed&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;A form is submitted&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  3. Hook It Up to a Button
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;function CongratsButton() {
  return (
    &amp;lt;button onClick={celebrate}&amp;gt;
      I Did It! 
    &amp;lt;/button&amp;gt;
  );
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  4. Bonus: Trigger Only Once
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import { useState } from "react";

function TaskDone() {
  const [done, setDone] = useState(false);

  function handleClick() {
    if (!done) {
      confetti();
      setDone(true);
    }
  }

  return &amp;lt;button onClick={handleClick}&amp;gt;Complete Task&amp;lt;/button&amp;gt;;
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  What You Just Learned
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;You can add meaningful micro-interactions in React&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;canvas-confetti works well without complex setup&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Emotion matters in UX — make users feel rewarded!&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Try This Next
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Add sound feedback using use-sound&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Combine with a progress bar&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Animate button transforms with framer-motion&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

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

&lt;p&gt;Don't underestimate the power of small delights. Whether you're building a to-do app, a quiz, or a learning tool a little confetti can go a long way in turning your app from useful to joyful.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>How to Stop Page Reloads in JavaScript with event.preventDefault()</title>
      <dc:creator>dan</dc:creator>
      <pubDate>Sat, 28 Jun 2025 10:35:08 +0000</pubDate>
      <link>https://dev.to/dangote/how-to-stop-page-reloads-in-javascript-with-eventpreventdefault-39l5</link>
      <guid>https://dev.to/dangote/how-to-stop-page-reloads-in-javascript-with-eventpreventdefault-39l5</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;Have you ever clicked a "Submit" button on a form, only to see the whole page flash and reset? By default, HTML forms and links trigger a full page reload—but with one line of JavaScript, we can stop this behavior.&lt;/p&gt;

&lt;p&gt;In this post, you’ll learn how to use &lt;em&gt;event.preventDefault()&lt;/em&gt; to keep your page from reloading unnecessarily.&lt;/p&gt;

&lt;p&gt;Why Use &lt;em&gt;event.preventDefault()?&lt;/em&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Better User Experience: No jarring page refreshes.&lt;/li&gt;
&lt;li&gt;Faster Interactions: Handle form data without waiting for the server.&lt;/li&gt;
&lt;li&gt;Control: Run your own JavaScript logic before/after submission.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Step-by-Step Example
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;1. HTML Setup&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Create a basic form:&lt;/p&gt;

&lt;p&gt;&lt;em&gt;html&lt;/em&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;form id="noReloadForm"&amp;gt;
  &amp;lt;input type="text" placeholder="Type something" required&amp;gt;
  &amp;lt;button type="submit"&amp;gt;Submit&amp;lt;/button&amp;gt;
&amp;lt;/form&amp;gt;
&amp;lt;p id="demo"&amp;gt;&amp;lt;/p&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;2. JavaScript: Stop the Reload&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Add an event listener to the form:&lt;/p&gt;

&lt;p&gt;&lt;em&gt;javascript&lt;/em&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;document.getElementById("noReloadForm").addEventListener("submit", (event) =&amp;gt; {
  event.preventDefault(); // Magic line! Stops the reload.

  // Get the input value
  const inputValue = event.target.querySelector("input").value;

  // Display it on the page (no reload needed!)
  document.getElementById("demo").textContent = `Submitted: ${inputValue}`;

  console.log("Form submitted without reloading!");
});
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;3. Try It Out&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Type something in the input.&lt;/p&gt;

&lt;p&gt;Click "Submit".&lt;/p&gt;

&lt;p&gt;&lt;em&gt;No page reload!&lt;/em&gt; The text appears below the form instantly.&lt;/p&gt;

&lt;h2&gt;
  
  
  When to Use This
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Forms: Stop resets after submission.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Links: Prevent navigation (e.g., for a "Like" button).&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Buttons: Run custom JavaScript instead of default actions.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Pitfalls to Avoid
&lt;/h2&gt;

&lt;p&gt;⚠️ Don’t forget server-side validation!&lt;/p&gt;

&lt;p&gt;preventDefault() only stops the browser’s default behavior.&lt;/p&gt;

&lt;p&gt;Always validate data on the server for security.&lt;/p&gt;

&lt;p&gt;⚠️ Test accessibility:&lt;/p&gt;

&lt;p&gt;Ensure forms work without JavaScript (progressive enhancement).&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;With event.preventDefault(), you can:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Stop unwanted page reloads.&lt;/li&gt;
&lt;li&gt;Run custom JavaScript logic.&lt;/li&gt;
&lt;li&gt;Improve user experience.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Next Steps:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Try adding validation or an API call after event.preventDefault().&lt;/p&gt;

&lt;p&gt;Explore other event methods like stopPropagation().&lt;/p&gt;

</description>
    </item>
  </channel>
</rss>
