django admin - 选择反向外键关系(不创建,我想添加可用)
Posted
技术标签:
【中文标题】django admin - 选择反向外键关系(不创建,我想添加可用)【英文标题】:django admin - select reverse foreign key relationships (not create, I want to add available) 【发布时间】:2013-09-01 13:14:24 【问题描述】:假设我有一个模型 School
和另一个模型 Student
。
class Student(models.Model):
school = models.ForeignKey(School)
name = models.CharField(max_length=100)
在管理员中点击学校时,会出现一个新页面,其中显示学校模型字段和值。
我还想在该页面本身中选择已经可用的学生列表。
Inlines 不同,它们将允许创建和编辑属于该学校的新记录(学生)。但我不希望这样,让我们假设已经有很多学生记录可用。我应该能够从该学校模型页面的管理员中选择它们。
【问题讨论】:
【参考方案1】:class SchoolAdminForm(forms.ModelForm):
students = forms.ModelMultipleChoiceField(
queryset=Student.objects.all(),
widget=FilteredSelectMultiple(verbose_name='students', is_stacked=False))
class Meta:
model = School
fields = ['your_school_fields_go_here']
def __init__(self, *args, **kwargs):
super(SchoolAdminForm, self).__init__(*args, **kwargs)
if self.instance:
# fill initial related values
self.fields['students'].initial = self.instance.student_set.all()
class SchoolAdmin(admin.ModelAdmin):
form = SchoolAdminForm
def save_model(self, request, obj, form, change):
super().save_model(request, obj, form, change)
original_students = set(obj.student_set.values_list("id", flat=True))
current_students = set(map(lambda x: x.id, form.cleaned_data['students']))
if original_students != current_students:
add_to_school = current_students - original_students
Student.objects.filter(id__in=add_to_school).update(school_id=obj.id)
remove_from_school = original_students - current_students
Student.objects.filter(id__in=remove_from_school).update(school_id=None)
【讨论】:
【参考方案2】:我按照菲利克斯的建议做了。唯一的问题是它给出了这样的错误:
ValueError: Unsaved model instance <School: disscount_None> cannot be used in an ORM query.
我发现的原因是在保存当前 School 模型之前,您无法更改学生对象中的外键。因为还没有任何东西可以添加到 fk 属性中!所以使用 felix 解决方案,但在 save_model 函数中使用“for”之前的 obj.save()
def save_model(self, request, obj, form, change):
original_students = obj.student_set.all()
new_students = form.cleaned_data['students']
remove_qs = original_students.exclude(id__in=new_students.values('id'))
add_qs = new_students.exclude(id__in=original_students.values('id'))
obj.save()
for item in remove_qs:
obj.student_set.remove(item)
for item in add_qs:
obj.student_set.add(item)
【讨论】:
【参考方案3】:您可以禁用内联“添加”权限。见InlineModelAdmin
【讨论】:
【参考方案4】:您的意思是对于给定的School
实例,您希望能够获得与该学校相关的所有学生的列表吗?
在这种情况下,您使用您指定的 ForeignKey 关系的 related_name
属性。你还没有定义你做的related_name
:
school = models.ForeignKey(School)
这很好,它只是使用默认的相关名称,即子类(学生)的名称,后跟_set
所以对于您的学校实例:
school = School.objects.get(pk=1)
students = school.student_set.all() # or .filter() or .exclude() etc
然后您可以将该学生查询集传递到您的模板中。
【讨论】:
我知道。我想在管理员中做到这一点。因此,必须有一个简单的小部件。以上是关于django admin - 选择反向外键关系(不创建,我想添加可用)的主要内容,如果未能解决你的问题,请参考以下文章