جانغو أورم:التخزين المؤقت ومعالجة كائنات ExternalKey

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

سؤال

ضع في اعتبارك الهيكل العظمي التالي لـmodels.py للعبة غزو الفضاء:

class Fleet(models.Model):
    game = models.ForeignKey(Game, related_name='planet_set')
    owner = models.ForeignKey(User, related_name='planet_set', null=True, blank=True)
    home = models.ForeignKey(Planet, related_name='departing_fleet_set')
    dest = models.ForeignKey(Planet, related_name='arriving_fleet_set')
    ships = models.IntegerField()

class Planet(models.Model):
    game = models.ForeignKey(Game, related_name='planet_set')
    owner = models.ForeignKey(User, related_name='planet_set', null=True, blank=True)
    name = models.CharField(max_length=250)
    ships = models.IntegerField()

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

  1. الاستعلام عن جميع الأساطيل والكواكب والكائنات الأخرى من قاعدة البيانات وتخزينها مؤقتًا ككائنات بايثون
  2. معالجة كائنات اللعبة، وحل حالة اللعبة
  3. احفظهم مرة أخرى في قاعدة البيانات

يبدو أن هذا النموذج ينهار تمامًا عند استخدام كائنات ExternalKey.على سبيل المثال، عندما يغادر أسطول جديد أحد الكواكب، لدي سطر يبدو كالتالي:

fleet.home.ships -= fleet.ships

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

هل هناك طريقة أفضل للتعامل مع هذا الوضع؟أم أن هذا هو حال جميع ORMs؟

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

المحلول

لا يقوم ORM الخاص بـ Django بتنفيذ ملف خريطة الهوية (إنه في تعقب التذاكر, ولكن ليس من الواضح ما إذا كان سيتم تنفيذه أو متى؛يوجد ملتزم أساسي واحد على الأقل في Django وأعرب عن معارضته لذلك).هذا يعني أنك إذا وصلت إلى نفس كائن قاعدة البيانات من خلال مسارين مختلفين للاستعلام، فأنت تعمل مع كائنات Python مختلفة في الذاكرة.

هذا يعني أن تصميمك (تحميل كل شيء في الذاكرة مرة واحدة، وتعديل الكثير من الأشياء، ثم حفظه بالكامل مرة أخرى في النهاية) غير عملي باستخدام Django ORM.أولاً لأنه غالبًا ما يؤدي إلى إهدار الكثير من الذاكرة عند تحميل نسخ مكررة من نفس الكائن، وثانيًا بسبب مشكلات "الكتابة فوق" مثل تلك التي تواجهها.

إما أنك تحتاج إلى إعادة صياغة التصميم الخاص بك لتجنب هذه المشكلات (إما أن تكون حريصًا على العمل مع QuerySet واحدة فقط في كل مرة، مع حفظ أي شيء تم تعديله قبل إجراء استعلام آخر؛أو إذا قمت بتحميل عدة استعلامات، أو ابحث عن جميع العلاقات يدويًا، فلا تجتاز المفاتيح الخارجية مطلقًا باستخدام السمات المناسبة لها)، أو استخدم Python ORM بديل ينفذ خريطة الهوية. SQLAlchemy هو خيار واحد.

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

نصائح أخرى

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