ميراث Django متعدد الطاولة مقابل تحديد علاقة OnetOone الصريحة في النماذج

StackOverflow https://stackoverflow.com/questions/1796556

  •  22-09-2019
  •  | 
  •  

سؤال

آمل أن يكون كل هذا منطقيًا :) سأوضح عبر التعليقات إذا لزم الأمر. أيضًا ، أقوم بتجربة استخدام نص جريء في هذا السؤال ، وسأقوم بتحريره إذا كنت (أو أنت) أجدها تشتت انتباهها. مع ذلك من الطريق ...

باستخدام Django.contrib.auth يمنحنا المستخدم والمجموعة ، من بين أشياء مفيدة أخرى لا يمكنني القيام بها بدون (مثل المراسلة الأساسية).

في تطبيقي لدي عدة أنواع مختلفة من المستخدمين. يمكن أن يكون المستخدم من نوع واحد فقط. يمكن التعامل مع ذلك بسهولة من قبل مجموعات ، مع القليل من العناية الإضافية. ومع ذلك ، يرتبط هؤلاء المستخدمون المختلفين ببعضهم البعض في التسلسل الهرمي / العلاقات.

لنلقي نظرة على هؤلاء المستخدمين: -

مديري المدارس - مستخدمي "المستوى الأعلى"

المسؤولون - كل مسؤول يقدم تقارير إلى مدير

المنسقون - كل منسق يقدم تقارير إلى مسؤول

وبصرف النظر عن هذه هناك أنواع مستخدمين أخرى غير مرتبطة مباشرة, ، ولكن قد يتم ربطها لاحقًا. على سبيل المثال ، "الشركة" هي نوع آخر من المستخدمين ، ويمكن أن يكون لها "منتجات" مختلفة ، وقد يتم الإشراف على المنتجات بواسطة "منسق". "المشتري" هو نوع آخر من المستخدمين الذين قد يشترون المنتجات.

الآن كل هذه لدى المستخدمين العديد من السمات الأخرى ، بعضها شائع في جميع أنواع المستخدمين وبعضها متميز فقط لنوع مستخدم واحد. على سبيل المثال ، يجب أن يكون لجميع أنواع المستخدمين عنوانًا. من ناحية أخرى ، فإن المستخدم الرئيسي هو الوحيد الذي ينتمي إلى "BranchOffice".

نقطة أخرى ، والتي ذكرت أعلاه ، هي ذلك يمكن للمستخدم أن يكون من نوع واحد فقط.

التطبيق أيضا يحتاج إلى تتبع من قام بإنشاء و/أو تعديل مبادئ المدارس والمسؤولين والمنسقين والشركات والمنتجات وما إلى ذلك. (لذلك هذا رابطان آخران لنموذج المستخدم.)

في هذا السيناريو ، هل من الجيد استخدام ميراث Django متعدد الطاولة على النحو التالي: -

from django.contrib.auth.models import User
class Principal(User):
    #
    #
    #    
    branchoffice = models.ForeignKey(BranchOffice)
    landline = models.CharField(blank=True, max_length=20)    
    mobile = models.CharField(blank=True, max_length=20)
    created_by = models.ForeignKey(User, editable=False, blank=True, related_name="principalcreator")    
    modified_by = models.ForeignKey(User, editable=False, blank=True, related_name="principalmodifier")
    #
    #
    #

أو يجب أن أفعل ذلك مثل هذا: -

class Principal(models.Model):
    #
    #
    #
    user = models.OneToOneField(User, blank=True)
    branchoffice = models.ForeignKey(BranchOffice)
    landline = models.CharField(blank=True, max_length=20)    
    mobile = models.CharField(blank=True, max_length=20)
    created_by = models.ForeignKey(User, editable=False, blank=True, related_name="principalcreator")    
    modified_by = models.ForeignKey(User, editable=False, blank=True, related_name="principalmodifier")
    #
    #
    #

يرجى مراعاة أن هناك أنواع مستخدمين أخرى مرتبطة عبر المفاتيح الأجنبية ، على سبيل المثال: -

class Administrator(models.Model):
    #
    #
    #
    principal = models.ForeignKey(Principal, help_text="The supervising principal for this Administrator")
    user = models.OneToOneField(User, blank=True)
    province = models.ForeignKey(         Province)
    landline = models.CharField(blank=True, max_length=20)    
    mobile = models.CharField(blank=True, max_length=20)
    created_by = models.ForeignKey(User, editable=False, blank=True, related_name="administratorcreator")    
    modified_by = models.ForeignKey(User, editable=False, blank=True, related_name="administratormodifier")

أدرك أن Django يستخدم علاقة فردية للميراث متعدد الطاولة وراء الكواليس. أنا لست مؤهلاً بما يكفي لتقرير ما هو نهج أكثر سليمًا.

هل كانت مفيدة؟

المحلول

أود التوسع في الحل بواسطة Thornomad.

يمكن أن يؤدي توسيع فئة مستخدم Django مباشرة إلى جميع أنواع المتاعب مع آليات Django.ath. ما قمت به في موقف مماثل هو بالضبط ما يقترحه Thornomad-لقد صنعت نموذج المستخدم الخاص بي المرتبط بمفرده مع نموذج مستخدم Django ، والذي عقدت فيه بيانات مستخدم إضافية والتي ورثت منها نماذج لأنواع مختلفة من المستخدمين.

شيء لتناسب ما وصفته:

class UserProfile(models.Model):
    user = models.OneToOneField(User, blank=True, related_name='profile')
    class Meta:
        abstract = True


class PositionHolderUserProfile(UserProfile):
    first_name = models.CharField(max_length=30)
    last_name = models.CharField(max_length=30)
    landline = models.CharField(blank=True, max_length=20)    
    mobile = models.CharField(blank=True, max_length=20)
    created_by = models.ForeignKey(PositionHolderUserProfile, editable=False, blank=True, related_name="created_users")    
    modified_by = models.ForeignKey(PositionHolderUserProfile, editable=False, blank=True, related_name="modified_users")

class Principal(PositionHolderUserProfile):
    branchoffice = models.ForeignKey(BranchOffice)

class Administrator(PositionHolderUserProfile):
    superior = models.ForeignKey(Principal, related_name="subordinates")
    province = models.ForeignKey(Province)

class Coordinator(PositionHolderUserProfile):
    superior = models.ForeignKey(Administrator, related_name="subordinates")


class Company(UserProfile):
    name = models.CharField(max_length=50)

class Product(models.Model):
    name = models.CharField(max_length=50)
    produced_by = models.ForeignKey(Company)

class Buyer(UserProfile):
    first_name = models.CharField(max_length=30)
    last_name = models.CharField(max_length=30)
    products_bought = models.ManyToManyField(Product)

نصائح أخرى

لقد انتقلت مؤخرًا إلى استخدام النماذج التي تربى عن contrib.auto.models.user. ملاحظتي العامة هي أنها من الناحية النظرية أنها رائعة ، لكن في بعض الأحيان لا يتم التعامل معها تلقائيًا كما يفترض أن يكونوا.

أعتقد أن قرارك بشأن الميراث مقابل OneToone يأتي إلى هذا:

  • هل أرغب في الحصول على Django تلقائيًا شيئًا صحيحًا بنسبة 95 ٪ من الوقت ، وأحتاج إلى تصحيح أن 5 ٪ أخرى

-أو-

  • هل أريد أن أفعل شيئًا يدويًا بنفسي بنسبة 100 ٪ من الوقت

إذا لم تكن قد رأيت ذلك ، فإن مدونة Scott Barham لديها منشور رائع حول ميراث المستخدم ، وكذلك إنشاء نهاية خلفية مخصصة للتأكد من إرجاع كائنك المخصص - تمديد مستخدم Django.

بالإضافة إلى ذلك سيكون حقل AutoonetOone الذي يوفره Django-annoying. إنه نوع من الهجين من النهجين هنا - لا يوجد ميراث يحدث ، لكن Django يعتني بإنشاء ملعب OneToonefield المطابق إذا لم يكن موجودًا.

ايضا، ثورنوماد هل تشير إلى نقطة جيدة حول التكرار في النماذج الخاصة بك. يمكنك بسهولة تنفيذ فئة مجردة لتنظيف ذلك على النحو (على افتراض أنك تقوم بتنفيذ OneToOne اليدوي):

class BaseExtendedUser(models.Model):
    user = models.OneToOneField(User, blank=True, related_name='profile')
    landline = models.CharField(blank=True, max_length=20)    
    mobile = models.CharField(blank=True, max_length=20)
    created_by = models.ForeignKey(User, editable=False, blank=True, related_name="created_users")    
    modified_by = models.ForeignKey(User, editable=False, blank=True, related_name="modified_users")

    class Meta:
        abstract = True

class Administrator(BaseExtendedUser):
    province = models.ForeignKey(Province)

class Principal(BaseExtendedUser):
    branchoffice = models.ForeignKey(BranchOffice)

لا أعتقد أنني سأرث User النموذج ، بل استخدم العرف UserProfile - يغادر ال contrib.auth نموذج وحده. مع العرف UserProfile النموذج ، يمكنك إعداد أ يتمركز نموذج ملف تعريف المستخدم الذي يمكن أن يكون جزءًا من جميع أنواع المستخدمين المختلفة.

فقط أنظر إليه بسرعة ، أيضًا ، سأبحث بعناية في أي نماذج تكرر جميع الحقول نفسها (مثل آخر اثنين Principle و Administrator عارضات ازياء). قد يؤدي الجمع بين وظائف المجموعة المضمنة مع فكرة ملف تعريف المستخدم إلى القيام بما تبحث عنه.

يرجى النظر في ما يحدث في نموذج البيانات عندما يتم ترقية المنسق إلى مدير. لن أستخدم الميراث في هذه الحالة على الإطلاق. يرجى إعادة النظر في اقتراح الملصق السابق "الجمع بين وظائف المجموعة المضمنة مع فكرة ملف تعريف المستخدم قد يفعل ما تبحث عنه."

هل تحتاج إلى كائنات من فئات المستخدم الخاصة بك لتتصرف مثل Auth.user في أي مكان؟ سيكون هذا هو السبب الأكثر وضوحًا لاستخدام الميراث على OneToOne. سيكون أحد المحترفين من نهج OnetOone هو السهولة التي يمكنك من خلالها التغيير إلى نموذج مستخدم آخر ، إذا كان هذا مصدر قلق.

المشكلة الحقيقية التي أراها مع ما لديك أعلاه (بواسطة أي من الطريقة) هو أنه لا يبدو أن هناك أي شيء يمنعك من وجود كائن رئيسي وكائن المسؤول يشارك نفس المستخدم. لا يمكن لـ OneToOnefield ضمان رسم خرائط فردي بين أي علاقتين.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top