Reputation: 11
I am having an issue writing a custom django migration where I am trying to set a field value for a model to a user. The model in question is shown below (CustomerMachine). This model uses the django-simple-history module to track changes in model instances. I am attempting to query the instance history in the migration and set the review_submitter value to the last user which edited the instance. The result of the history query history_user returns a <class 'django.contrib.auth.models.User'> type, but when I try to set the review_submitter to that value I get the following error: ValueError: Cannot assign "<User: user.name>": "CustomerMachine.review_submitter" must be a "User" instance. Any insight into whats going on here?
simplified class example
class CustomerMachine(models.Model):
review_submitter = models.ForeignKey(settings.AUTH_USER_MODEL, default=None)
history = HistoricalRecords()
custom migration
from __future__ import unicode_literals
from __future__ import absolute_import
from django.conf import settings
from django.db import migrations, models
from django.contrib.auth.models import User
from acceptance.models import CustomerMachine
def set_submitter(apps, schema_editor):
machines = apps.get_model('acceptance', 'CustomerMachine')
for machine in machines.objects.all():
history = CustomerMachine.history.filter(serial=machine.serial)
if history:
history_user = history.last().history_user
machine.review_submitter = history_user
machine.save()
def reverse_func(apps, schema_editor):
pass # code for reverting migration, if any
class Migration(migrations.Migration):
dependencies = [
('acceptance', '0031_auto_20200914_1611'),
]
operations = [
migrations.RunPython(set_submitter, reverse_func),
]
migration 0031_auto_20200914_1611
from __future__ import unicode_literals
from django.conf import settings
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
('acceptance', '0030_auto_20191218_1927'),
]
operations = [
migrations.AddField(
model_name='customermachine',
name='review_submitter',
field=models.ForeignKey(default=None, on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL),
),
migrations.AddField(
model_name='historicalcustomermachine',
name='review_submitter',
field=models.ForeignKey(blank=True, db_constraint=False, default=None, null=True, on_delete=django.db.models.deletion.DO_NOTHING, related_name='+', to=settings.AUTH_USER_MODEL),
),
]
Upvotes: 0
Views: 979
Reputation: 590
The problem is that you are trying to import model into the migration directly:
from acceptance.models import CustomerMachine
In migrations you can only get models like that:
machines = apps.get_model('acceptance', 'CustomerMachine')
This model can be used later:
history = machines.history.filter(serial=machine.serial)
instead of:
history = CustomerMachine.history.filter(serial=machine.serial)
The thing is that in migrations you don't have access to classic models with their state and when you do machines = apps.get_model('acceptance', 'CustomerMachine')
you are getting <class '__fake__.CustomerMachine'>
which is not your CustomerMachine
(you can check with pdb in you migration). And when you are trying mixing you standard models with the "fake" equivalents you have the errors like you described.
Upvotes: 0