EDYTOWANO:
Jak ustawić wartość domyślną pola Django na funkcję, która jest oceniana za każdym razem, gdy tworzony jest nowy obiekt modelu?
Chcę zrobić coś podobnego do następującego, z tą różnicą, że w tym kodzie kod jest oceniany raz i ustawia domyślną tę samą datę dla każdego utworzonego obiektu modelu, zamiast oceniać kod za każdym razem, gdy zostanie utworzony obiekt modelu:
from datetime import datetime, timedelta
class MyModel(models.Model):
# default to 1 day from now
my_date = models.DateTimeField(default=datetime.now() + timedelta(days=1))
ORYGINALNY:
Chcę utworzyć wartość domyślną dla parametru funkcji, tak aby była dynamiczna i była wywoływana i ustawiana za każdym razem, gdy funkcja jest wywoływana. Jak mogę to zrobić? na przykład,
from datetime import datetime
def mydate(date=datetime.now()):
print date
mydate()
mydate() # prints the same thing as the previous call; but I want it to be a newer value
W szczególności chcę to zrobić w Django, np.
from datetime import datetime, timedelta
class MyModel(models.Model):
# default to 1 day from now
my_date = models.DateTimeField(default=datetime.now() + timedelta(days=1))
django
django-models
parameters
lambda
default
Rob Bednark
źródło
źródło
Odpowiedzi:
Pytanie jest błędne. Podczas tworzenia pola modelu w Django nie definiujesz funkcji, więc domyślne wartości funkcji są nieistotne:
Ta ostatnia linia nie definiuje funkcji; wywołuje funkcję w celu utworzenia pola w klasie.
PRE Django 1.7
Django pozwala domyślnie przekazać wywołanie i będzie je wywoływać za każdym razem, tak jak chcesz:
Django 1.7+
Zwróć uwagę, że od wersji Django 1.7 używanie lambdy jako wartości domyślnej nie jest zalecane (por. Komentarz @stvnw). Właściwym sposobem na to jest zadeklarowanie funkcji przed polem i użycie jej jako wywoływalnej w default_value o nazwie arg:
Więcej informacji w odpowiedzi @simanas poniżej
źródło
get_default_my_date
?Robienie tego
default=datetime.now()+timedelta(days=1)
jest absolutnie złe!Jest oceniany, gdy uruchamiasz swoją instancję django. Jeśli jesteś pod apache'em to prawdopodobnie zadziała, ponieważ w niektórych konfiguracjach apache unieważnia twoją aplikację django na każde żądanie, ale nadal możesz znaleźć siebie pewnego dnia, przeglądając swój kod i próbując dowiedzieć się, dlaczego zostało to obliczone nie tak, jak się spodziewasz .
Właściwym sposobem na zrobienie tego jest przekazanie wywoływalnego obiektu do domyślnego argumentu. Może to być funkcja datetime.today lub funkcja niestandardowa. Następnie jest oceniany za każdym razem, gdy zażądasz nowej wartości domyślnej.
źródło
get_deadline(my_parameter)
?deadline
ponownie usunąć pole, jednocześnie usuwającget_deadline
funkcję? Usunąłem pole z funkcją dla wartości domyślnej, ale teraz Django ulega awarii podczas uruchamiania po usunięciu funkcji. Mógłbym ręcznie edytować migrację, co w tym przypadku byłoby w porządku, ale co by było, gdybyś po prostu zmienił domyślną funkcję i chciał usunąć starą funkcję?Istnieje ważna różnica między następującymi dwoma konstruktorami DateTimeField:
Jeśli używasz
auto_now_add=True
w konstruktorze, data i godzina, do której odwołuje się my_date, jest „niezmienna” (ustawiana tylko raz, gdy wiersz jest wstawiany do tabeli).Dzięki
auto_now=True
, jednak wartość datetime będą aktualizowane za każdym razem, gdy obiekt zostanie zapisany.W pewnym momencie było to dla mnie zdecydowanie trudne. W celach informacyjnych dokumenty są tutaj:
https://docs.djangoproject.com/en/dev/ref/models/fields/#datetimefield
źródło
Czasami może zajść potrzeba uzyskania dostępu do danych modelu po utworzeniu nowego modelu użytkownika.
Oto jak generuję token dla każdego nowego profilu użytkownika, używając pierwszych 4 znaków jego nazwy użytkownika:
źródło
Nie możesz tego zrobić bezpośrednio; wartość domyślna jest oceniana podczas oceny definicji funkcji. Ale można to obejść na dwa sposoby.
Po pierwsze, możesz utworzyć (a następnie wywołać) nową funkcję za każdym razem.
Lub, prościej, po prostu użyj specjalnej wartości, aby oznaczyć wartość domyślną. Na przykład:
Jeśli
None
jest to całkowicie rozsądna wartość parametru i nie ma innej rozsądnej wartości, której można by użyć w jej miejsce, możesz po prostu utworzyć nową wartość, która jest zdecydowanie poza domeną Twojej funkcji:W niektórych rzadkich przypadkach piszesz metakod, który naprawdę musi być w stanie przyjąć absolutnie wszystko, nawet powiedzmy
mydate.func_defaults[0]
. W takim przypadku musisz zrobić coś takiego:źródło
myfunc
funkcja ma pobierać (i drukować) adatetime
; zmieniłeś to, więc nie można go używać w ten sposób.Przekaż funkcję jako parametr zamiast przekazywania wyniku wywołania funkcji.
To znaczy zamiast tego:
Spróbuj tego:
źródło
print datetime.now()
bezwarunkowo.datetime.now
funkcja jest przekazywana . Ale każdy użytkownik, który przekaże wartość inną niż domyślna, przekaże datę i godzinę, a nie funkcję.foo = datetime.now(); myfunc(foo)
wzrośnieTypeError: 'datetime.datetime' object is not callable
. Gdybym rzeczywiście chciał użyć twojej funkcji, musiałbymmyfunc(lambda: foo)
zamiast tego zrobić coś takiego , co nie jest rozsądnym interfejsem.