Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Migration clashes with forms.py

The command python manage.py makemigrations fails most of time due to the forms.py, in which new models or new fields are referenced at class definition level.

So I have to comment each such definitions for the migration to operate. It's a painfull task.

I don't understand why the migration process import the forms.py module. I think that importing models modules should be sufficient.

Is there a way to avoid those errors ?

like image 368
albar Avatar asked Sep 16 '16 16:09

albar


People also ask

Does Django handle migrations?

Django can't automatically generate data migrations for you, as it does with schema migrations, but it's not very hard to write them. Migration files in Django are made up of Operations, and the main operation you use for data migrations is RunPython .

What is the difference between Makemigrations and migrate in Django?

So the difference between makemigrations and migrate is this: makemigrations auto generates migration files containing changes that need to be applied to the database, but doesn't actually change anyhting in your database. migrate will make the actual modifications to your database, based on the migration files.

What is Django fake migration?

Django Migrations Fake migrations When a migration is run, Django stores the name of the migration in a django_migrations table. Create and Fake initial migrations for existing schema. If your app already has models and database tables, and doesn't have migrations. First create initial migrations for you app.


2 Answers

I was having this same issue and found the specific problem. When the migrate command was being called, Django's system checks made their way into my forms.py and then would fail when they encountered a line of code that made a query against a table that the migration was supposed to create. I had a choicefield that instantiated the choices with a database query like this:

university = forms.ChoiceField(
    choices=[('', '')] + [(university.id, university.name) for university in University.objects.all()],
    widget=forms.Select(
        attrs={
            'class': 'form-control',
            'placeholder': 'University',
        }
    ),
    required=True
)

The solution was to remove the query from choices (leaving it just as [('', '')] and then populate the choices in the class's init method instead.

class UniversityForm(forms.Form):

    university = forms.ChoiceField(
        choices=[('', '')],
        widget=forms.Select(
            attrs={
                'class': 'form-control',
                'placeholder': 'University',
            }
        ),
        required=True
    )


def __init__(self, *args, **kwargs):
    super(UniversityForm, self).__init__(*args, **kwargs)

    # Load choices here so db calls are not made during migrations.
    self.fields['university'].choices = [('', '')] + [(university.name, university.name) for university in University.objects.all()]
like image 74
Nate Avatar answered Oct 03 '22 20:10

Nate


Thanks to @alasdair I understood my problem and found a workaround: I replace the original code in the views.py file

from MyApp import forms

with

import sys
if 'makemigrations' not in sys.argv and 'migrate' not in sys.argv:
    from MyApp import forms

It works fine in my case, but I suppose there is a better way to know if the current process is a migration or not. If so, please advise.

like image 36
albar Avatar answered Oct 03 '22 20:10

albar