Saya sedang menulis kelas Django Middleware yang ingin saya jalankan hanya sekali saat startup, untuk menginisialisasi beberapa kode arbriter lainnya. Saya telah mengikuti solusi yang sangat bagus yang diposting oleh sdolan di sini , tetapi pesan "Halo" adalah output ke terminal dua kali . Misalnya
from django.core.exceptions import MiddlewareNotUsed
from django.conf import settings
class StartupMiddleware(object):
def __init__(self):
print "Hello world"
raise MiddlewareNotUsed('Startup complete')
dan dalam file pengaturan Django saya, saya punya kelas yang termasuk dalam MIDDLEWARE_CLASSES
daftar.
Tetapi ketika saya menjalankan Django menggunakan runserver dan meminta halaman, saya masuk ke terminal
Django version 1.3, using settings 'config.server'
Development server is running at http://127.0.0.1:8000/
Quit the server with CONTROL-C.
Hello world
[22/Jul/2011 15:54:36] "GET / HTTP/1.1" 200 698
Hello world
[22/Jul/2011 15:54:36] "GET /static/css/base.css HTTP/1.1" 200 0
Adakah ide mengapa "Hello world" dicetak dua kali? Terima kasih.
Jawaban:
Pembaruan dari jawaban Pykler di bawah ini: Django 1.7 sekarang memiliki kaitan untuk ini
Jangan lakukan seperti ini.
Anda tidak ingin "middleware" untuk startup satu kali.
Anda ingin mengeksekusi kode di tingkat atas
urls.py
. Modul itu diimpor dan dieksekusi sekali.urls.py
sumber
Pembaruan: Django 1.7 sekarang memiliki pengait untuk ini
mengajukan:
myapp/apps.py
mengajukan:
myapp/__init__.py
Untuk Django <1.7
Jawaban nomor satu tampaknya tidak berfungsi lagi, urls.py dimuat berdasarkan permintaan pertama.
Apa yang telah bekerja akhir-akhir ini adalah untuk menempatkan kode startup di salah satu dari Anda INSTALLED_APPS init Py misalnya
myapp/__init__.py
Ketika menggunakan
./manage.py runserver
... ini dieksekusi dua kali, tetapi itu karena runserver memiliki beberapa trik untuk memvalidasi model pertama dll ... ... penyebaran normal atau bahkan ketika runserver memuat otomatis, ini hanya dijalankan sekali.sumber
Pertanyaan ini dijawab dengan baik di posting blog Entri titik kait untuk proyek Django , yang akan bekerja untuk Django> = 1.4.
Pada dasarnya, Anda dapat menggunakannya
<project>/wsgi.py
untuk melakukan itu, dan itu akan dijalankan hanya sekali, ketika server mulai, tetapi tidak ketika Anda menjalankan perintah atau mengimpor modul tertentu.sumber
Jika membantu seseorang, selain pykler ini jawabannya, "--noreload" pilihan mencegah runserver dari mengeksekusi perintah pada startup dua kali:
Tapi perintah itu tidak akan memuat ulang server setelah perubahan kode lain juga.
sumber
os.environ.get('RUN_MAIN')
untuk hanya mengeksekusi kode Anda satu kali dalam proses utama (lihat stackoverflow.com/a/28504072 )ready(self)
panggilan sementara masih dapat memulai hanya sekali. Bersulang!runserver
secara default memulai dua proses dengan nomor pid yang berbeda (berbeda).--noreload
membuatnya memulai satu proses.Seperti yang disarankan oleh @Pykler, dalam Django 1.7+ Anda harus menggunakan hook yang dijelaskan dalam jawabannya, tetapi jika Anda ingin fungsi Anda dipanggil hanya ketika run server dipanggil (dan bukan saat melakukan migrasi, bermigrasi, shell, dll. Disebut ), dan Anda ingin menghindari pengecualian AppRegistryNotReady yang harus Anda lakukan sebagai berikut:
mengajukan:
myapp/apps.py
sumber
Perhatikan bahwa Anda tidak dapat keandalan terhubung ke database atau berinteraksi dengan model di dalam
AppConfig.ready
fungsi (lihat peringatan di dokumen).Jika Anda perlu berinteraksi dengan database dalam kode start-up Anda, satu kemungkinan adalah menggunakan
connection_created
sinyal untuk mengeksekusi kode inisialisasi saat koneksi ke database.Jelas, solusi ini adalah untuk menjalankan kode satu kali per koneksi basis data, bukan sekali per proyek dimulai. Jadi Anda akan menginginkan nilai yang masuk akal untuk
CONN_MAX_AGE
pengaturan sehingga Anda tidak menjalankan kembali kode inisialisasi pada setiap permintaan. Perhatikan juga bahwa server pengembangan mengabaikanCONN_MAX_AGE
, jadi Anda AKAN menjalankan kode sekali per permintaan dalam pengembangan.99% dari waktu ini adalah ide yang buruk - kode inisialisasi database harus dalam migrasi - tetapi ada beberapa kasus penggunaan di mana Anda tidak dapat menghindari inisialisasi terlambat dan peringatan di atas dapat diterima.
sumber
my_receiver
fungsi putuskan sendiri dariconnection_created
sinyal, khususnya, tambahkan berikut ini kemy_receiver
fungsi:connection_created.disconnect(my_receiver)
.jika Anda ingin mencetak "hello world" satu kali ketika Anda menjalankan server, letakkan print ("hello world") di luar kelas StartupMiddleware
sumber