Lead-up:
I subclassed django.db.models.fields.CharField. Then used that custom field called myapp.models.QueryStringField in a model and made my migrations and migrated successfully. Then I changed my mind and decided to replace it with a normal CharField in my model, which I did (again with successfull migration).
Problem:
When I then deleted the QueryStringField class entirely from myapp.models and did makemigrations, it threw the following error (last lines shown here):
File "C:\...\migrations\00....py", line 17, in Migration
field=myapp.models.QueryStringField(max_length=255),
AttributeError: module 'myapp.models' has no attribute 'QueryStringField'
What can I do to fix this? I understand that this is technically correct, since the migration references a class that is not present, but surely this can be solved somehow. I am a little nervous about just deleting migration files.
You can not just delete a field class, that class is referenced by the migration files.
You should change the migration files where the QueryStringField is involved. You can inspect the migration where you changed the field, and remove that part of the migration, so:
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('someapp', '1234_some_name'),
]
operations = [
# migrations.AlterField(
# model_name='mymodel',
# name='myfield',
# field=models.QueryStringField(
# # ...
# ),
# ),
]
as well as in the migration where you change it back:
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('someapp', '5678_some_other_name'),
]
operations = [
# migrations.AlterField(
# model_name='mymodel',
# name='myfield',
# field=models.CharField(
# # ...
# ),
# ),
]
After you removed these changes (and all changes that thus work with the QueryStringField), you can safely remove it.
Related
I'm trying to rename a model field name without any impact on the DB using db_colum.
My model before:
class Foo(models.Model)::
old_name = models.CharField()
My model after:
class Foo(models.Model)::
new_name = models.CharField(db_column="old_name")
I generated a migration and Django guessed that I have renamed the field. The migration looks like:
class Migration(migrations.Migration):
dependencies = [
("fooapp", "0001_bar"),
]
operations = [
migrations.RenameField(
model_name="foo", old_name="old_name", new_name="new_name",
),
migrations.AlterField(
model_name="foo",
name="new_name",
field=models.CharField(db_column="old_name"),
),
]
Everything is working fine. I try the migration and it is ok. But if I take a look at the SQL generated (with ./manage.py sqlmigrate), I see:
--
-- Rename field old_name on foo to new_name
--
ALTER TABLE "fooapp_foo" RENAME COLUMN "old_name" TO "new_name";
--
-- Alter field new_name on foo
--
ALTER TABLE "fooapp_foo" RENAME COLUMN "new_name" TO "old_name";
I don't get why the migration does that instead of doing nothing. Is there a way to avoid that?
It does seem that Django migration engine has produced unnecessary migration commands/steps ( should be reported as Bug )
In meantime you could edit migration to avoid these queries from being executed by making custom RunSQL replacement for these migration operations
Something in a line of
migrations.RunSQL(
migrations.RunSQL.noop,
state_operations=[
migrations.RenameField(
model_name="foo", old_name="old_name", new_name="new_name",
),
migrations.AlterField(
model_name="foo",
name="new_name",
field=models.CharField(db_column="old_name"),
),
],
)
With Django 1.11, I am trying to add a new column that is conditioned on other columns (as shown in the below image) and view it at front-end. This link is the closest example but I would like to implement it in Django. How can we do this?
I suggest implement this action on the migration file:
After you changed model, execute ./manage.py makemigrations
Open new migration file in editor, content of this file maybe is similar as below:
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [('migrations', '0001_initial')]
operations = [
migrations.AddField('MyModel', 'A_islargerthan_B', models.BooleanField(default=False)),
]
Now you must inject your updater code by using migrations.RunPython :
from django.db import migrations, models
def update_A_islargerthan_B(apps, schema_editor):
MyModel = apps.get_model('my_app', 'MyModel')
for obj in MyModel.objects.all():
obj.A_islargerthan_B = obj.column_A > obj.column_B
obj.save()
class Migration(migrations.Migration):
dependencies = [('migrations', '0001_initial')]
operations = [
migrations.AddField('MyModel', 'A_islargerthan_B', models.BooleanField(default=False)),
migrations.RunPython(update_A_islargerthan_B),
]
Run ./manage.py migrate
Read more about Django migrations
I have a migrations come from the work of another person, and I'm in on a code base controlled by the version too. I created a migration file after adding a new field but the problem is in the data migration (0003_datamigration_initial_service_configuration.py)that is created before through the function get_or_create () is executed in the head of the list while my migration file data in the end I should not change a migration already developed.
This is my list of migrations
0001_initial.py
0002_datamigration_initial_users_list.py
0003_datamigration_initial_mymodel.py
...
0015.addnewfield
0003_datamigration_initial_mymodel.py:
from __future__ import unicode_literals
from django.db import migrations
from ..models import MyModel
def create_initial_mymodel(apps, schema_editor):
current_product_type, created = MyModel.objects.get_or_create()
class Migration(migrations.Migration):
dependencies = [
('myapp', '0002_datamigration_initial_users_list'),
]
operations = [
migrations.RunPython(create_initial_mymodel),
]
Rhe error is no such column named new_field
How can I fix the problem without editing any data migrations?
You should use apps.get_model to get the MyModel model, instead of importing it directly.
def create_initial_mymodel_forward(apps, schema_editor):
MyModel = apps.get_model('myapp', 'MyModel')
current_product_type, created = MyModel.objects.get_or_create()
Using apps.get_model will load a historical version of the model with the correct fields.
I have 2 django apps i.e. main and authtools. When I run
python manage.py migrate
, I get a CircularDependencyError:
raise CircularDependencyError(", ".join("%s.%s" % n for n in cycle))
django.db.migrations.graph.CircularDependencyError: main.0001_initial, authtools.0001_initial
In my setting file I have the AUTH_USER_MODEL defined as such:AUTH_USER_MODEL = 'authtools.User' . The migration files created look like this:
For the authtools app, it shows dependancies as:
dependencies = [
('main', '__first__'),
('auth', '0001_initial'),
]
And for the main app, the depandancies are shown as:
dependencies = [
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
]
What could be wrong?
If you use ManyToMany + 'through' option to different application, than according to this answer you should:
Comment a whole line where you use ManyToMany+through by putting #
at the beginning of the line
makemigrations of_all_apps_you_need (also the one where the line from p1 exist)
uncomment the line from p1
makemigrations the_app_where_the_line_from_p1_exist
migrate
If you dont use ManyToMany, than according to this answer, try similar actions.
Lets suppose that you want to create these models:
libros/models.py:
class Libro(models.Model):
name = models.CharField(max_length=20)
perfile = models.ForeignKey('perfiles.Perfile', null=True)
perfiles/models.py:
class Perfile(models.Model):
name = models.CharField(max_length=20)
libro = models.ForeignKey('libros.Libro', null=True)
Of course you can't do it because of the circular dependency. So comment out foreign key in the Libro model:
class Libro(models.Model):
name = models.CharField(max_length=20)
# perfile = models.ForeignKey('perfiles.Perfile', null=True)
And run two migrations:
python manage.py makemigrations libros
python manage.py makemigrations perfiles
After that uncomment the perfile foreign key in the Libro model and run another migration:
python manage.py makemigrations libros
I think you need to follow this ticket of django code base: https://code.djangoproject.com/ticket/22932
According to them your migration code should look like either this (https://code.djangoproject.com/attachment/ticket/22932/team.0001_initial.py.diff) or(https://code.djangoproject.com/attachment/ticket/22932/team.0002_auto_20140704_1453.py):
# -*- coding: utf-8 -*-
2 from __future__ import unicode_literals
3
4 from django.db import models, migrations
5 from django.conf import settings
6
7
8 class Migration(migrations.Migration):
9
10 dependencies = [
11 migrations.swappable_dependency(settings.AUTH_USER_MODEL),
12 ('team', '0001_initial'),
13 ]
14
15 operations = [
16 migrations.CreateModel(
17 name='TeamCaptain',
18 fields=[
19 ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
20 ('rider', models.ForeignKey(to=settings.AUTH_USER_MODEL)),
21 ('team', models.ForeignKey(to='team.Team')),
22 ],
23 options={
24 },
25 bases=(models.Model,),
26 ),
27 ]
The idea with migrations is that you have to plan the workflow that Django needs to follow when applying your models.
Let's say you have two models and each of one has a ForeignKey to the other one. You cannot create these two models and makemigrations. You have to apply them step by step. First apply one model without the relation to the other one, then the other model (now, the relation to the first one can be kept) and then the first model's relation to the second. Think logical. It's impossible to write a model which relies on another one without having the second one.
But this has to be done just for the first migrations creation process (e.g. a new application without any migration). Then you just maintain and update your models.
I've experienced the same issue and was able to resolve it by interchanging the order of makemigration command.
Using TitanFighter's example. There's no need to escape model fields, instead makemigration for perfiles first then migrations for libros.
Hopefully this helps someone.
I'm trying to create a auth.Group with permissions automaticly with migrations. My problem is that when I run migrate on empty database the migration that tries to attach permission to the group can't find the permission. If I target an earlier migration so that migrate exits without an error the permissions appear into the database and after that the migration code can find the permission. So what can I do so that the migration can reference a permission which is created in an earlier migration when the migrations are run back to back?
def load_data(apps, schema_editor):
Permission = apps.get_model('auth', 'Permission')
Group = apps.get_model('auth', 'Group')
can_add = Permission.objects.get(codename='add_game')
developers = Group.objects.create(name='Developer')
developers.permissions.add(can_add)
developers.save()
class Migration(migrations.Migration):
dependencies = [
('myApp', '0004_game'),
]
operations = [
migrations.RunPython(load_data),
]
The game model is created in an earlier migration. This code causes always an error stating that Permission matching query does not exist when I run it with other migrations on an empty database.
I'm using python 3.4 with django 1.7.2
Oh. 4 years later...
To create permissions Django uses post_migrate signal.
Therefore, when running all migrations at a time, permissions do not yet exist.
Therefore, you can take out your function, for example, in the management command.
However, you can still do it like this:
from django.contrib.auth.management import create_permissions
APPS = [
...your app labels
]
def create_applications_permissions():
for app in APPS:
app_config = django_apps.get_app_config(app)
create_permissions(app_config)
def load_data(apps, schema_editor):
create_applications_permissions()
Permission = apps.get_model('auth', 'Permission')
Group = apps.get_model('auth', 'Group')
can_add = Permission.objects.get(codename='add_game')
developers = Group.objects.create(name='Developer')
developers.permissions.add(can_add)
developers.save()
class Migration(migrations.Migration):
dependencies = [
('myApp', '0004_game'),
]
operations = [
migrations.RunPython(load_data),
]
And to create permissions do not use apps passed to the migration. Will not pass the check in create_permissions:
if not app_config.models_module:
return
But you have to be careful.
I hope someone will be useful.