2009-05-15 13 views
8

Mam pole statusu, które ma 3 wartości: oczekujące, aktywowane i odrzucone. Jeśli zmieniam wartość statusu Chcę, aby miał aktywowany czek, którego nie można zmienić na oczekujący. I nie chcę pisać zapisanych-proców dla tego. Czy przed zapisaniem mogę mieć poprzednią wartość w Django?Jak sprawdzić przejście wartości w Django (django-admin)?

Oznacza nową i starą wartość.

+0

+1 - Zastanawiam się nad tym samym.W moim przypadku jest ciężka praca, która jest wykonywana w metodzie zapisu, która jest konieczna tylko wtedy, gdy zmieniło się pole w konkretnym podzbiorze pól modelu i szukałem sposobu na sprawdzenie, czy tak jest, czy nie. . Dzięki! –

Odpowiedz

10
def clean_status(self): 
    status = self.cleaned_data.get('status') 
    if status == 'pending': 
     if self.instance and self.instance.status == 'activated': 
      raise forms.ValidationError('You cannot change activated to pending') 

    return status 

Ta metoda ma zostać dodana do podklasy Form. Jego nazwa to clean_FIELD_NAME.

cleaned_data zawiera poprzednie wartości. Nowa wartość jest przechowywana w self.instance.

Metoda alternatywna może być dodana do podklasy forms.Field. See Django documentation.

+0

Hej, Dominik Rodger, możesz pomóc w "inline-django". Moje pytanie w django – ha22109

8

Można to zrobić w nadpisanej metodzie save. Należy pamiętać, że instancje modelu Django nie są rzeczywistymi obiektami bazy danych, po prostu pobierają swoje wartości z obciążenia. Możesz więc łatwo wrócić do bazy danych przed zapisaniem bieżącego obiektu, aby uzyskać istniejące wartości.

def save(self, *args, **kwargs): 
    if self.status == 'pending': 
     old_instance = MyClass.objects.get(pk=self.pk) 
     if old_instance.status == 'activated': 
       raise SomeError 
    super(MyModel, self).save(*args, **kwargs) 

Obecnie nie ma dobrego sposobu na zwrócenie użytkownikowi błędu innego niż zgłoszenie wyjątku. Obecnie trwa projekt Google Summer of Code, który umożliwia "walidację modelu", ale nie będzie on gotowy przez kilka miesięcy.

Jeśli chcesz zrobić coś podobnego w admin, najlepszym sposobem jest zdefiniowanie niestandardowego ModelForm z przesłoniętą metodą clean(). Jednak tym razem, ponieważ jest to formularz, masz już dostęp do starych wartości bez ponownego uderzania w db. Kolejną korzyścią jest to, że użytkownik może zwrócić błąd sprawdzania poprawności formularza.

class MyModelForm(forms.ModelForm): 

    class Meta: 
      model = MyModel 

    def clean_status(self): 
     status = self.cleaned_data.get('status', '') 
     if status == 'pending': 
      if self.instance and self.instance.status == 'activated': 
        raise forms.ValidationError(
         'You cannot change activated to pending' 
       ) 
     return status 

class MyModelAdmin(forms.ModelAdmin): 
    form = MyModelForm 
    model = MyModel 
+0

to dlatego, że prawdopodobnie należy zastąpić metodę ModelAdmin.save_model: http://docs.djangoproject.com/en/dev/ref/contrib/admin/#modeladmin-methods – ohnoes

+0

Dodałem alternatywę, korzystając z powyższego administratora. –

+0

Jeśli warunek powinien być , jeśli self.instance i self.instance.status == "aktywowane": podnieś formularze.ValidiationError – ha22109

0

Zamiast przesłonić metodę zapisu, czy nie byłoby to dobre miejsce do używania sygnałów? Przechwytywanie zapisu przed zatwierdzeniem, sprawdzanie bieżącej wartości w bazie danych i przekazywanie składowania lub odrzucanie?

Teraz nie jestem pewien, czy sygnał blokuje żądanie zapisu, czy też dzieje się tak asynchronicznie, więc nie krępuj się, aby odpowiedzieć na tę odpowiedź, jeśli nie można użyć sygnału, aby zapobiec zdarzeniu, które miało miejsce po sprawdzeniu poprawności.

Jestem przeciwny nadpisywaniu wbudowanych metod, jeśli istnieje inne wbudowane narzędzie, które działa równie dobrze.

+1

Myślę, że nadpisywanie save() i delete() może być dobrą praktyką. Mam klasy Zdjęcie i miniaturę. Kciuk ma item = models.ForeignKey (Photo). photo.delete() jest nadpisywany i usunie wszystkie kciuki (dla t w self.thumbnail_set.all(): t.delete()) przed uruchomieniem super (Photo, self) .delete(). Jeśli usunięcie kciuka zostanie wykonane w sygnale, utrzymanie kodu będzie trudniejsze. – vikingosegundo

+0

ale __init__ I wolud nigdy nie przeciążam. Zamiast tego użyłbym sygnału. – vikingosegundo

1

Odpowiedzi na te pytania udzielono w innym miejscu na temat przepełnienia stosu, ale właściwym sposobem jest użycie czegoś takiego, jak this, aby sprawdzić, czy pola są zabrudzone. Wtedy możesz użyć sygnału, by wskazać, że coś się zmieniło, co jest ważne. (twoje pole)

0

Znaleziono ten wątek podczas szukania odpowiedzi na to samo pytanie. Dlaczego nie zrobić czegoś takiego? W ten sposób można uniknąć dotykania bazy danych. I wbudowany __init__ tylko trochę przedłużony. Myślę, że to znacznie prostszy sposób niż używanie sygnałów.

class MyModel(models.Model): 
    my_fair_field = .... 

    def __init__(self, *args, **kwargs): 
     super(MyModel, self).__init__(*args, **kwargs) 
     self.__clean_fair_field = self.my_fair_field 

    def save(self, *args, **kwargs): 
     # check if field value changed 
     if self.__clean_fair_field != self.my_fair_field 
       # ...do some work... 

     super(MyModel, self).save(*args, **kwargs) 
Powiązane problemy