Hamed Salimian
Hamed Salimian

Reputation: 881

Geodjango: Change PolygonField to MultiPolygonField with exisiting data using a migration

I have a model with a PolygonField, which had dozens of rows. I am trying to change the field to MultiPolygonField, but data is still in polygon mode. How can I convert all existing data to the new type?

models.py:

class Region(models.Model):
    class Meta:
        verbose_name = _("region")
        verbose_name_plural = _("regions")

    polygon = models.PolygonField(_("polygon"))  # <== this is going to be MultiPolygon
    name = models.CharField(_("name"), max_length=100)

Upvotes: 1

Views: 1872

Answers (1)

Udi
Udi

Reputation: 30482

Option 1: Use SQL

Assuming you are using postgis, the following SQL can convert your data by using ST_Multi:

ALTER TABLE myapp_region
    ALTER COLUMN polygon TYPE geometry(MultiPolygon, 4326)
    USING ST_Multi(polygon);

Do not execute this directly, instead run makemigrations which will create a new migration (for example: myapp/migrations/0006_yyyyyyyy.py) similar to:

import django.contrib.gis.db.models.fields
from django.db import migrations


class Migration(migrations.Migration):

    dependencies = [
        ('myapp', '0005_zzzzzzzzzzzzz'),
    ]

    operations = [
        migrations.AlterField(
            model_name='region',
            name='polygon',
            field=django.contrib.gis.db.models.fields.MultiPolygonField(srid=4326),
        ),
    ]

Encapsulate your AlterField opertaions with a RunSQL operation like this:

operations = [
    migrations.RunSQL(
        "ALTER TABLE myapp_region ALTER COLUMN polygon type geometry(MultiPolygon, 4326) using ST_Multi(polygon);",
        state_operations=[
            migrations.AlterField(
                model_name='region',
                name='polygon',
                field=django.contrib.gis.db.models.fields.MultiPolygonField(
                    srid=4326),
            ),
        ],
    )
]

and now run your migration.

Option 2: Data Migrations

  • Create a new geom = models.MultiPolygonField(null=True) field next to your current field.
  • Create and run a migration to add the new multipolygon field.
  • Create a data migration and use RunPython to copy your data:

    for o in Region.objects.all():
        o.geom = MultiPolygon([o.polygon])
        o.save()
    

    (Untested: You might be able to use Region.objects.update() instead)

  • In models.py, delete the original field and remove null=True; create a migration.
  • Optional: rename geom to polygon with another migration.

Upvotes: 3

Related Questions