2017-06-29 15 views
7

कोई भी जानता है कि एक विदेशी क्षेत्र कैसे बनाएं और इसे हमेशा एक ही मॉडल पर इंगित करें, अब तक मुझे यह मिला है।कस्टम django विदेशी क्षेत्र

class PanMachineTimeUnitField(models.ForeignKey): 
    def __init__(self, **kwargs): 
     to = 'panbas.PanBasTimeUnit' 
     kwargs['verbose_name'] = _('Machine Unit') 
     kwargs['related_name'] = 'machine_unit' 
     super(PanMachineTimeUnitField, self).__init__(to, **kwargs) 

लेकिन शुरुआत में मुझे त्रुटियां मिलीं। मैं की तरह उपयोग करने के लिए,

machine_unit = PanMachineTimeUnitField() 

आगे कोई जरूरत घोषणाओं करना है।

संपादित करें: मुझे यह चाहिए क्योंकि, मेरे पास यह विदेशीकुछ कुछ स्थानों पर शांत रहेगा। यदि मैं क्षेत्र के verbose_name को बदलना चाहता हूं, तो मैं चाहता हूं कि मेरे सभी फ़ील्ड इस परिवर्तन से प्रभावित हों। Verbose नाम एक उदाहरण था, यह एक और विशेषता हो सकती है।

मैं डिफ़ॉल्ट रूप से घोषित करने के लिए सेटिंग्स py का उपयोग नहीं करना चाहता हूं।

+0

आपकी त्रुटियां पोस्ट कर सकते हैं? – Todor

उत्तर

8

मेरा सुझाव है कि आप ForeignKey की एक इसी तरह पहले से कॉन्फ़िगर उदाहरण बनाने के लिए केवल एक सरल समारोह का उपयोग करें: (ForeignKey के उपवर्ग का एक उदाहरण नहीं)

def pan_machine_time_unit_field(**kwargs): 
    othermodel = 'panbas.PanBasTimeUnit' 
    on_delete = models.DO_NOTHING # or what you need 
    kwargs['verbose_name'] = 'Machine Unit' 
    kwargs.setdefault('related_name', '+') 
    # or: kwargs.setdefault('related_name', "%(app_label)s_%(class)s_related", 
    return models.ForeignKey(othermodel, on_delete, **kwargs) 

class C(models.Model): 
    machine_unit = pan_machine_time_unit_field() 
    # or: 
    # machine_unit = pan_machine_time_unit_field(related_name='klass_c_children') 

related_name विशेषता में नाम के लिए प्रयोग किया जाता है othermodel की लक्षित ऑब्जेक्ट से संबंधित सभी ऑब्जेक्ट्स से पिछड़ा संबंध। यह नाम अन्य मॉडेल ('panbas.PanBasTimeUnit', आमतौर पर ऐप और क्लास नाम के साथ कुछ अद्वितीय होना चाहिए) या वह नाम '+' हो सकता है यदि आप पिछड़ा संबंध क्वेरी सेट नहीं बनाना चाहते हैं। उदाहरण में दोनों प्रकारों को शामिल किया गया है। on_delete भी याद रखें।

यदि आपको वास्तव में उप-वर्ग बनाने की आवश्यकता होगी (जो अधिक विधियों को अनुकूलित करने की आवश्यकता है तो समझ में आता है), आपको माइग्रेशन के लिए deconstruct विधि भी परिभाषित करनी होगी। अगर आपको बाद में इस तरह के सबक्लास को संशोधित करने की आवश्यकता है तो यह जटिल होगा। migrations on a custom field के कारण इसे कभी भी हटाया जा सकता है, नाम बदल दिया जा सकता है। दूसरी ओर, यदि आप सीधे फ़ंक्शन द्वारा विदेशीकी का एक साधारण उदाहरण बनाते हैं, तो माइग्रेशन के बारे में सभी को अनदेखा किया जा सकता है।


संपादित

वैकल्पिक रूप से आपको लगता है कि क्षेत्र के साथ एक abstract base model बना सकते हैं और विरासत या multiple inheritance द्वारा नए मॉडल बना सकते हैं:

class WithPanBasTimeUnit(models.Model): 
    machine_unit = models.ForeignKey(
     'panbas.PanBasTimeUnit', 
     models.DO_NOTHING, 
     verbose_name=_('Machine Unit'), 
     related_name='%(app_label)s_%(class)s_related' 
    ) 

    class Meta: 
     abstract = True 

class ExampleModel(WithPanBasTimeUnit, ...or more possible base models...): 
    ... other fields 

यह समाधान (गलत SOUTION Ykh से प्रेरित) उपयोगी यदि आप उस क्षेत्र के साथ मॉडल में एक विधि जोड़ना चाहते हैं या अधिक फ़ील्ड एक साथ जोड़ना चाहते हैं, अन्यथा मूल समाधान आसान है आर।

6
class PanBasTimeUnit(models.Model): 
    machine_unit = models.ForeignKey('self', blank=True, null=True, 
           verbose_name=u'parent') 

उपयोग 'self' या 'panbas.PanBasTimeUnit' ठीक होगा।

+1

मैं विदेशीकी को कोई पैरामीटर नहीं देना चाहता हूं "कोई और घोषणा की आवश्यकता नहीं है।" – durdenk

+0

यह एक PanabasTimeUnit ऑब्जेक्ट से अन्य PanBasTimeUnit ऑब्जेक्ट में एक अवांछित क्रॉस संदर्भ फ़ील्ड जोड़ देगा और यह प्रश्न के लिए उपयोगी कुछ भी हल नहीं करता है। मैं आपके समाधान को ठीक कर रहा हूं और इसे अपने उत्तर के अंत में जोड़ रहा हूं, क्योंकि यह एक टिप्पणी में बहुत लंबा है। – hynekcer

1

क्यों अपने प्रयास अपने काम करना चाहिए में सीधे machine_unit = models.ForeignKey(panbas.PanBasTimeUnit, verbose_name=_('Machine Unit'), related_name='machine_unit')) ?

+0

मेरे पास इस विदेशीकी को बहुत ही शांत स्थानों में रखा जाएगा, इसलिए मैं इसे एक ऐसे स्थान पर प्रबंधित करना चाहता हूं जहां मैं वर्बोज़ नाम बदलूं, ı सभी विदेशीकी वर्बोज़_नाम को बदलना चाहते हैं। – durdenk

+0

सेटिंग्स.py में वर्बोज़ नाम को सेट करने के बारे में क्या है: MY_VERBOSE_NAME = _ ('मशीन यूनिट'), और मॉडल में: machine_unit = models.ForeignKey (panbas.PanBasTimeUnit, verbose_name = settings.MY_VERBOSE_NAME, related_name = 'machine_unit')) – Yom86

3

एक मामूली संशोधन का उपयोग नहीं।

class PanMachineTimeUnitField(models.ForeignKey): 
    def __init__(self, **kwargs): 
     kwargs["to"] = 'panbas.PanBasTimeUnit' 
     kwargs['verbose_name'] = _('Machine Unit') 
     kwargs['related_name'] = 'machine_unit' 
     super(PanMachineTimeUnitField, self).__init__(**kwargs) 
4

आप एक ही related_name के साथ एक मॉडल के लिए कई विदेशी कुंजी नहीं हो सकता।

वास्तव में, PanBasTimeUnit उदाहरण पर, <instance>.machine_unit पर कॉल करते समय Django वापस कौन सा प्रबंधक होना चाहिए? यही कारण है कि आपको related models and abstract classes पर सावधान रहना होगा।

यदि आप अपने कोड में kwargs['related_name'] = 'machine_unit' हटाते हैं, तो इसे ठीक से काम करना चाहिए, और इसे kwargs['related_name'] = "%(app_label)s_%(class)s_related" या कुछ इसी तरह से बदलें।

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