<?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: Jayson Gellido</title>
    <description>The latest articles on DEV Community by Jayson Gellido (@jayson_gellido_0e72103fd0).</description>
    <link>https://dev.to/jayson_gellido_0e72103fd0</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%2F3540466%2Fc43c8c60-0d9f-4955-88fc-7e80197aa0eb.png</url>
      <title>DEV Community: Jayson Gellido</title>
      <link>https://dev.to/jayson_gellido_0e72103fd0</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/jayson_gellido_0e72103fd0"/>
    <language>en</language>
    <item>
      <title>Migrating Django from MySQL to Oracle: Handling Existing Tables and Many-to-Many Relationships</title>
      <dc:creator>Jayson Gellido</dc:creator>
      <pubDate>Tue, 30 Sep 2025 20:14:05 +0000</pubDate>
      <link>https://dev.to/jayson_gellido_0e72103fd0/migrating-django-from-mysql-to-oracle-handling-existing-tables-and-many-to-many-relationships-5anh</link>
      <guid>https://dev.to/jayson_gellido_0e72103fd0/migrating-django-from-mysql-to-oracle-handling-existing-tables-and-many-to-many-relationships-5anh</guid>
      <description>&lt;p&gt;Migrating a Django project from MySQL to Oracle can be tricky, especially when your Oracle database already has existing tables with data. In this post, I’ll share a real-world problem I faced and how I solved it, so other developers can avoid similar headaches.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The Problem&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;While migrating a Django project from MySQL to Oracle, I ran into two major issues:&lt;/p&gt;

&lt;p&gt;ORA-00955: name is already used by an existing object&lt;br&gt;
This happens when Django tries to create a table that already exists in Oracle. Unlike MySQL, Oracle is case-sensitive when using quoted identifiers.&lt;/p&gt;

&lt;p&gt;ORA-00942: table or view does not exist&lt;br&gt;
This occurs when Django expects a table to exist with a certain name, but Oracle either doesn’t have it or Django’s default naming (lowercase, no quotes) doesn’t match Oracle’s actual table name (usually uppercase).&lt;/p&gt;

&lt;p&gt;Many-to-Many Fields in Oracle&lt;/p&gt;

&lt;p&gt;For example, I had a Profile model with several ManyToManyFields:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;class Profile(models.Model):
    account_assignment = models.ManyToManyField(AccountModel, blank=True)
    bypass_po_box_restriction = models.ManyToManyField(AccountModel, blank=True)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After migrating to Oracle, Django couldn’t find the join tables, giving the ORA-00942 error.&lt;/p&gt;

&lt;p&gt;Oracle automatically converts unquoted table names to uppercase, so the join tables were actually named something like:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;PROFILE_PROFILE_ACCOUNT_ASSIGNMENT&lt;br&gt;
PROFILE_PROFILE_BYPASS_PO_BOX_RESTRICTION&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The Fix&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;There are two key steps:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Use db_table for Many-to-Many fields&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;You can tell Django to use the exact table name that exists in Oracle:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;class Profile(models.Model):
    account_assignment = models.ManyToManyField(
        AccountModel,
        blank=True,
        db_table='"PROFILE_PROFILE_ACCOUNT_ASSIGNMENT"'
    )
    bypass_po_box_restriction = models.ManyToManyField(
        AccountModel,
        blank=True,
        db_table='"PROFILE_PROFILE_BYPASS_PO_BOX_RESTRICTION"'
    )
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Note the double quotes "...". Oracle treats quoted identifiers as case-sensitive, so this ensures Django uses the correct table.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Use db_table in the model Meta for normal tables&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;For other models that already exist in Oracle, like:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;MAIN_SHIPPINGCARRIERSERVICESMODEL&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;You can specify the table name directly in Meta:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;class ShippingCarrierServicesModel(models.Model):
    # fields...

    class Meta:
        db_table = 'MAIN_SHIPPINGCARRIERSERVICESMODEL'
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If the table was created without quotes, you don’t need extra quotes in db_table.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Key Takeaways&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Oracle is case-sensitive with quoted identifiers, so always check how your tables were created.&lt;/p&gt;

&lt;p&gt;Use db_table in Django models to point to existing tables, avoiding unnecessary migrations or table creation errors.&lt;/p&gt;

&lt;p&gt;For many-to-many join tables, db_table is crucial if you’re working with an existing schema.&lt;/p&gt;

&lt;p&gt;Always check the actual table names in Oracle:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;SELECT table_name FROM user_tables;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Conclusion&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Migrating Django projects from MySQL to Oracle is not just a matter of changing the database driver. Table naming conventions, many-to-many relationships, and Oracle’s case sensitivity can create unexpected errors.&lt;/p&gt;

&lt;p&gt;Using db_table strategically allows you to work with existing Oracle tables without rewriting your entire schema or losing data.&lt;/p&gt;

</description>
      <category>django</category>
      <category>oracle</category>
      <category>adw</category>
      <category>python</category>
    </item>
  </channel>
</rss>
