Django 1.11中外键为何需默认值?迁移遇非空报错
Let me break down why you're seeing this error and how to fix it—it's a common gotcha when working with non-nullable ForeignKeys in Django.
Why the default value is required
Django asks for a default value because if your Credit table already exists in the database, there are existing records that don't have a user value set, and you're making the user field non-nullable. When running makemigrations, Django needs to populate this field for all existing rows to satisfy the database's non-null constraint—it can't leave those fields empty.
This has nothing to do with your goal of associating new Credit instances with the current active user; it's purely a database consistency requirement for existing data.
How to resolve this
You have a few options depending on whether you already have Credit records in your database:
Option 1: No existing Credit records yet
If you haven't created any Credit entries and this is the first time adding this field, double-check your migration history. If the Credit table doesn't exist yet, Django won't ask for a default value because there's no data to populate. Just run makemigrations and migrate normally.
Option 2: You have existing Credit records
Sub-option A: Use a temporary default value
Pick an existing user (like your superuser) to assign to all existing Credit records temporarily:
- Update your
Creditmodel'suserfield to include a default (replace1with the ID of a valid user in your database):user = models.ForeignKey(settings.AUTH_USER_MODEL, default=1) - Run
makemigrationsandmigrate—this will populate all existingCreditrows with the user ID you specified. - Once the migration is done, remove the
defaultargument from the field:user = models.ForeignKey(settings.AUTH_USER_MODEL) - Run
makemigrationsandmigrateagain to remove the default constraint from the database.
Sub-option B: Temporarily allow null values (then backfill)
If you don't want to assign a random user to existing records, you can temporarily make the field nullable:
- Update the
userfield to allow nulls:user = models.ForeignKey(settings.AUTH_USER_MODEL, null=True) - Run
makemigrationsandmigrate—this adds the field without enforcing non-null yet. - Manually backfill the
userfield for all existingCreditrecords (you can do this via the Django admin, a management command, or the shell). - Once all records have a
uservalue, remove thenull=Trueargument:user = models.ForeignKey(settings.AUTH_USER_MODEL) - Run
makemigrationsandmigrateagain to enforce the non-null constraint.
Associating new Credit instances with the current active user
As for your original goal of linking new Credit entries to the current logged-in user, that's handled in your view logic, not the model's default. When creating a Credit instance, use request.user (assuming you're in a view with access to the request):
from django.shortcuts import render, redirect from .models import Credit def add_credit(request): if request.method == 'POST': # Create Credit instance linked to current user Credit.objects.create( user=request.user, name=request.POST['name'], payment_reference=request.POST['payment_reference'], amount=request.POST['amount'], # Fill in other required fields ) return redirect('credit_list') return render(request, 'add_credit.html')
This way, every new Credit you create will automatically be tied to the active user, and the migration-time default was just a one-time fix for existing data.
内容的提问来源于stack exchange,提问作者Phillip Smith

