3

I've been porting a Django project to Python 3 and Django 2. I have had to add on_delete to all my models with foreign keys as required in Django 2. Now I have tried to make migrations for those changes have been getting TypeError: __init__() missing 1 required positional argument: 'on_delete'.

The file it references is the 0002 migration file not the models file which has been updated. I am not sure how to go about fixing this. I have tried faking the migrations and I still get the same error.

I am not sure why it thinks the database doesn't exist, I have checked and everything is intact and working in Postgres. Any ideas?

halfer
  • 19,824
  • 17
  • 99
  • 186
Taylor
  • 1,223
  • 1
  • 15
  • 30
  • Yes, the `on_delete=` field on a `ForeignKey` and `OneToOneField` are now requires. You should fix the migration files. – Willem Van Onsem Jul 17 '19 at 22:01
  • Isn't that the point of making migrations so that they are added to the migrations? If I add them to previously ran migrations files such as 0002, how would that work? – Taylor Jul 17 '19 at 22:09
  • but you say you upgraded the Django version. So now you let a Django-2.0 framework interpret code written by a Django-1.x framework. Django is not 100% backwards compatible. The exceptions are listed in the release notes. In the previous versions of Django, these were not required. – Willem Van Onsem Jul 17 '19 at 22:11
  • I did upgrade versions and I also added the necessary field to the my models.py. Correct me if I am wrong but from what I understand 1) it should ignore 0002 file since it has already been ran and 2) when I update the models.py file make migrations should make the corresponding changes so they are documented for others to use. – Taylor Jul 17 '19 at 22:16
  • no the migration files are each time interpreted. Since the migration file calls the `ForeignKey` constructor it will error. The fact that you already applied them is irrelevant. Since Django will interpret these to make a *directed acyclic graph* that it will topologically sort to run migrations it might not have run yet. – Willem Van Onsem Jul 17 '19 at 22:18
  • the release notes even specify that you should update the migration files. They advice to squash the files, such that you can more easily perform a search-and-replace. – Willem Van Onsem Jul 17 '19 at 22:18
  • Your correct, thanks for the info. The actual informational part is in the release notes for 1.9 and not 2.0 you may want to add that to your answer. – Taylor Jul 17 '19 at 22:31
  • If I recall correctly it was marked "deprecated" since 1.9. But usually in Django something is deprecated for two released until it is actually removed, to give developers some time to adapt :). – Willem Van Onsem Jul 17 '19 at 22:34

1 Answers1

5

Since ForeignKey fields [Django-doc] and OneToOneField fields fields now have a required on_delete parameter.

This is specified in the release notes of Django-2.0 under Features removed in 2.0:

The on_delete argument for ForeignKey and OneToOneField is now required in models and migrations. Consider squashing migrations so that you have fewer of them to update.

You thus should inspect your migration files for ForeignKeys and OneToOneFields, and add an on_delete parameter, like:

class Migration(migrations.Migration):

    initial = False

    dependencies = [
        ('app', '0001_initial'),
    ]

    operations = [
        migrations.CreateModel(
            name='Model',
            fields=[
                ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
                ('some_foreignkey', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='app.OtherModel')),
            ],
        ),
    ]

You should inspect the documentation on the on_delete parameter to see what deletion strategy is the best for each situation. The options are, at the time of writing CASCADE, PROTECT, SET_NULL, SET_DEFAULT, SET(..), DO_NOTHING.

If you did not specify the on_delete in the pre- versions, it made a default to CASCADE. So if you want the same behavior, you should add on_delete=models.CASCADE. This is noted in the 1.11 version of the documentation on on_delete:

Deprecated since version 1.9: on_delete will become a required argument in Django 2.0. In older versions it defaults to CASCADE.

Willem Van Onsem
  • 443,496
  • 30
  • 428
  • 555
  • I had no luck with `django.db.models.deletion.CASCADE` (django-2.2.9), but plain `models.CASCADE` worked fine. This also seems to be what is suggested at https://docs.djangoproject.com/en/2.1/releases/1.9/#foreignkey-and-onetoonefield-on-delete-argument – Jan Kyu Peblik Jan 16 '20 at 20:09