You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

自定义Django User模型引发外键约束错误及产品添加失败问题

问题排查与解决方案

一、Admin删除OTP/User时的外键约束错误

核心原因

  1. 重复定义password字段:AbstractUser继承自AbstractBaseUser,已自带加密的password字段,手动添加同名字段会导致数据库字段冲突,触发约束异常。
  2. ManyToManyField反向关联名重复:groups和user_permissions使用同一个related_name='myuser_set',导致数据库关联表的反向查询逻辑冲突,删除操作时触发外键约束失败。
  3. 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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.22 03:10:03