Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

ValueError: Cannot assign User: issue on my OneToOneField relationship

Tags:

python

django

I'm facing a really odd problem with OneToOneField. I've a really simple model like

class Doctor(models.Model):
    user = models.OneToOneField(User)

The problem is with my method RunPython in the migration. I've written a 0002_addusers migration that depends on 0001_initial and the code is the following:

class Migration(migrations.Migration):
    def create_users(apps, schema_editor):
        u = User.objects.create_superuser('admin', '[email protected]', 'admin')
        u.save()

        du = User.objects.create_user(username='doc01', password='doc01')
        du.save()

def create_doctors(apps, schema_editor):
    Doctor = apps.get_model('custom_user', 'Doctor')
    du = User.objects.get(username='doc01')

    d = Doctor(user=du)
    d.save()

dependencies = [
    ('custom_user', '0001_initial')
]

operations = [
    migrations.RunPython(create_users),
    migrations.RunPython(create_doctors),
]

What is really weird for me is that this really simple code works in views, works in shell, works everywhere except in the migration :)

The traceback is the follow:

line 23, in create_doctors
d = Doctor(user=du)
...
ValueError: Cannot assign "<User: doc01>": "Doctor.user" must be a "User" instance.

Thank you a lot for any support!

EDIT: I found out the solution. I just had to call the RunPython

migrations.RunPython(create_users, create_doctor)

as Avinash suggested even without moving the functions outside the class.

It seems that subsequent functions have to be called as arguments of a single RunPython call.

like image 319
ennioma Avatar asked Apr 17 '15 13:04

ennioma


2 Answers

The suggested answer to run migrations.RunPython(create_users, create_doctor) doesn't solve your issue, it just makes it invisible.

The second argument of RunPython is the function that will be called during a rollback, this is why it did not raise any exception when migrating upwards. You never called the function create_doctors.

Your issue is caused by du not being a User instance. This can be caused in migrations when not using apps.get_model to get the model class. You should use the following code instead:

class Migration(migrations.Migration):
    def create_users(apps, schema_editor):
        User = apps.get_model('auth', 'User')  # Here you get the user programatically, it is a good practise in migrations
        u = User.objects.create_superuser('admin', '[email protected]', 'admin')
        u.save()

        du = User.objects.create_user(username='doc01', password='doc01')
        du.save()

    def create_doctors(apps, schema_editor):
        Doctor = apps.get_model('custom_user', 'Doctor')
        User = apps.get_model('auth', 'User')  # Here you get the user programatically, it is a good practise in migrations
        du = User.objects.get(username='doc01')

        d = Doctor(user=du)
        d.save()

    dependencies = [
        ('custom_user', '0001_initial')
    ]

    operations = [
        migrations.RunPython(create_users),
        migrations.RunPython(create_doctors),
    ]
like image 81
BrunoG Avatar answered Oct 21 '22 09:10

BrunoG


I think the problem is in your migration code. Define your methods outside the Migration class then call it from migration's RunPython command.

Try below code in your migration file. This will work.

def create_users(apps, schema_editor):
    u = User.objects.create_superuser('admin', '[email protected]', 'admin')
    u.save()

    du = User.objects.create_user(username='doc01', password='doc01')
    du.save()

def create_doctors(apps, schema_editor):
    Doctor = apps.get_model('custom_user', 'Doctor')
    du = User.objects.get(username='doc01')
    # We can't import the Doctor model directly, But we can create it. Try this - 
    Doctor.objects.create(user=du)

class Migration(migrations.Migration):

    dependencies = [
        ('custom_user', '0001_initial')
    ]

    operations = [
        migrations.RunPython(create_users, create_doctors),
    ]
like image 2
Avinash Kr Mallik Avatar answered Oct 21 '22 08:10

Avinash Kr Mallik