Reputation: 4134
I've got two relevant models; Item
and Category
, and I'm trying to write a data migration to place existing items into categories. The migration looks like this so far:
def categorise(apps, schema_editor):
Category = apps.get_model("orders", "Category")
Item = apps.get_model("orders", "Item")
some_category = Category.objects.create(name="Category name")
some_category.items.add(Item.objects.get(name="Item name"))
class Migration(migrations.Migration):
dependencies = [
('orders', '0005_populate'),
]
operations = [
migrations.RunPython(categorise)
]
And the (relevant parts of the) models look like this:
class Item(models.Model):
name = models.CharField(max_length=200)
class Category(models.Model):
name = models.CharField(max_length=200)
items = models.ManyToManyField(Item)
When I perform the migration listed above, though, I run into a type error on the last line of the categorise
function. It tells me TypeError: 'Item' instance expected, got <Item: Item object>
. That's odd, since they seem like the same type. I took care to import the Item
model via apps rather than through a regular import
in order to make sure it would be the same historical model definition that created the items currently in the database.
What could be the reason?
EDIT: Here are the relevant bits from the previous migrations. I now realise some of these originate from before I updated to Django 1.8. Is that relevant?
EDIT 2: As it turns out, running python manage.py migrate
twice in direct succession does fix the issue. What does that mean?
Update: this turned out to be a bug in 1.8, but will be fixed when the patch for ticket 24573 is merged.
0001:
class Migration(migrations.Migration):
dependencies = [
]
operations = [
migrations.CreateModel(
name='Item',
fields=[
('id', models.AutoField(serialize=False, verbose_name='ID', auto_created=True, primary_key=True)),
('name', models.CharField(max_length=200))
],
options={
},
bases=(models.Model,),
),
]
0002:
class Migration(migrations.Migration):
dependencies = [
('orders', '0001_initial'),
]
operations = [
migrations.CreateModel(
name='Category',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('name', models.CharField(max_length=200)),
('items', models.ManyToManyField(to='orders.Item'))
],
options={
},
bases=(models.Model,),
),
]
0003:
class Migration(migrations.Migration):
dependencies = [
('orders', '0002_category'),
]
operations = [
migrations.AlterField(
model_name='item',
name='discounts',
field=models.ManyToManyField(blank=True, to='orders.Discount'),
preserve_default=True,
),
]
0005:
def populate(apps, schema_editor):
Item = apps.get_model("orders", "Item")
def add_item(name):
item = Item.objects.create(name=name)
# ..
add_item("Item name", 160)
# .. etc
class Migration(migrations.Migration):
dependencies = [
('orders', '0004_auto_20150328_0929'),
]
operations = [
migrations.RunPython(populate)
]
Upvotes: 4
Views: 1887
Reputation: 53669
My guess is that you're on 1.7. and the models in apps
are not properly reloaded after a change from a previous migration has affected one of them. Handling of this is better in 1.8.
A workaround is to use directly add the primary key of Item
:
def categorise(apps, schema_editor):
Category = apps.get_model("orders", "Category")
Item = apps.get_model("orders", "Item")
some_category = Category.objects.create(name="Category name")
some_category.items.add(Item.objects.get(name="Item name").pk)
# or for multiple items
some_category.items.add(Item.objects.filter(...).values_list('pk', flat=True))
Upvotes: 4