Один-ко-многим встроенный выбор с django admin

У меня есть стандартная связь "много-к-одному". Есть куча полей, но для наших целей здесь соответствующая модель:

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

Я создал администратора, и он отлично работает. он даже автоматически имеет возможность установить класс, когда я редактирую Студент. Однако, когда я иду для создания/редактирования класса, все, что я получаю, является полем ввода для имени.

Есть ли способ добавить поле/поле, в котором учащиеся могут быть добавлены в качестве членов класса со страницы администратора класса? Я могу сделать форму встроенной, но это нужно для создания новых учеников. У меня уже есть все мои ученики, и я просто ищу быстрый способ добавления нескольких существующих учеников в разные классы.

Ответ 1

Вот решение "пользовательской формы", как предложил Люк Снейрингер. Во всяком случае, я удивлен отсутствием готового решения 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

Ответ 2

Есть! Вы хотите InlineModelAdmin (см. Документацию InlineModelAdmin)

Краткое описание кода:

class StudentAdminInline(admin.TabularInline):
    model = Student

class ClassAdmin(admin.ModelAdmin):
    inlines = (StudentAdminInline, )
admin.site.register(Class, ClassAdmin)

Ответ 3

Вы также можете запустить имена учеников через вторую модель, чтобы они были ForeignKey. Например, после оригинальной записи кода добавьте:

class AssignedStudents(models.Model):
    assigned_to = models.ForeignKey(Class, on_delete=models.CASCADE)
    student = models.ForeignKey(Student, on_delete=models.CASCADE)

Затем добавьте строчку к администратору, как сказал Люк Снерингер. Вы получите выпадающий список, из которого вы можете выбрать имена учеников. Хотя есть возможность создавать новых учеников.