Antoine Quellier
Antoine Quellier

Reputation: 152

How to override M2M field names and models in Django with an existing database?

I'm using Django 3.1.3 and working with an existing postgresql database. Most of the models and fields names of this DB are badly chosen and/or way too long. Most of the time its easy to change them with some handy Django options like so :

class NewModelName(models.Models):

    new_field_name = models.CharField(max_length=50, db_column='old_field_name')

    class Meta:
        managed=False
        db_table='database_old_table_name'

But let say I want to change a M2M field name and the corresponding model name. I'd like to have something like :

class Foo(models.Models):

    new_m2m_field_name = models.ManyToManyField('RelatedModel', blank=True, db_column='old_m2m_field_name')

    class Meta:
        managed=False
        db_table='foo_old_table_name'


class RelatedModel(models.Models):

    name = models.CharField(max_length=50)

    class Meta:
        managed=False
        db_table='related_model_old_table_name'

But if I do that, Django will throw an error stating django.db.utils.ProgrammingError: relation "foo_new_m2m_field_name" does not exist. It is like it is ignoring the db_column option. Any idea how I could get to a similar result ?

Thanks!

Upvotes: 1

Views: 800

Answers (3)

Henri
Henri

Reputation: 801

You could add a property db_table (link)

linking to the previous table, named foo_old_table_name in your case. According to the doc,

By default, this table name is generated using the name of the many-to-many field and the name of the table for the model that contains it

So for the field new_m2m_field_name, the previous table making the link was named : old_field_name_database_old_table_name. Hence :

new_field_name = models.CharField(max_length=50, db_column='old_field_name', db_table='old_field_name_database_old_table_name')

The option through could be changed too, but I do not think it is necessary if the modifications on names are coherent.

Upvotes: 1

AKX
AKX

Reputation: 169051

You will probably need to manually define the Through model (that Django would otherwise implicitly create behind the scenes) in order to make it unmanaged.

class Foo(models.Models):

    new_m2m_field_name = models.ManyToManyField(
        "RelatedModel",
        blank=True,
        db_column="old_m2m_field_name",
        through="FooRelatedJoin",  # <- new
    )

    class Meta:
        managed = False
        db_table = "foo_old_table_name"


class RelatedModel(models.Models):

    name = models.CharField(max_length=50)

    class Meta:
        managed = False
        db_table = "related_model_old_table_name"


class FooRelatedJoin(models.Models):  # <- all new
    foo = models.ForeignKey(Foo)
    related_model = models.ForeignKey(RelatedModel)

    class Meta:
        managed = False
        db_table = "foo_join_table"

Upvotes: 1

iklinac
iklinac

Reputation: 15738

From Django documentation regarding ManyToManyField

ManyToManyField.db_table The name of the table to create for storing the many-to-many data. If this is not provided, Django will assume a default name based upon the names of: the table for the model defining the relationship and the name of the field itself.

Also depending on column names (non standard names) in original database you might have to define through model ( pivot table) as through table

Upvotes: 2

Related Questions