Django Admin中外键字段无需多对多或中间表实现多选的方案及代码报错求助
Django Admin中外键字段无需多对多或中间表实现多选的方案及代码报错求助
各位大佬好,我最近在做Django项目时遇到个棘手的问题,想请教下大家的思路。我有个关联外键的模型,想要在Admin里给外键字段加多选功能,但不想用多对多关系或者额外中间表,于是尝试重写表单的save方法,结果一直报错,折腾好久没搞定,来求助了!
先贴下我的模型代码:
class StudentPlatformDefaultDocuments(models.Model): id = models.AutoField(db_column='id', primary_key=True, db_index=True) document = models.ForeignKey(Documents, db_column='DocumentId')
我的需求很简单:希望用户在表单里能一次性选择多个Documents实例,提交后自动创建多条StudentPlatformDefaultDocuments记录,每条对应一个选中的Document。
然后是我在forms.py里尝试的save方法代码:
def save(self, commit=True): document = self.cleaned_data['document'] print(document,'document get') instance= super(MyModelForm, self).save(commit=False) if document: documents = [] for doc in document: print(doc,'doc1212121') print(doc.documentid,'doc1212121') document1 = Documents.objects.get( documentid=doc.documentid).documentid print(document1,'document1') documents.append(document1) test = StudentPlatformDefaultDocuments.objects.create( document=doc.documentid) test.save() print(documents) return instance
现在运行起来就报错,我自己排查了半天也没找到问题所在,想问问各位我的思路哪里错了?有没有更靠谱的实现方式?
针对你的问题,我整理了几个关键的修正点和实现方案:
1. 先把表单字段改成支持多选的类型
你首先得把表单里的document字段从默认的单选择改成多选择,不然cleaned_data里拿到的不是列表,循环肯定报错。修改表单类如下:
from django import forms from .models import StudentPlatformDefaultDocuments, Documents class MyModelForm(forms.ModelForm): # 替换成多选字段,指定可选的Documents数据集 document = forms.ModelMultipleChoiceField( queryset=Documents.objects.all(), widget=forms.SelectMultiple(), # 用多选控件 required=True ) class Meta: model = StudentPlatformDefaultDocuments fields = ['document']
2. 修正save方法的逻辑
你的save方法有几个明显的问题:
- 没必要调用
super().save(commit=False),因为你要创建多条记录,不是修改单个实例; - 创建记录时,ForeignKey字段需要传入Documents实例,而不是documentid的值,直接用循环里的
doc就行,不用再去查一次; - 多余的print语句可以去掉,方便调试但上线要删掉。
修正后的save方法:
def save(self, commit=True): selected_docs = self.cleaned_data.get('document') created_instances = [] if selected_docs and commit: # 循环创建每条关联记录 for doc in selected_docs: instance = StudentPlatformDefaultDocuments.objects.create(document=doc) created_instances.append(instance) # 返回创建的实例列表,方便后续处理(可选) return created_instances
3. 配置Admin使用这个表单
如果是在Django Admin里用,记得在ModelAdmin里指定我们的自定义表单:
from django.contrib import admin from .models import StudentPlatformDefaultDocuments from .forms import MyModelForm class StudentPlatformDefaultDocumentsAdmin(admin.ModelAdmin): form = MyModelForm # 可以自定义列表显示的字段 list_display = ('id', 'document') admin.site.register(StudentPlatformDefaultDocuments, StudentPlatformDefaultDocumentsAdmin)
为什么你之前的代码会报错?
大概率是这两个原因:
- 表单字段没改成多选,导致
cleaned_data['document']是单个对象,不是列表,循环时直接报错; - 创建记录时传入的是
doc.documentid(数值),但ForeignKey字段需要的是Documents实例,引发类型不匹配的错误。
按照上面的步骤改完,应该就能正常实现多选保存的功能了,你可以试试!
备注:内容来源于stack exchange,提问作者Shital
相关产品推荐
相关产品推荐

