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

Django中遇TypeError: cannot pickle 'generator' object错误求助

解决Django中cannot pickle 'generator' object错误并实现作业选教师功能

问题背景

我是Django新手,正在开发实践项目积累实操经验。项目包含用户、校长、学生、教师、作业5类资源,权限逻辑如下:

  • 校长可查看所有教师、教师提交/批改的作业,还可重新批改教师已评分的作业
  • 学生可创建、编辑作业草稿,查看自己创建的所有作业,并提交草稿给教师
  • 教师可查看提交给自己的作业并评分

我的models.py代码:

from django.db import models
from django.contrib.auth.models import AbstractBaseUser, BaseUserManager
from django.core.validators import MaxValueValidator, MinValueValidator

# Create your models here.

class UserManager(BaseUserManager):
    def create_user(self, email, username, first_name, last_name, password=None):
        if not email:
            return ValueError("User must have an email Adress")

        if not username:
            return ValueError("User must have an username")

        user = self.model(
            email = self.normalize_email(email),
            username = username,
            first_name = first_name,
            last_name = last_name,
        )

        user.set_password(password)
        user.save(using=self._db)
        return user
    
    def create_superuser(self, email, username, first_name, last_name, password=None):
        user = self.create_user(
            email=email, 
            username=username,
            first_name=first_name,
            last_name = last_name,
            password=password,
        )

        user.is_admin = True
        user.is_active = True
        user.is_staff = True
        user.is_superadmin = True
        user.save(using=self._db)
        return user


class User(AbstractBaseUser):
    PRINCIPAL = 1
    TEACHER = 2
    STUDENT = 3

    ROLE_CHOICE = (
        (PRINCIPAL, 'Principal'),
        (TEACHER, 'Teacher'),
        (STUDENT, 'Student'),
    )

    first_name = models.CharField(max_length=20)
    last_name = models.CharField(max_length=20)
    email = models.EmailField(max_length=60, unique=True)
    username = models.CharField(max_length=30, unique=True)
    phone_number = models.CharField(max_length=12, blank=True)
    role = models.PositiveSmallIntegerField(choices=ROLE_CHOICE, blank=True, null=True)


    # required field
    date_joined = models.DateTimeField(auto_now_add=True)
    last_login = models.DateTimeField(auto_now_add=True)
    created_date = models.DateTimeField(auto_now_add=True)
    modified_date = models.DateTimeField(auto_now=True)
    is_admin = models.BooleanField(default=False)
    is_staff = models.BooleanField(default=False)
    is_active = models.BooleanField(default=False)
    is_superadmin = models.BooleanField(default=False)

    USERNAME_FIELD = 'email'
    REQUIRED_FIELDS = ['username', 'first_name', 'last_name']


    objects = UserManager()

    def __str__(self):
        return self.email

    def has_perm(self, perm, obj=None):
        return self.is_admin

    def has_module_perms(self, app_label):
        return True
    



teacher = User.objects.filter(role=2)
teacher_choice = ((i.first_name.capitalize+i.last_name.capitalize,f'{i.first_name} {i.last_name}') for i in teacher)
print(teacher_choice)


class Assignment(models.Model):
    title = models.CharField(max_length=200)
    disc = models.TextField(max_length=500)
    user = models.ForeignKey(User, on_delete=models.CASCADE)
    teacher = models.CharField(choices=teacher_choice, max_length=200, null=True)


class Grade(models.Model):
    assignment = models.OneToOneField(Assignment, on_delete=models.CASCADE)
    grade = models.FloatField(validators=[MinValueValidator(0), MaxValueValidator(10)])

错误信息

运行时出现错误:

Exception Value:cannot pickle 'generator' object

错误出现在Assignment类的这行代码:

teacher = models.CharField(choices=teacher_choice, max_length=200, null=True)

我需要实现学生提交作业时选择特定教师的功能,从数据库获取所有教师并生成choices,但遇到上述错误,请求帮助解决。


错误原因

你用生成器表达式创建了teacher_choice,但Django的模型字段choices要求传入可序列化(可pickle)的序列类型(比如列表、元组),生成器对象无法被序列化,因此触发该错误。

另外,你直接在模型定义外执行User.objects.filter(role=2)还有两个隐患:

  1. 模型初始化阶段数据库可能还未创建,执行查询会直接报错
  2. 教师数据更新后,choices不会自动刷新,因为这段代码只会在模型加载时执行一次

正确实现方案

方案1:用ForeignKey关联教师(推荐)

作业和教师是明确的关联关系,用ForeignKey比CharField更合理,既能保证数据一致性,后续查询也更便捷:

修改Assignment模型的teacher字段:

class Assignment(models.Model):
    title = models.CharField(max_length=200)
    disc = models.TextField(max_length=500)
    user = models.ForeignKey(User, on_delete=models.CASCADE, related_name='student_assignments')
    # 关联教师,自动过滤出角色为TEACHER的用户
    teacher = models.ForeignKey(
        User, 
        on_delete=models.SET_NULL, 
        null=True, 
        blank=True,
        limit_choices_to={'role': User.TEACHER},
        related_name='teacher_assignments'
    )
  • limit_choices_to会在admin后台或表单中自动过滤教师角色的用户
  • related_name方便反向查询,比如教师查看自己的作业:teacher.teacher_assignments.all()

方案2:动态生成choices(适合特殊场景)

如果一定要用CharField,需要在表单中动态生成choices,不要在模型里硬编码:

  1. 先修改模型,去掉choices参数:
class Assignment(models.Model):
    title = models.CharField(max_length=200)
    disc = models.TextField(max_length=500)
    user = models.ForeignKey(User, on_delete=models.CASCADE)
    teacher = models.CharField(max_length=200, null=True, blank=True)
  1. 创建表单时动态获取教师选项:
from django import forms
from .models import Assignment, User

class AssignmentForm(forms.ModelForm):
    class Meta:
        model = Assignment
        fields = ['title', 'disc', 'teacher']
    
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        # 动态获取所有教师并生成choices
        teachers = User.objects.filter(role=User.TEACHER)
        self.fields['teacher'].choices = [
            (f"{t.first_name.capitalize()} {t.last_name.capitalize()}", f"{t.first_name} {t.last_name}")
            for t in teachers
        ]

(注意:你之前写的i.first_name.capitalize少了括号,正确写法是i.first_name.capitalize())


额外优化点

  1. 修复capitalize()的调用错误,必须加括号才能执行方法
  2. 模型初始化阶段不要执行数据库查询,所有查询逻辑应放在视图、表单或信号中
  3. 后续权限逻辑可以用Django内置权限系统,或者自定义装饰器实现

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.24 21:47:06