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!
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.
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.
makemigrations is responsible for packaging up your model changes into individual migration files - analogous to commits - and migrate is responsible for applying those to your database.
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.
By doing python manage.py migrate app B (or A; both works) . Remove the migration files A and Y for time being from the project location. Now unapply B, by doing python manage.py migrate app X .
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
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With