djangosqlitedjango-modelsgeodjangodjango-4.0

Django 4: How to modify MultiPolygonField from nullable to not-null


I am trying to convert my MultiPolygonField field from this:

multipolygon = MultiPolygonField(null=True)

to this:

multipolygon = MultiPolygonField(null=False)

It looks simple, so I execute "makemigrations" and I get the usual message warning that the database needs something to populate existing rows (I confirmed that there is no row in my database with that field being null):

Whether I choose option 1:

  1. Provide a one-off default now (will be set on all existing rows with a null value for this column)

And set the following as default:

'SRID=3857;POINT(0.0 0.0)'

or option 2:

  1. Ignore for now. Existing rows that contain NULL values will have to be handled manually, for example with a RunPython or RunSQL operation

I get the following error when I execute "migrate":

ValueError: Cannot alter field borders.Border.multipolygon into borders.Border.multipolygon - they do not properly define db_type (are you using a badly-written custom field?)

I have been able to make that same change with other simpler field types without any issue. How to do this with MultiPolygonFields? I am using Django 4 and sqlite 3.31, in case that matters.


Solution

  • This is how I finally "solved" the issue (not exactly solved, but I found a longer way to get the same results):

    I divided the migration in 6 steps:

    1. I created a new field "multipolygon_new"
    2. I copied data from my initial field "multipolygon" to the new one I just created "multipolygon_new"
    3. I deleted my initial field, "multipolygon"
    4. I created "multipolygon" again, but being not-null
    5. I copied data from "multipolygon_new" to ""multipolygon"
    6. I deleted "multipolygon_new"

    For steps 2 and 5 used the following command to create a custom migration:

    python manage.py makemigrations --empty yourappname
    

    and then I modified the migration file to execute my custom copy query:

    migrations.RunSQL(
        sql=[("UPDATE mytable ......", ],
    )
    

    for the other steps I used the usual makemigrations command.