2014-10-24 6 views
9

मैं Django 1.7 माइग्रेशन का उपयोग करता हूं, और विशेष रूप से, प्रारंभिक डेटा के साथ एक नव निर्मित डेटाबेस को पॉप्युलेट करना चाहता हूं। इस प्रकार, मैं इसके लिए डेटा माइग्रेशन का उपयोग करता हूं। यह इस तरह दिखता है:मैं Django माइग्रेशन के भीतर से सिग्नल कैसे भेज सकता हूं?

@receiver(signals.post_save, sender=django.contrib.auth.models.User) 
def add_user_details(sender, instance, created, **kwargs): 
    if created: 
     my_app.UserDetails.objects.create(user=instance) 

लेकिन:

def populate_with_initial_data(apps, schema_editor): 
    User = apps.get_model("auth", "User") 
    new_user = User.objects.create(username="nobody") 

class Migration(migrations.Migration): 

    ... 

    operations = [ 
     migrations.RunPython(populate_with_initial_data), 
    ] 

इसी समय, मैं हर नए उपयोगकर्ता के लिए UserDetails मॉडल का एक उदाहरण करना चाहते हैं यह संकेत प्रवास के बाहर ही काम करता है । कारण यह है कि apps.get_model("auth", "User")django.contrib.auth.models.User से काफी अलग है कि कोई सिग्नल नहीं भेजा जाता है। अगर मैं इसे मैन्युअल रूप से करने की कोशिश, इस तरह, यह विफल रहता है:

signals.post_save.send(django.contrib.auth.models.User, instance=julia, created=True) 

यह विफल रहता है क्योंकि तब, संकेत हैंडलर एक नईUserDetails एक ऐतिहासिकUser को O2O साथ ओर इशारा करते हुए बनाने की कोशिश:

ValueError: Cannot assign "<User: User object>": "UserDetails.user" must be a "User" instance. 

बमर।

ठीक है, मैं सिग्नल हैंडलर को सीधे कॉल कर सकता हूं। लेकिन मुझे एक कीवर्ड तर्क (और अन्य ऐतिहासिक वर्गों की आवश्यकता है) में ऐतिहासिक UserDetails कक्षा उत्तीर्ण करनी थी। इसके अलावा, UserDetails वाला ऐप इस डेटा माइग्रेशन वाला नहीं है, इसलिए यह एक बदसूरत निर्भरता होगी जो आसानी से टूट सकती है, उदा। यदि UserDetails ऐप INSTALLED_APPS से हटा दिया गया है।

तो, क्या यह केवल एक मौजूदा सीमा है जिसे मुझे बदसूरत कोड और फिक्समे टिप्पणी के साथ संबोधित करना है? या डेटा माइग्रेशन से सिग्नल भेजने का कोई तरीका है?

+0

आप इस के लिए एक समाधान मिला? –

+2

हां, signal.post_migrate का उपयोग कर क्योंकि यह * * कहा जाता है। लेकिन इसे अभी भी कोड की आवश्यकता है जो आवश्यक नहीं होना चाहिए। –

+0

आप उत्तर पोस्ट और के रूप में इस सवाल अनुत्तरित Django सवालों के शीर्ष पर बैठा है अपने खुद के जवाब को स्वीकार करना चाहिए। – dotcomly

उत्तर

3

आप ऐसा नहीं कर सकते (और नहीं करना चाहिए) क्योंकि जब आपका माइग्रेशन निष्पादित होता है, तो आपका UserDetails इस माइग्रेशन को लिखने से वास्तव में अलग हो सकता है। यही कारण है कि django (और दक्षिण) "जमे हुए मॉडल" का उपयोग करते हैं जो माइग्रेशन लिखते समय समान होते हैं।

"दुर्भाग्य से", आपको माइग्रेशन लिखने पर व्यवहार की अपेक्षा रखने के लिए अपने माइग्रेशन में अपना सिग्नल कोड जमा करना होगा।

एक साधारण उदाहरण समझने के लिए क्यों यह महत्वपूर्ण है वास्तविक मॉडल (या संकेतों आदि) का उपयोग नहीं करने के लिए एक प्रवास के अंदर:

आज, मैं इस हो सकता है:

class UserDetails(models.Model): 
    user = models.ForeignKey(...) 
    typo_fild = models.CharField(...) 

@receiver(signals.post_save, sender=django.contrib.auth.models.User) 
def add_user_details(sender, instance, created, **kwargs): 
    if created: 
     UserDetails.objects.create(user=instance, typo_fild='yo') 

फिर, मैं एक है डेटा माइग्रेशन (जिसे "populate_users" कहा जाता है) जो नए उपयोगकर्ता बनाते हैं और मैं इसके अंदर add_user_details निष्पादन को मजबूर करता हूं। यह ठीक है: यह आज काम करता है।

कल, मैं ठीक मेरी typo_fild - अंदर>typo_fieldUserDetails और add_user_details अंदर। डेटाबेस में फ़ील्ड का नाम बदलने के लिए एक नया स्कीमा माइग्रेशन बनाया गया है।

इस बिंदु पर, मेरी प्रवास "populate_users" असफल क्योंकि जब एक नया उपयोगकर्ता बनाया जाएगा, यह एक नई UserDetails एक क्षेत्र "typo_field" जिसके साथ बनाने के लिए अभी तक डेटाबेस में मौजूद नहीं है कोशिश करेंगे: इस क्षेत्र केवल अगले प्रवास के साथ डीबी में नाम बदल जाएगा।

तो, अगर मैं एक अच्छा माइग्रेशन रखना चाहता हूं जो किसी भी समय काम करेगा, तो मुझे माइग्रेशन के अंदर add_user_details के व्यवहार की प्रतिलिपि बनाना होगा। add_user_details का यह फ्रीज apps.get_model("myapp", "UserDetails") के माध्यम से जमे हुए मॉडल UserDetails का उपयोग करें और एक नया UserDetailstypo_fild जो भी जमे हुए है के साथ बनाने के लिए होगा।

+1

यदि आप चाहें तो आप हमेशा अपने पैर में शूट कर सकते हैं। आखिरकार, अन्य सिग्नल * भेजे गए हैं, और अब मैं इन मुद्दों को हल करने के लिए उनका उपयोग करता हूं। यदि आप मॉडल में समस्याग्रस्त परिवर्तन लागू करते हैं, तो आप सिग्नल हैंडलर में आत्मनिरीक्षण का उपयोग कर सकते हैं। "लगातार मामला सरल बनाएं, और दुर्लभ मामला संभव है।" –

संबंधित मुद्दे