Search code examples
pythondjangopython-3.xdjango-models

How to use a user as a ForeignKey in a Django model


I've got this model in my Django application:

class ClubSession(models.Model):
    location = models.CharField(max_length=200)
    coach = models.ForeignKey('auth.User', on_delete=models.CASCADE)
    date = models.DateTimeField(default=now)
    details = models.TextField()

    def __str__(self):
        return self.title

I can run python manage.py makemigrations club_sessions without issue but when I thn run python manage.py migrate club_sessions I get ValueError: Field 'id' expected a number but got 'username'. username is a superuser and already exists.

How do I resolve this?

This is the latest migration:

# Generated by Django 3.0.6 on 2020-05-28 15:07

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),
        ('club_sessions', '0004_auto_20200528_1450'),
    ]

    operations = [
        migrations.AlterField(
            model_name='clubsession',
            name='coach',
            field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL),
        ),
        migrations.AlterField(
            model_name='clubsession',
            name='location',
            field=models.CharField(max_length=200),
        ),
    ]

Solution

  • By default Django lets a ForeignKey refer to the primary key of the target model. This also has some advantages to make relations more uniform.

    If you really want to save the username in the ForeignKey, you can specify a to_field=… parameter [Django-doc] and let it refer to a column that is unique (the username of the default User model is unique), so we can refer to it with:

    from django.conf import settings
    
    class ClubSession(models.Model):
        location = models.CharField(max_length=200)
        coach = models.ForeignKey(
            settings.AUTH_USER_MODEL,
            on_delete=models.CASCADE,
            to_field='username'
        )
        date = models.DateTimeField(default=now)
        details = models.TextField()
    
        def __str__(self):
            return self.title

    You will need to remove the already existing migration and make a new one in order to migrate the database properly.

    Note: It is normally better to make use of the settings.AUTH_USER_MODEL [Django-doc] to refer to the user model, than to use the User model [Django-doc] directly. For more information you can see the referencing the User model section of the documentation [Django-doc].