2010-08-26 12 views
18

Jak ustawić wartość domyślną dla pola, które ma zostać pobrane z istniejących obiektów modelu?Django: domyślna wartość pola z instancji własnego modelu

Próbowałem to i to nie działało:

1)

class ModelA(models.Model): 
    fieldA = models.CharField(default=self.get_previous()) 

    def get_previous(self): 
     return ModelA.objects.all()[0].fieldA 

NameError: name 'self' is not defined

2)

class ModelA(models.Model): 
    fieldA = models.CharField(default=ModelA.get_previous()) 

    @staticmethod 
    def get_previous(): 
     return ModelA.objects.all()[0].fieldA 

NameError: name 'ModelA' is not defined

3)

class ModelA(models.Model): 
    fieldA = models.CharField(default=get_previous()) 

def get_previous(): 
    return ModelA.objects.all()[0].fieldA 

NameError: global name 'get_previous' is not defined

4)

def get_previous(): 
    return ModelA.objects.all()[0].fieldA 

class ModelA(models.Model): 
    fieldA = models.CharField(default=get_previous()) 

NameError: global name 'ModelA' is not defined

I to jest jasne, dlaczego 3) i 4) nie będzie działać. Mogę sobie wyobrazić, dlaczego 1) nie zadziała - wygląda na to, że cechy klasy nie mogą odnosić się do instancji (to znaczy do jaźni). Mogę sobie wyobrazić, dlaczego 2) nie zadziała - najwyraźniej nie ma odniesienia do Modelu A, dopóki tłumacz nie przejdzie przez całą klasę.

Jak powinienem to zrobić?

Odpowiedz

16

W swoich przykładach należy usunąć operatora połączeń ().

Obecnie instrukcja jest wykonywana natychmiast w pierwszym cyklu odczytu-parsowania. Określając nazwę symbolu, klasa Django otrzymuje wskaźnik funkcji, który będzie wykonywał, gdy rzeczywiście będzie potrzebował wartości domyślnej.

Przykład staje:

def get_previous(): 
    return ModelA.objects.all()[0].fieldA 

class ModelA(models.Model): 
    fieldA = models.CharField(default=get_previous) 

Jeśli masz zamiar zrobić to dla wielu dziedzinach, należy rozważyć overridding funkcję save, więc trzeba tylko pobrać poprzedni obiekt z bazy danych tylko raz.

+1

Dobra uwaga! W moim przypadku jednak mam wiele pól, aby uzyskać domyślną wartość, więc potrzebowałbym osobnej funkcji dla każdego z nich. (Ale rozważę użycie lambda do uogólnienia tego, coś jak 'lambda: get_default ('field_name')') – grucha

+1

Równoważnie, powinieneś być w stanie zrobić 'default = lambda: ModelA.objects.all() [0]. poleA'. –

+1

Należy pamiętać, że użycie domyślnej funkcji lambda spowoduje bałagan z migracjami, ponieważ funkcji lambda nie można serializować. – Ironbeard

3

Jeśli chcesz po prostu wyjście wartości domyślne, zastępują __getattr__() metoda tak:

class ModelA(models.Model): 
    # your fields 
    def __getattr__(self, name): 
    if(name == 'fieldA' and !self.fieldA): 
     return self.get_previous() 
    else: 
     return super(ModelA, self).__getattr__(name) 

Zapisywanie Wartość domyślna od obiektu będzie trochę difficultier. Pierwsze rozwiązanie, które przychodzi mi do głowy, override save() method (uważam, że jest prostsze rozwiązanie)

3

Opcja 1: Use model forms. Są to formularze oparte na modelach, które można łatwo wypełnić ich wartości wartościami z określonej instancji. Ta opcja jest dobra, jeśli chcesz, aby wartość domyślna była widoczna dla użytkownika w formularzach.

Opcja 2: Override the model's save method, i zakoduj tam zaznaczenie - jeśli pole A jest Brak, a następnie wpisz w nim pewną wartość. Ta opcja jest lepsza, jeśli chcesz, aby domyślna wartość działała w warstwie danych, a nie tylko jako wartości domyślne formularza (tj. Również dla instancji tworzonych w inny sposób).

+0

Moim celem jest pokazanie wartości domyślnej użytkownikowi, a nie jej zapisanie, jeśli nie ma wartości, więc opcja_1 odpowiedzi wygląda dobrze. Chociaż bardziej podoba mi się odpowiedź vdboor, ponieważ jest to poziom pythonowy i nie jest on specyficzny dla django. Djangonauts, popraw mnie, jeśli idę w niewłaściwy sposób ;-) – grucha