自定义Django User模型引发外键约束错误及产品添加失败问题
问题排查与解决方案
一、Admin删除OTP/User时的外键约束错误
核心原因
- 重复定义password字段:
AbstractUser继承自AbstractBaseUser,已自带加密的password字段,手动添加同名字段会导致数据库字段冲突,触发约束异常。 - ManyToManyField反向关联名重复:
groups和user_permissions使用同一个related_name='myuser_set',导致数据库关联表的反向查询逻辑冲突,删除操作时触发外键约束失败。 - username字段配置错误:仅设置
username = ''未正确覆盖AbstractUser中username的唯一性约束,引发数据库结构异常。
修复代码
修改自定义User模型:
from django.contrib.auth.base_user import BaseUserManager from django.db import models from django.contrib.auth.models import AbstractUser class MyUserManager(BaseUserManager): # 保持原代码不变... class User(AbstractUser): # 修正username:取消唯一性,设为可选字段 username = models.CharField(max_length=150, unique=False, blank=True, null=True) name = models.CharField(max_length=255) email = models.EmailField( verbose_name='Email', max_length=255, unique=True, ) is_analyst = models.BooleanField(default=False) DOB = models.DateField() gender_choices = (('M', 'Male'), ('F', 'Female')) gender = models.CharField(max_length=1, choices=gender_choices) city_code = models.CharField(max_length=2) # 移除重复的password字段(AbstractUser已自带) # password = models.CharField(max_length=255) is_active = models.BooleanField(default=True) is_admin = models.BooleanField(default=False) first_name = None last_name = None USERNAME_FIELD = 'email' REQUIRED_FIELDS = ['name', 'is_analyst', 'DOB', 'gender', 'city_code'] objects = MyUserManager() # 为groups和user_permissions设置唯一的反向关联名 groups = models.ManyToManyField( 'auth.Group', verbose_name='groups', blank=True, help_text='The groups this user belongs to. A user will get all permissions granted to each of their groups.', related_name='myuser_groups' ) user_permissions = models.ManyToManyField( 'auth.Permission', verbose_name='user permissions', blank=True, help_text='Specific permissions for this user.', related_name='myuser_permissions' ) # 保持原方法不变... class OTP(models.Model): # 保持原代码不变...
执行数据库迁移:
python manage.py makemigrations python manage.py migrate
二、无法添加产品的问题
核心原因
Order模型的shipping属性中引用了i.product.digital,但Product模型里的digital字段被注释掉,导致访问该属性时触发AttributeError,进而影响产品的添加操作。
修复方案
方案1:恢复Product的digital字段
取消Product模型中digital字段的注释:
class Product(models.Model): name = models.CharField(max_length=200) product_cat = models.CharField(max_length=200) product_cat_code = models.IntegerField() product_subcat = models.CharField(max_length=200) product_subcat_code = models.IntegerField() price = models.FloatField() # 恢复digital字段 digital = models.BooleanField(default=False, null=True, blank=True) image = models.ImageField(null=True, blank=True) # 保持原方法不变...
方案2:修改Order的shipping逻辑(无需digital字段)
如果不需要判断商品是否为虚拟商品,直接调整shipping属性:
class Order(models.Model): # 保持原字段不变... @property def shipping(self): # 根据业务需求修改逻辑,示例默认关闭shipping return False
额外优化
删除product应用models中无用的User导入:
# 移除该行:from django.contrib.auth.models import User
补充配置(若使用ImageField)
若产品图片上传失败,需在项目settings.py中配置媒体文件路径:
MEDIA_ROOT = BASE_DIR / 'media' MEDIA_URL = '/media/'
并在主urls.py中添加媒体路由:
from django.conf import settings from django.conf.urls.static import static urlpatterns = [ # 你的其他路由配置 ] + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
内容的提问来源于stack exchange,提问作者Khair Ahammed
相关产品推荐
相关产品推荐

