जब Django केवल ONCE प्रारंभ करता है तो कोड निष्पादित करें?


177

मैं एक Django मिडलवेयर क्लास लिख रहा हूं जिसे मैं केवल एक बार स्टार्टअप पर अमल करना चाहता हूं, कुछ अन्य अभिगृहीत कोड को इनिशियलाइज़ करना है। मैंने sdolan द्वारा पोस्ट किए गए बहुत अच्छे समाधान का अनुसरण किया है , लेकिन "हैलो" संदेश टर्मिनल पर दो बार आउटपुट है । उदाहरण के लिए

from django.core.exceptions import MiddlewareNotUsed
from django.conf import settings

class StartupMiddleware(object):
    def __init__(self):
        print "Hello world"
        raise MiddlewareNotUsed('Startup complete')

और मेरे Django सेटिंग फ़ाइल में, मुझे MIDDLEWARE_CLASSESसूची में शामिल वर्ग मिला है ।

लेकिन जब मैं रनसोवर का उपयोग करके Django चलाता हूं और एक पृष्ठ का अनुरोध करता हूं, तो मैं टर्मिनल में मिलता हूं

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

कोई भी विचार क्यों "हैलो वर्ल्ड" दो बार छपा है? धन्यवाद।


1
सिर्फ जिज्ञासा के लिए, क्या आपको पता चला कि init .py में कोड दो बार निष्पादित क्यों होता है ?
उत्पाती

3
@ अधिक बार यह केवल रनसर के तहत दो बार निष्पादित होता है ... ऐसा इसलिए है क्योंकि रनसरवर पहले उन्हें निरीक्षण करने के लिए ऐप्स को लोड करता है और फिर वास्तव में सर्वर शुरू करता है। रनर के ऑटोरैलोएड पर भी कोड केवल एक बार निष्पादित होता है।
पाइकलर

1
वाह मैं यहाँ रहा हूँ .... तो टिप्पणी @Pykler के लिए फिर से धन्यवाद, यही मैं सोच रहा था।
पश्चिमीगुन

जवाबों:


112

नीचे पाइक्लर के उत्तर से अद्यतन: Django 1.7 अब इसके लिए एक हुक है


इस तरह मत करो।

आप एक बार की स्टार्टअप चीज के लिए "मिडलवेयर" नहीं चाहते हैं।

आप शीर्ष-स्तर में कोड निष्पादित करना चाहते हैं urls.py। उस मॉड्यूल को एक बार आयात और निष्पादित किया जाता है।

urls.py

from django.confs.urls.defaults import *
from my_app import one_time_startup

urlpatterns = ...

one_time_startup()

1
@Andrei: प्रबंधन कमांड पूरी तरह से एक अलग समस्या है। सभी प्रबंधन आदेशों से पहले विशेष वन-टाइम स्टार्टअप का विचार समझना मुश्किल है। आपको कुछ विशिष्ट प्रदान करना होगा । शायद एक और सवाल में।
S.Lott

1
Urls.py में सरल पाठ मुद्रित करने की कोशिश की, लेकिन कोई आउटपुट नहीं था। क्या हो रहा है ?
स्टीव के

8
Urls.py कोड को पहले अनुरोध पर ही निष्पादित किया जाता है (अनुमान करें कि यह @SteveK के प्रश्न का उत्तर देता है) (django 1.5)
lajarre

4
यह प्रत्येक कार्यकर्ता के लिए एक बार निष्पादित होता है, मेरे मामले में, इसे कुल 3 बार निष्पादित किया जाता है।
राफेल

9
@halilpazarlama यह उत्तर पुराना है - आपको पाइकलर के उत्तर का उपयोग करना चाहिए।
मार्क चेकरियन

271

अद्यतन: Django 1.7 अब इसके लिए एक हुक है

फ़ाइल: myapp/apps.py

from django.apps import AppConfig
class MyAppConfig(AppConfig):
    name = 'myapp'
    verbose_name = "My Application"
    def ready(self):
        pass # startup code here

फ़ाइल: myapp/__init__.py

default_app_config = 'myapp.apps.MyAppConfig'

Django के लिए <1.7

नंबर एक का जवाब अब काम नहीं करता है, पहले अनुरोध पर urls.py लोड किया गया है।

हाल ही में क्या काम किया है स्टार्टअप कोड को अपने किसी भी INSTALLED_APPS init .py उदाहरण के लिए रखा हैmyapp/__init__.py

def startup():
    pass # load a big thing

startup()

उपयोग करते समय ./manage.py runserver... इसे दो बार निष्पादित किया जाता है, लेकिन ऐसा इसलिए है क्योंकि रनवेवर में पहले मॉडल आदि को मान्य करने के लिए कुछ तरकीबें हैं ... सामान्य तैनाती या यहां तक ​​कि जब चलाने वाले ऑटो पुनः लोड करता है, तो इसे केवल एक बार निष्पादित किया जाता है।


4
मुझे लगता है कि यह परियोजना को लोड करने वाली प्रत्येक प्रक्रिया के लिए निष्पादित होता है। इसलिए, मैं यह नहीं सोच सकता कि यह किसी भी तैनाती परिदृश्य के तहत पूरी तरह से काम क्यों नहीं करेगा। यह प्रबंधन आदेशों के लिए काम करता है। +1
स्काईलार सेवेलैंड

2
मैं समझता हूँ कि इस समाधान कुछ मनमाना कोड निष्पादित करने के लिए सर्वर शुरू होता है लेकिन यह संभव है करने के लिए जब इस्तेमाल किया जा सकता का हिस्सा कुछ डेटा लोड किया जाएगा? उदाहरण के लिए, मैं एक ऐसी वस्तु को लोड करना चाहता हूं जिसमें एक विशाल मैट्रिक्स हो, इस मैट्रिक्स को एक चर में रखें और इसका उपयोग वेब एप के माध्यम से करें, प्रत्येक अनुरोध में एक उपयोगकर्ता कर सकता है। क्या ऐसी कोई चीज है?
पैट्रिक

2
प्रलेखन का कहना है कि यह किसी डेटाबेस इंटरैक्शन को करने के लिए जगह नहीं है। यह बहुत सारे कोड के लिए अनुपयुक्त है। यह कोड कहां जा सकता है?
मार्क

3
संपादित करें: एक संभव हैक कमांड लाइनों के तर्कों की जांच करने के लिए है (x 'के लिए sys.argv में x के लिए [' makemigrations ',' माइग्रेट ')]
Conchylicultor

2
यदि आपकी स्क्रिप्ट दो बार चल रही है तो आप इस उत्तर को देखें: stackoverflow.com/a/28504072/5443056
ब्राडेन होल

37

यह सवाल Django परियोजनाओं के लिए ब्लॉग पोस्ट एंट्री पॉइंट हुक में अच्छी तरह से उत्तर दिया गया है , जो Django> = 1.4 के लिए काम करेगा।

मूल रूप से, आप ऐसा करने के <project>/wsgi.pyलिए उपयोग कर सकते हैं , और यह केवल एक बार चलाया जाएगा, जब सर्वर शुरू होता है, लेकिन तब नहीं जब आप कमांड चलाते हैं या किसी विशेष मॉड्यूल को आयात करते हैं।

import os
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "{{ project_name }}.settings")

# Run startup code!
....

from django.core.wsgi import get_wsgi_application
application = get_wsgi_application()

फिर से एक टिप्पणी जोड़ने के लिए पुष्टि करें कि यह विधि केवल एक बार कोड निष्पादित करेगी। किसी भी लॉकिंग तंत्र की आवश्यकता नहीं है।
ATOzTOA

लिपियों को यहाँ जोड़ा गया है, जब परीक्षण ढांचा शुरू होता है, तब क्रियान्वित नहीं किया जाता है
लेविसॉ

इस जवाब ने उन समाधानों के लिए ढाई दिन की खोज को समाप्त कर दिया जो बस काम नहीं करते थे।
नील मुनरो

3
ध्यान दें कि यह तब निष्पादित होता है जब वेबसाइट पर पहला अनुरोध किया जाता है, न कि जब आप अपाचे शुरू करते हैं।
user984003

18

अगर यह किसी व्यक्ति की मदद करता है, तो पाइकलर के जवाब के अलावा , "--noreload" विकल्प रनस्वर को स्टार्टअप पर कमांड को दो बार निष्पादित करने से रोकता है:

python manage.py runserver --noreload

लेकिन वह आदेश अन्य कोड के परिवर्तनों के बाद भी रनर को पुनः लोड नहीं करेगा।


1
धन्यवाद इसने मेरी समस्या हल कर दी! मुझे आशा है कि जब मैं इसे लागू करता हूं तो ऐसा नहीं होता है
गैबो

2
एक विकल्प के रूप में, आप की सामग्री की जांच कर सकते हैं os.environ.get('RUN_MAIN')करने के लिए केवल अपने कोड निष्पादित मुख्य प्रक्रिया में एक बार (देखें stackoverflow.com/a/28504072 )
bdoering

हाँ, इस प्लस पाइक्लर के जवाब ने मेरे लिए भी काम किया, क्योंकि इसने कई ready(self)कॉल्स को रोका जबकि अभी भी उन्हें केवल एक बार ही शुरू किया जा सका है। चीयर्स!
डार्ककाइग्नस

Django runserverडिफ़ॉल्ट रूप से दो प्रक्रियाओं को अलग-अलग (भिन्न) संख्याओं के साथ शुरू करता है। --noreloadयह एक प्रक्रिया शुरू करता है।
यूजीन जीआर। फिलिपोव

15

जैसा कि @Pykler द्वारा सुझाया गया है, Django 1.7+ में आपको उसके उत्तर में बताए गए हुक का उपयोग करना चाहिए, लेकिन यदि आप चाहते हैं कि आपका फ़ंक्शन केवल तभी बुलाया जाए जब रन सर्वर को बुलाया जाता है (और माइग्रेशन, माइग्रेट, शेल, आदि बनाते समय नहीं कहा जाता है) ), और आप AppRegistryNotReady अपवादों से बचना चाहते हैं जो आपको निम्न प्रकार से करने होंगे:

फ़ाइल: myapp/apps.py

import sys
from django.apps import AppConfig

class MyAppConfig(AppConfig):
    name = 'my_app'

    def ready(self):
        if 'runserver' not in sys.argv:
            return True
        # you must import your modules here 
        # to avoid AppRegistryNotReady exception 
        from .models import MyModel 
        # startup code here

12
क्या यह उत्पादन मोड में चलता है? उत्पादों में AFAIK। मोड वहाँ कोई "धावक" शुरू कर दिया है।
nerdoc

इसके लिए धन्यवाद! मेरे पास मेरे ऐप में उन्नत पायथन शेड्यूलर है और जब मैं प्रबंधन थिंकपैड कमांड चलाते हुए शेड्यूलर को चलाना नहीं चाहता था।
ल्यूक

4

ध्यान दें कि आप डेटाबेस से कनेक्ट नहीं कर सकते हैं या AppConfig.readyफ़ंक्शन के अंदर मॉडल के साथ बातचीत कर सकते हैं ( डॉक्स में चेतावनी देखें )।

यदि आपको अपने स्टार्ट-अप कोड में डेटाबेस के साथ सहभागिता करने की आवश्यकता है, तो डेटाबेस से connection_createdकनेक्शन पर प्रारंभ कोड को निष्पादित करने के लिए सिग्नल का उपयोग करने की एक संभावना है ।

from django.dispatch import receiver
from django.db.backends.signals import connection_created

@receiver(connection_created)
def my_receiver(connection, **kwargs):
    with connection.cursor() as cursor:
        # do something to the database

जाहिर है, यह समाधान डेटाबेस कनेक्शन के अनुसार एक बार कोड चलाने के लिए है, एक बार प्रोजेक्ट शुरू होने के बाद नहीं। तो आप CONN_MAX_AGEसेटिंग के लिए एक समझदार मूल्य चाहते हैं ताकि आप हर अनुरोध पर आरंभीकरण कोड फिर से नहीं चला रहे हैं। यह भी ध्यान दें कि विकास सर्वर अनदेखा करता है CONN_MAX_AGE, इसलिए आप विकास में अनुरोध के अनुसार एक बार कोड चलाएंगे।

99% समय यह एक बुरा विचार है - डेटाबेस इनिशियलाइज़ेशन कोड को माइग्रेशन में जाना चाहिए - लेकिन कुछ उपयोग के मामले हैं जहां आप देर से आरंभीकरण से बच नहीं सकते हैं और ऊपर दिए गए चेतावनी स्वीकार्य हैं।


2
यह एक अच्छा समाधान है यदि आपको अपने स्टार्टअप कोड में डेटाबेस तक पहुंचने की आवश्यकता है। इसे केवल एक बार चलाने के लिए प्राप्त करने के लिए एक सरल विधि यह है कि my_receiverफ़ंक्शन स्वयं connection_createdसिग्नल से डिस्कनेक्ट हो , विशेष रूप से, my_receiverफ़ंक्शन को निम्नलिखित जोड़ें connection_created.disconnect(my_receiver):।
एलन

1

यदि आप "हेल्लो वर्ल्ड" प्रिंट करना चाहते हैं, तो एक बार जब आप सर्वर चलाते हैं, तो क्लास स्टार्ट आउटमिलवेयर से प्रिंट ("हैलो वर्ल्ड") डालें

from django.core.exceptions import MiddlewareNotUsed
from django.conf import settings

class StartupMiddleware(object):
    def __init__(self):
        #print "Hello world"
        raise MiddlewareNotUsed('Startup complete')

print "Hello world"

3
हाय ऑस्कर! SO पर, हम पसंद करते हैं कि उत्तर में अंग्रेजी में स्पष्टीकरण शामिल हो, न कि केवल कोड। क्या आप कृपया बता सकते हैं कि आपका कोड समस्या को कैसे / क्यों ठीक करता है?
मैक्स वॉन हिप्पेल
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.