小编典典

使用Django管理员进行一对多内联选择

django

我建立了标准的多对一关系。有很多字段,但是出于我们的目的,相关模型为:

class Class(models.Model):
    name = models.CharField(max_length=128)

class Student(models.Model):
    class = models.ForeignKey(Class)
    name = models.CharField(max_length=128)
    address = models.CharField(max_length=128)
    # ...etc

我创建了一个管理员,效果很好。当我编辑学生时,它甚至可以自动设置班级。但是,当我去创建/编辑一个类时,我得到的只是名称输入框。

是否可以添加一个框/字段,以便在班级管理页面中将学生添加为班级成员?我可以内联表单,但这就是创建新学生。我已经创建了所有学生,并且正在寻找一种快速方法来将多个现有学生添加到不同的班级。


阅读 567

收藏
2020-03-30

共2个答案

小编典典

这是Luke Sneeringer建议的“自定义表单”解决方案。无论如何,我对缺少这个问题(相当自然且可能很常见)的现成Django解决方案感到惊讶。我想念什么吗?

from django import forms
from django.db import models
from django.contrib import admin

class Foo(models.Model):
    pass

class Bar(models.Model):
    foo = models.ForeignKey(Foo)

class FooForm(forms.ModelForm):
    class Meta:
        model = Foo

    bars = forms.ModelMultipleChoiceField(queryset=Bar.objects.all())

    def __init__(self, *args, **kwargs):
        super(FooForm, self).__init__(*args, **kwargs)
        if self.instance:
            self.fields['bars'].initial = self.instance.bar_set.all()

    def save(self, *args, **kwargs):
        # FIXME: 'commit' argument is not handled
        # TODO: Wrap reassignments into transaction
        # NOTE: Previously assigned Foos are silently reset
        instance = super(FooForm, self).save(commit=False)
        self.fields['bars'].initial.update(foo=None)
        self.cleaned_data['bars'].update(foo=instance)
        return instance

class FooAdmin(admin.ModelAdmin):
    form = FooForm
2020-03-30
小编典典

你需要InlineModelAdmin (请参见InlineModelAdmin文档)

简短的示例代码:

class StudentAdminInline(admin.TabularInline):
    model = Student

class ClassAdmin(admin.ModelAdmin):
    inlines = (StudentAdminInline, )
admin.site.register(Class, ClassAdmin)
2020-03-30