2011-05-17 10 views
38

Mam standardową konfigurację relacji wiele do jednego. Istnieje kilka pól, ale dla naszych celów odpowiedni model to:Jeden do wielu wybierz liniowo z 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 

Stworzyłem administratora i działa świetnie. nawet automatycznie ma możliwość ustawienia klasy podczas edycji Ucznia. Jednak kiedy idę do tworzenia/edycji klasy, wszystko, co dostaję, to pole wprowadzania nazwy.

Czy istnieje sposób na dodanie pola/pola, w którym Uczniowie mogą być dodawani jako członkowie klasy ze strony administratora klasy? Mogę utworzyć formularz inline, ale to jest stworzenie nowych Studentów. Mam już wszystkich moich studentów i właśnie szukam szybkiej metody dodawania wielu istniejących studentów do innej klasy ".

+0

Nie ma mowy. Nie znalazłem rozwiązania po bardzo ciągłym szukaniu ... – zen11625

Odpowiedz

26

Oto "forma zwyczaj" rozwiązanie jako Luke Sneeringer sugerowane. W każdym razie, jestem zaskoczony brakiem gotowego rozwiązania Django do tego (raczej naturalnego i prawdopodobnie powszechnego) problemu. Czy czegoś brakuje?

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 
+1

Szczerze mówiąc nie wiem, co w końcu robiłem, aby rozwiązać to w końcu. Jestem pewien, że było to coś podobnego. I tak, to naprawdę dziwne, że nie mają czegoś wcześniejszego/prostszego. – MrGlass

+1

Podoba mi się to rozwiązanie, ale chciałem się upewnić, co rozumiesz przez argument "FIXME:" commit ". Jaki jest problem? –

+2

Aby zachować spójność z API ModelForm, foo_form.save (commit = False) powinien zwrócić obiekt, który nie został jeszcze zapisany w bazie danych (zobacz https://docs.djangoproject.com/en/dev/topics/forms/ modelforms/# the-save-method); Podana implementacja ignoruje argument "commit". Najprawdopodobniej nie użyjesz commit = False; jeśli tak, nie ma problemu. – zag

29

Jest! Chcesz InlineModelAdmin(see InlineModelAdmin documentation here)

Przykładowy kod w skrócie:

class StudentAdminInline(admin.TabularInline): 
    model = Student 

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

Nawiasem mówiąc, zachowaj ostrożność, nadając nazwę klasie "Klasa". To działa, ale będzie cię gryźć później (na przykład w pierwszym wierszu 'Studenta'). I 'class = models.ForeignKey (klasa)' * nie * działa, ponieważ "klasa" jest zastrzeżonym słowem. –

+0

tak. W rzeczywistości są to fałszywe imiona: P bezpieczeństwo, bla bla bla, itd. Uświadomiłem sobie złe imię później. Właściwie, spodziewałem się, że zostaniesz wezwany jako student college'u szukający pomocy domowej - to jest jak standardowy scenariusz dla zadania hw. – MrGlass

+8

Próbowałem implementacji i to nie robi tego, czego potrzebuję. Jak już wspomniałem w pytaniu, wiem, jak dodać formularz inline, ale TabularInline jest przeznaczony do tworzenia nowego obiektu. Chcę po prostu pozwolić użytkownikowi wybrać z istniejącej listy studentów, których już posiadam. – MrGlass