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

如何通过主键/外键关联三个Django模型?报错解决与需求实现

报错原因分析

  • 错误使用ManyToOneRel:models.ManyToOneRel是Django内部用于维护外键关系的底层类,并非定义模型字段的公开API;one_to_many是该类的缓存属性,不是可调用方法,直接调用会触发TypeError。
  • company_id关联对象错误:ReportDetails的company_id字段错误关联了settings.AUTH_USER_MODEL,不符合“以Company为核心关联”的需求,应关联Company模型。
  • Company与User的关系逻辑错误:原Company模型的user外键设计导致一个公司仅能关联一个用户,无法满足“公司拥有多个员工”的场景。

符合需求的模型关联方案

核心关系梳理:

  1. 一对多:一个公司对应多个员工
  2. 一对多:一个公司对应多个报告,每个报告由一位员工创建
  3. 多对多(带中间模型):记录员工查看报告的行为,用于统计查看列表

修改后的完整模型代码:

from django.db import models
from django.contrib.auth.models import AbstractBaseUser, PermissionsMixin, BaseUserManager
import uuid
from django.conf import settings

class UserManager(BaseUserManager):
    def create_user(self, email, password=None, **extra_fields):
        if not email:
            raise ValueError('Users must have an email address')
        email = self.normalize_email(email)
        user = self.model(email=email, **extra_fields)
        user.set_password(password)
        user.save(using=self._db)
        return user

    def create_superuser(self, email, password):
        user = self.create_user(email, password)
        user.is_staff = True
        user.is_superuser = True
        user.save(using=self._db)
        return user

class User(AbstractBaseUser, PermissionsMixin):
    """系统用户模型"""
    email = models.EmailField(max_length=255, unique=True)
    fname = models.CharField(max_length=255)
    lname = models.CharField(max_length=255)
    is_active = models.BooleanField(default=True)
    is_staff = models.BooleanField(default=False)
    phone_number = models.PositiveIntegerField(default=0)
    license = models.CharField(default="0", max_length=50)
    signature = models.ImageField(null=True, upload_to="signatures/")
    # 用户所属公司:一个用户属于一个公司,一个公司对应多个员工
    company = models.ForeignKey(
        'Company',
        on_delete=models.CASCADE,
        related_name='employees',
        null=True,
        blank=True
    )

    objects = UserManager()
    USERNAME_FIELD = 'email'

    def __str__(self):
        return self.email

class Company(models.Model):
    """公司模型"""
    company_id = models.UUIDField(
        primary_key=True,
        default=uuid.uuid4,
        editable=False,
        unique=True
    )
    owner = models.CharField(max_length=30)
    owner_email = models.CharField(max_length=75)
    company_name = models.CharField(max_length=75)
    company_addr = models.CharField(max_length=255)
    phone_number = models.PositiveIntegerField(default=0)
    logo = models.ImageField(null=True, upload_to="logos/")

    def __str__(self):
        return self.company_name

class ReportDetails(models.Model):
    """报告详情模型"""
    report_uuid = models.UUIDField(
        primary_key=True,
        default=uuid.uuid4,
        editable=False,
        unique=True
    )
    # 报告所属公司:一个公司对应多个报告
    company = models.ForeignKey(
        Company,
        on_delete=models.CASCADE,
        related_name='reports'
    )
    # 报告创建者:一个用户创建多个报告
    created_by = models.ForeignKey(
        settings.AUTH_USER_MODEL,
        on_delete=models.CASCADE,
        related_name='created_reports'
    )
    title = models.CharField(max_length=100)
    r_id = models.CharField(max_length=100)

    def __str__(self):
        return self.title

# 记录用户查看报告的行为,用于统计员工查看列表
class ReportView(models.Model):
    user = models.ForeignKey(
        settings.AUTH_USER_MODEL,
        on_delete=models.CASCADE,
        related_name='viewed_reports'
    )
    report = models.ForeignKey(
        ReportDetails,
        on_delete=models.CASCADE,
        related_name='viewed_by'
    )
    viewed_at = models.DateTimeField(auto_now_add=True)

    class Meta:
        # 限制同一用户不可重复记录查看同一报告(可按需移除)
        unique_together = ('user', 'report')

    def __str__(self):
        return f"{self.user.email} viewed {self.report.title}"

常用查询示例

  • 获取某公司的所有员工:company.employees.all()
  • 获取某公司的所有报告:company.reports.all()
  • 获取某员工创建的所有报告:user.created_reports.all()
  • 获取某员工查看过的所有报告:user.viewed_reports.all()
  • 实现公司内员工查看任意报告:在视图层判断当前用户的company属性与报告的company属性是否一致即可

内容的提问来源于stack exchange,提问作者im_up

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.09 22:24:51