DIEDIT:
Bagaimana saya dapat menyetel standar bidang Django ke fungsi yang dievaluasi setiap kali objek model baru dibuat?
Saya ingin melakukan sesuatu seperti berikut, kecuali bahwa dalam kode ini, kode akan dievaluasi satu kali dan menetapkan default ke tanggal yang sama untuk setiap objek model yang dibuat, daripada mengevaluasi kode setiap kali objek model dibuat:
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))
ASLI:
Saya ingin membuat nilai default untuk parameter fungsi sedemikian rupa sehingga dinamis dan dipanggil dan disetel setiap kali fungsi dipanggil. Bagaimana saya bisa melakukan itu? misalnya,
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
Secara khusus, saya ingin melakukannya di Django, misalnya,
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
sumber
sumber
Jawaban:
Pertanyaannya salah arah. Saat membuat bidang model di Django, Anda tidak sedang mendefinisikan sebuah fungsi, jadi nilai default fungsi tidak relevan:
Baris terakhir ini tidak mendefinisikan sebuah fungsi; itu memanggil fungsi untuk membuat field di kelas.
PRE Django 1.7
Django mengijinkan Anda melewatkan sebuah yang dapat dipanggil sebagai default , dan itu akan memanggilnya setiap kali, seperti yang Anda inginkan:
Django 1.7+
Harap dicatat bahwa sejak Django 1.7, penggunaan lambda sebagai nilai default tidak direkomendasikan (lihat komentar @stvnw). Cara yang tepat untuk melakukan ini adalah dengan mendeklarasikan fungsi sebelum kolom dan menggunakannya sebagai callable di default_value bernama arg:
Informasi lebih lanjut di jawaban @simanas di bawah ini
sumber
get_default_my_date
?Melakukan ini
default=datetime.now()+timedelta(days=1)
benar-benar salah!Ini akan dievaluasi ketika Anda memulai contoh Anda dari django. Jika Anda berada di bawah apache, ini mungkin akan berhasil, karena pada beberapa konfigurasi apache mencabut aplikasi django Anda pada setiap permintaan, tetapi Anda masih dapat menemukan diri Anda suatu hari nanti melihat-lihat kode Anda dan mencoba mencari tahu mengapa ini dihitung tidak seperti yang Anda harapkan .
Cara yang benar untuk melakukan ini adalah dengan meneruskan objek yang dapat dipanggil ke argumen default. Ini bisa berupa fungsi datetime.today atau fungsi kustom Anda. Kemudian itu dievaluasi setiap kali Anda meminta nilai default baru.
sumber
get_deadline(my_parameter)
?deadline
bidang lagi sekaligus menghapusget_deadline
fungsinya? Saya telah menghapus bidang dengan fungsi untuk nilai default, tetapi sekarang Django lumpuh saat memulai setelah menghapus fungsi tersebut. Saya dapat mengedit migrasi secara manual, yang akan baik-baik saja dalam kasus ini, tetapi bagaimana jika Anda hanya mengubah fungsi default, dan ingin menghapus fungsi lama?Ada perbedaan penting antara dua konstruktor DateTimeField berikut:
Jika Anda menggunakan
auto_now_add=True
dalam konstruktor, datetime yang direferensikan oleh my_date adalah "tidak dapat diubah" (hanya disetel sekali saat baris dimasukkan ke tabel).Dengan
auto_now=True
, bagaimanapun, nilai tanggal waktu akan diperbarui setiap kali objek disimpan.Ini jelas merupakan gotcha bagi saya pada satu titik. Untuk referensi, dokumennya ada di sini:
https://docs.djangoproject.com/en/dev/ref/models/fields/#datetimefield
sumber
Terkadang Anda mungkin perlu mengakses data model setelah membuat model pengguna baru.
Berikut adalah cara saya membuat token untuk setiap profil pengguna baru menggunakan 4 karakter pertama dari nama pengguna mereka:
sumber
Anda tidak dapat melakukannya secara langsung; nilai default dievaluasi ketika definisi fungsi dievaluasi. Tetapi ada dua cara untuk mengatasinya.
Pertama, Anda dapat membuat (lalu memanggil) fungsi baru setiap saat.
Atau, lebih sederhananya, cukup gunakan nilai khusus untuk menandai default. Sebagai contoh:
Jika
None
merupakan nilai parameter yang masuk akal, dan tidak ada nilai wajar lainnya yang dapat Anda gunakan sebagai gantinya, Anda dapat membuat nilai baru yang pasti berada di luar domain fungsi Anda:Dalam beberapa kasus yang jarang terjadi, Anda menulis kode meta yang benar-benar harus dapat mengambil apa pun, bahkan, katakanlah
mydate.func_defaults[0]
,. Dalam hal ini, Anda harus melakukan sesuatu seperti ini:sumber
myfunc
fungsinya dibuat untuk mengambil (dan mencetak) adatetime
; Anda telah mengubahnya sehingga tidak dapat digunakan seperti itu.Meneruskan fungsi sebagai parameter alih-alih meneruskan hasil pemanggilan fungsi.
Artinya, alih-alih ini:
Coba ini:
sumber
print datetime.now()
tanpa syarat.datetime.now
fungsi tersebut. Tetapi setiap pengguna yang meneruskan nilai non-default akan melewati waktu waktu, bukan fungsi.foo = datetime.now(); myfunc(foo)
akan meningkatTypeError: 'datetime.datetime' object is not callable
. Jika saya benar-benar ingin menggunakan fungsi Anda, saya harus melakukan sesuatu seperti itumyfunc(lambda: foo)
, yang bukan antarmuka yang masuk akal.