J'ai mis en place une relation plusieurs-à-un standard. Il y a un tas de domaines, mais pour nos besoins ici, le modèle pertinent est:
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
J'ai créé un administrateur et cela fonctionne très bien. il a même automatiquement la possibilité de définir la classe lorsque je modifie un étudiant. Cependant, lorsque je vais créer/modifier une classe, tout ce que j'obtiens est une zone de saisie pour le nom.
Existe-t-il un moyen d'ajouter une boîte/un champ où les étudiants peuvent être ajoutés en tant que membres de la classe à partir de la page d'administration de la classe? Je peux créer un formulaire en ligne, mais c'est pour créer de nouveaux étudiants. J'ai déjà créé tous mes étudiants et je cherche juste une méthode rapide pour ajouter plusieurs étudiants existants à différentes classes.
Voici la solution "formulaire personnalisé" comme l'a suggéré Luke Sneeringer. Quoi qu'il en soit, je suis surpris par l'absence de solution prête à l'emploi Django à ce problème (plutôt naturel et probablement courant). Suis-je en train de manquer quelque chose?
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
Il y a! Vous voulez InlineModelAdmin
(voir la documentation InlineModelAdmin ici)
Exemple de code en bref:
class StudentAdminInline(admin.TabularInline):
model = Student
class ClassAdmin(admin.ModelAdmin):
inlines = (StudentAdminInline, )
admin.site.register(Class, ClassAdmin)
Vous pouvez également exécuter les noms des étudiants via un deuxième modèle afin qu'ils soient un ForeignKey
. Par exemple, après le message de code d'origine, ajoutez:
class AssignedStudents(models.Model):
assigned_to = models.ForeignKey(Class, on_delete=models.CASCADE)
student = models.ForeignKey(Student, on_delete=models.CASCADE)
Ajoutez ensuite l'inline à l'administrateur comme l'a dit Luke Sneeringer. Vous vous retrouvez avec une liste déroulante dans laquelle vous pouvez sélectionner les noms des étudiants. Cependant, il existe toujours la possibilité de créer de nouveaux étudiants.
Cela aidera probablement: j'ai utilisé l'approche décrite, mais j'ai changé les méthodes save
et save_m2m
de la manière suivante:
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_m2m(self):
pass
def save(self, *args, **kwargs):
self.fields['bars'].initial.update(foo=None)
foo_instance = Foo()
foo_instance.pk = self.instance.pk
# Copy all other fields.
# ... #
foo_instance.save()
self.cleaned_data['bars'].update(foo=instance)
return instance
class FooAdmin(admin.ModelAdmin):
form = FooForm