简体   繁体   中英

Django detecting redundant migrations repetitively

Background

We are working in Python3.4 / Django1.8.4 and we are witnessing a strange phenomenon with respect to our user model, and specifically the timezone field of this model.

Every so often when we are making migrations the new migration file will include an operation to alter said timezone field, but all of the attributes that are included in the operation are already set to the same values that the migration is trying to assign!

There are 3 such fields and they are:

1) default - with the value of "UTC"

2) max_length - with the value of 30 , and

3) choices - a very long array of tuples containing time zone names/values.

It looks like:

choices=[('Africa/Abidjan', 'Africa/Abidjan'), ('Africa/Accra', 'Africa/Accra'), ('Africa/Addis_Ababa', 'Africa/Addis_Ababa'), ... ]

The migration operation always wants to set these 3 properties of the timezone field to the exact same 3 corresponding values, even though they are already set to such values, It is essentially a redundant. useless operation.

Sometimes when we run makemigrations there will be no changes to the app, except to this silly field!

Questions

1) Why is this happening?

2) How do we prevent this? It's annoying that the app thinks migrations are needed when they aren't.

Extra Info

While the same 3 properties of the field are always set to the exact same values, the order that they appear in the operation seems to be non-deterministic (likely because django uses unordered dict instances to store the data which is used to generate the migration file).

The choices field, as we define it in our model, is dynamically generated when the app is initially run. The (boiled-down) code looks like this:

class MyUser(models.Model):
    f_name = models.CharField(max_length=32398) # Gotta accomodate those crazy south-eastern names haha
    l_name = models.CharField(max_length=94823)

    # ...
    # more fields and stuff etc.
    # ...

    time_zone = models.CharField(default="UTC", choices=TIMEZONE_CHOICES, max_length=30)

The important part there is that choices=TIMEZONE_CHOICES , which is defined earlier as such:

import pytz
TIMEZONE_CHOICES = ()
for time_zone in pytz.common_timezones:
    TIMEZONE_CHOICES += ((time_zone, time_zone),)

Just including this information in case it turns out to be relevant.

Try to copy the plain list of timezones from pytz to your project, so you are sure that choices does not depends from a third party

You could try using an existing package that will allow you to use a time zone directly as a model field.

https://pypi.python.org/pypi/django-timezone-field/

class MyModel(models.Model):
    timezone1 = TimeZoneField(default='Europe/London') # defaults supported

Your timezones are probably coming out in different orders on different runs. Try

import pytz
TIMEZONE_CHOICES = ()
for time_zone in pytz.common_timezones:
    TIMEZONE_CHOICES += ((time_zone, time_zone),)
TIMEZONE_CHOICES = sorted(TIMEZONE_CHOICES) # sort list to make it consistent

Also--a minor nit since this only runs at startup--but building up a big tuple with repeated concatenation is probably a lot more expensive than this

import pytz
TIMEZONE_CHOICES = sorted((tz,tz) for tz in pytz.common_timezones)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM