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)还有两个隐患:
- 模型初始化阶段数据库可能还未创建,执行查询会直接报错
- 教师数据更新后,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,不要在模型里硬编码:
- 先修改模型,去掉
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)
- 创建表单时动态获取教师选项:
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())
额外优化点
- 修复
capitalize()的调用错误,必须加括号才能执行方法 - 模型初始化阶段不要执行数据库查询,所有查询逻辑应放在视图、表单或信号中
- 后续权限逻辑可以用Django内置权限系统,或者自定义装饰器实现
内容的提问来源于stack exchange,提问作者Prashank Mishra
相关产品推荐
相关产品推荐

