django अमूर्त मॉडल बनाम नियमित विरासत


86

वाक्यविन्यास के अलावा, एक django सार मॉडल का उपयोग करने और django मॉडल के साथ सादे अजगर विरासत के उपयोग के बीच क्या अंतर है? फायदा और नुकसान?

अद्यतन करें: मुझे लगता है कि मेरा प्रश्न गलत समझा गया था और मुझे एक सार मॉडल और एक वर्ग के बीच अंतर के लिए प्रतिक्रियाएं मिलीं जो django.db.models.Model से विरासत में मिली हैं। मैं वास्तव में एक मॉडल वर्ग के बीच का अंतर जानना चाहता हूं जो एक django सार वर्ग (Meta: abstract = True) से प्राप्त होता है और एक सादा पायथन वर्ग जो कि 'ऑब्जेक्ट' (और मॉडल नहीं। मॉडल) से विरासत में मिला है।

यहाँ एक उदाहरण है:

class User(object):
   first_name = models.CharField(..

   def get_username(self):
       return self.username

class User(models.Model):
   first_name = models.CharField(...

   def get_username(self):
       return self.username

   class Meta:
       abstract = True

class Employee(User):
   title = models.CharField(...

1
यह दो विरासत दृष्टिकोण charlesleifer.com/blog/django-patterns-model-inheritance
jpotts18

जवाबों:


152

मैं वास्तव में एक मॉडल वर्ग के बीच का अंतर जानना चाहता हूं जो एक django सार वर्ग (Meta: abstract = True) से प्राप्त होता है और एक सादा पायथन वर्ग जो कि 'ऑब्जेक्ट' (और मॉडल नहीं। मॉडल) से विरासत में मिला है।

Django केवल उपवर्गों के लिए तालिकाओं का निर्माण करेगा models.Model, इसलिए पूर्व ...

class User(models.Model):
   first_name = models.CharField(max_length=255)

   def get_username(self):
       return self.username

   class Meta:
       abstract = True

class Employee(User):
   title = models.CharField(max_length=255)

... की तर्ज पर एक एकल तालिका तैयार की जाएगी ...

CREATE TABLE myapp_employee
(
    id         INT          NOT NULL AUTO_INCREMENT,
    first_name VARCHAR(255) NOT NULL,
    title      VARCHAR(255) NOT NULL,
    PRIMARY KEY (id)
);

... जबकि बाद ...

class User(object):
   first_name = models.CharField(max_length=255)

   def get_username(self):
       return self.username

class Employee(User):
   title = models.CharField(max_length=255)

... कोई तालिका उत्पन्न नहीं होगी।

आप कुछ ऐसा करने के लिए कई विरासत का उपयोग कर सकते हैं ...

class User(object):
   first_name = models.CharField(max_length=255)

   def get_username(self):
       return self.username

class Employee(User, models.Model):
   title = models.CharField(max_length=255)

... जो एक तालिका बनाएगा, लेकिन यह Userकक्षा में परिभाषित क्षेत्रों की अनदेखी करेगा , इसलिए आप इस तरह एक तालिका के साथ समाप्त करेंगे ...

CREATE TABLE myapp_employee
(
    id         INT          NOT NULL AUTO_INCREMENT,
    title      VARCHAR(255) NOT NULL,
    PRIMARY KEY (id)
);

3
धन्यवाद, यह मेरे सवाल का जवाब देता है। यह अभी भी स्पष्ट नहीं है कि प्रथम_नाम कर्मचारी के लिए क्यों नहीं बनाया गया है।
22

4
@rpq आपको Django के सोर्स कोड की जांच करनी होगी, लेकिन IIRC इसमें कुछ मेटाक्लास हैकरी का उपयोग करता है models.Model, इसलिए सुपरक्लास में परिभाषित फ़ील्ड को नहीं उठाया जाएगा (जब तक कि वे उपवर्ग भी न हों models.Model)।
आया

@rpq मुझे पता है कि यह 7 साल पहले था जब आपने पूछा था, लेकिन ModelBase' __new__कॉल ' में , यह क्लास की विशेषताओं की प्रारंभिक जाँच करता है, जाँचता है कि क्या विशेषता मान में एक contribute_to_classविशेषता है - Fieldsकि आप सभी को Django में परिभाषित करते हैं, इसलिए वे एक विशेष डिक्शनरी में शामिल हैं, जिसे contributable_attrsअंततः DDL उत्पन्न करने के लिए प्रवास के दौरान पास किया जाता है।
यू चेन

1
हर बार जब मैं डीजे को देखता हूं तो मैं रोना चाहता हूं, क्यों ????? क्यों सभी बकवास, क्यों फ्रेमवर्क को भाषा की तुलना में पूरी तरह से अलग व्यवहार करना है? कम से कम विस्मय के सिद्धांत के बारे में क्या? यह व्यवहार (जैसे django में ALMOST बाकी सब कुछ) ऐसा कोई भी नहीं है जो अजगर को समझता है।
ई। सेरा

36

एक सार मॉडल प्रत्येक सबचाइल्ड के लिए कॉलम के पूरे सेट के साथ एक टेबल बनाता है, जबकि "सादे" पायथन इनहेरिटेंस का उपयोग लिंक्ड टेबल (उर्फ "मल्टी-टेबल इनहेरिटेंस") का एक सेट बनाता है। उस मामले पर विचार करें जिसमें आपके दो मॉडल हैं:

class Vehicle(models.Model):
  num_wheels = models.PositiveIntegerField()


class Car(Vehicle):
  make = models.CharField(…)
  year = models.PositiveIntegerField()

यदि Vehicleएक सार मॉडल है, तो आपके पास एक एकल तालिका होगी:

app_car:
| id | num_wheels | make | year

हालाँकि, यदि आप सादे पायथन वंशानुक्रम का उपयोग करते हैं, तो आपके पास दो तालिकाएँ होंगी:

app_vehicle:
| id | num_wheels

app_car:
| id | vehicle_id | make | model

जहां vehicle_idएक पंक्ति के लिए लिंक है, app_vehicleउसमें कार के लिए पहियों की संख्या भी होगी।

अब, Django इसे अच्छी तरह से ऑब्जेक्ट फॉर्म में डाल देगा ताकि आप num_wheelsएक विशेषता के रूप में एक्सेस कर सकें Car, लेकिन डेटाबेस में अंतर्निहित प्रतिनिधित्व अलग होगा।


अपडेट करें

आपके अपडेट किए गए प्रश्न को संबोधित करने के लिए, एक Django अमूर्त वर्ग से विरासत और पायथन से विरासत में मिला अंतर objectयह है कि पूर्व को डेटाबेस ऑब्जेक्ट के रूप में माना जाता है (इसलिए इसके लिए तालिकाओं को डेटाबेस में सिंक किया जाता है) और इसका व्यवहार एक है Model। एक सादे पायथन objectसे प्रवेश करने से उन गुणों में से कोई भी वर्ग (और उसके उपवर्ग) नहीं मिलता है।


1
करना models.OneToOneField(Vehicle)भी मॉडल वर्ग को विरासत में देने के बराबर होगा, है ना? और इसका परिणाम दो अलग-अलग तालिकाओं में होगा, है ना?
रफय

1
@MohammadRafayAleem: हाँ, लेकिन जब इनहेरिटेंस का उपयोग करते हुए, Django बनायेगा, जैसे, num_wheelsa पर एक विशेषता car, जबकि OneToOneFieldआपके पास एक ऐसा करने के लिए होगा कि आप खुद को डेरेफेर करें।
मियादी

मैं नियमित वंशानुक्रम के साथ कैसे बल दे सकता हूं कि सभी फ़ील्ड app_carतालिका के लिए पुन: उत्पन्न होते हैं, ताकि इसके पास सूचक num_wheelsहोने के बजाय फ़ील्ड भी हो vehicle_id?
डॉन Grem

@ डोरिनग्रेकू: आधार वर्ग को एक अमूर्त मॉडल बनाएं और उसी से विरासत में मिला।
मिपाडी

@mipadi की समस्या यह है कि मैं बेस क्लास को अमूर्त नहीं बना सकता, इसका उपयोग पूरे प्रोजेक्ट में किया जा रहा है।
डॉन Grem

13

मुख्य अंतर यह है कि मॉडल के लिए डेटाबेस टेबल कैसे बनाए जाते हैं। यदि आप abstract = TrueDjango के बिना इनहेरिटेंस का उपयोग करते हैं, तो माता-पिता और बच्चे के मॉडल दोनों के लिए एक अलग तालिका बनाएंगे जो प्रत्येक मॉडल में परिभाषित फ़ील्ड रखती है।

यदि आप abstract = Trueबेस क्लास के लिए उपयोग करते हैं , तो Django केवल उन वर्गों के लिए एक तालिका बनाएगा जो बेस क्लास से विरासत में मिलती हैं - कोई फर्क नहीं पड़ता कि क्या फ़ील्ड बेस क्लास या इनहेरिटिंग क्लास में परिभाषित हैं।

पेशेवरों और विपक्ष आपके आवेदन की वास्तुकला पर निर्भर करते हैं। निम्नलिखित उदाहरण मॉडल को देखते हुए:

class Publishable(models.Model):
    title = models.CharField(...)
    date = models.DateField(....)

    class Meta:
        # abstract = True

class BlogEntry(Publishable):
    text = models.TextField()


class Image(Publishable):
    image = models.ImageField(...)

यदि Publishableवर्ग सार नहीं है Django कॉलम के साथ publishables के लिए एक मेज पैदा करेगा titleऔर dateऔर अलग-अलग तालिकाओं BlogEntryऔर Image। इस समाधान का लाभ यह होगा कि आप आधार मॉडल में परिभाषित किए गए फ़ील्ड के लिए सभी पबलीशबल्स को क्वेरी करने में सक्षम हैं , भले ही वे ब्लॉग प्रविष्टियाँ या चित्र हों। लेकिन इसलिए Django को जॉइन करना होगा यदि आप उदाहरण के लिए इमेजेस के लिए क्वेश्चन करते हैं ... यदि Publishable abstract = TrueDjango बनाने के लिए एक टेबल नहीं बनाई जाएगी Publishable, लेकिन केवल ब्लॉग एंट्रीज और इमेजेज के लिए, जिसमें सभी फील्ड्स (इनहेरिट की गई) भी होंगी । यह आसान होगा क्योंकि किसी भी ऑपरेशन जैसे कि पाने के लिए किसी जॉइन की जरूरत नहीं होगी।

मॉडल विरासत पर Django के दस्तावेज़ भी देखें ।


9

बस कुछ ऐसा जोड़ना चाहते थे जो मैंने अन्य उत्तरों में नहीं देखा है।

अजगर वर्गों के साथ, क्षेत्र का नाम छिपाना मॉडल विरासत के साथ अनुमति नहीं है

उदाहरण के लिए, मैंने एक प्रयोग के मामले के साथ मुद्दों का प्रयोग किया है:

मैं एक मॉडल Django के प्रमाणन से इनहेरिट था PermissionMixin :

class PermissionsMixin(models.Model):
    """
    A mixin class that adds the fields and methods necessary to support
    Django's Group and Permission model using the ModelBackend.
    """
    is_superuser = models.BooleanField(_('superuser status'), default=False,
        help_text=_('Designates that this user has all permissions without '
                    'explicitly assigning them.'))
    groups = models.ManyToManyField(Group, verbose_name=_('groups'),
        blank=True, help_text=_('The groups this user belongs to. A user will '
                                'get all permissions granted to each of '
                                'his/her group.'))
    user_permissions = models.ManyToManyField(Permission,
        verbose_name=_('user permissions'), blank=True,
        help_text='Specific permissions for this user.')

    class Meta:
        abstract = True

    # ...

तब मैं अपने mixin जो अन्य बातों के अलावा मैं इसे ओवरराइड करने के लिए करना चाहता था था related_nameके groupsक्षेत्र। तो यह कमोबेश इसी तरह था:

class WithManagedGroupMixin(object):
    groups = models.ManyToManyField(Group, verbose_name=_('groups'),
        related_name="%(app_label)s_%(class)s",
        blank=True, help_text=_('The groups this user belongs to. A user will '
                            'get all permissions granted to each of '
                            'his/her group.'))

मैं इस 2 मिश्रण का उपयोग कर रहा था:

class Member(PermissionMixin, WithManagedGroupMixin):
    pass

तो हाँ, मुझे उम्मीद है कि यह काम करेगा लेकिन ऐसा नहीं हुआ। लेकिन यह मुद्दा अधिक गंभीर था क्योंकि मुझे जो त्रुटि मिल रही थी वह बिल्कुल भी मॉडल की ओर इशारा नहीं कर रही थी, मुझे नहीं पता था कि क्या गलत हो रहा है।

इसे हल करने की कोशिश करते हुए मैंने अनियमित रूप से अपने मिश्रण को बदलने और इसे अमूर्त मॉडल मिश्रण में बदलने का फैसला किया। त्रुटि इसमें बदल गई:

django.core.exceptions.FieldError: Local field 'groups' in class 'Member' clashes with field of similar name from base class 'PermissionMixin'

जैसा कि आप देख सकते हैं, यह त्रुटि बताती है कि क्या चल रहा है।

यह एक बहुत बड़ा अंतर था, मेरी राय में :)


मेरे पास एक प्रश्न है जो यहां मुख्य प्रश्न से संबंधित नहीं है, लेकिन आपने इसे आखिरकार (समूहों के क्षेत्र के संबंधित_नाम को ओवरराइड करने में) कैसे लागू किया?
kalo

@ एकल IIRC मैंने सिर्फ नाम को पूरी तरह से बदल दिया है। विरासत में मिले खेतों को हटाने या बदलने का कोई तरीका नहीं है।
एड्रियन

हां, मैं इस पर हार मानने के लिए लगभग तैयार था, जब मुझे योगदान_को_क्लास पद्धति का उपयोग करने का एक तरीका मिला।
kalo

1

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

यदि आपको आधार "ऑब्जेक्ट" संस्करण विरासत में मिला है, तो आपका कर्मचारी वर्ग सिर्फ एक मानक वर्ग होगा, और first_name डेटाबेस तालिका का हिस्सा नहीं बनेगा। आप इसके साथ कोई प्रपत्र नहीं बना सकते हैं या किसी अन्य Django सुविधाओं का उपयोग नहीं कर सकते हैं।

यदि आप मॉडल का माइग्रेट करते हैं। मोडल संस्करण, आपके कर्मचारी वर्ग में Django मॉडल की सभी विधियाँ होंगी, और यह डेटाबेस फ़ील्ड के रूप में first_name फ़ील्ड को इनहेरिट करेगा, जिसका उपयोग किसी प्रपत्र में किया जा सकता है।

प्रलेखन के अनुसार, ए सार मॉडल "पायथन स्तर पर सामान्य जानकारी को फैक्टर करने का एक तरीका प्रदान करता है, जबकि अभी भी डेटाबेस स्तर पर केवल एक प्रति बच्चा मॉडल तालिका बना रहा है।"


0

मैं ज्यादातर मामलों में अमूर्त वर्ग को पसंद करूंगा क्योंकि यह एक अलग तालिका नहीं बनाता है और ओआरएम को डेटाबेस में जुड़ने की आवश्यकता नहीं है। और अमूर्त वर्ग का उपयोग Django में बहुत सरल है

class Vehicle(models.Model):
    title = models.CharField(...)
    Name = models.CharField(....)

    class Meta:
         abstract = True

class Car(Vehicle):
    color = models.CharField()

class Bike(Vehicle):
    feul_average = models.IntegerField(...)
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.