Django-rest-framework: استدعاءات PUT لا "تحل محل حالة المورد المستهدف" بشكل كامل

تم إنشاؤها على ٣٠ يونيو ٢٠١٦  ·  68تعليقات  ·  مصدر: encode/django-rest-framework

تحرير: لمعرفة الحالة الحالية للمشكلة ، انتقل إلى https://github.com/encode/django-rest-framework/issues/4231#issuecomment -332935943

===

أواجه مشكلة في تنفيذ مكتبة Optimistic Concurrency على تطبيق يستخدم DRF للتفاعل مع قاعدة البيانات. أحاول:

  • تأكد من أن السلوك الذي أراه يُنسب إلى DRF
  • تأكد من أن هذا هو السلوك المقصود
  • حدد ما إذا كان هناك أي طريقة عملية للتغلب على هذا السلوك

لقد أضفت مؤخرًا تزامنًا متفائلًا إلى تطبيق Django الخاص بي. لحفظ البحث عن Wiki:

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

كان لدي واجهة مستخدم قديمة تتحدث من خلال DRF. لم تتعامل واجهة المستخدم القديمة مع أرقام الإصدارات. كنت أتوقع أن يتسبب هذا في حدوث أخطاء في التزامن ، لكنه لم يحدث. إذا فهمت المناقشة في # 3648 بشكل صحيح:

  • يقوم DRF بدمج PUT مع السجل الحالي. يؤدي هذا إلى ملء معرف إصدار مفقود بمعرف قاعدة البيانات الحالي
  • نظرًا لأن هذا يوفر دائمًا تطابقًا ، فإن حذف هذا المتغير سيؤدي دائمًا إلى كسر نظام التزامن المتفائل الذي يتواصل عبر DRF
  • ~ لا توجد خيارات سهلة (مثل جعل الحقل "مطلوبًا") لضمان إرسال البيانات في كل مرة. ~ (تحرير: يمكنك حل المشكلة بجعلها مطلوبة كما هو موضح في هذا التعليق )

خطوات التكاثر

  1. قم بإعداد حقل التزامن متفائل على نموذج
  2. قم بإنشاء مثيل جديد وقم بالتحديث عدة مرات (للتأكد من أنه لم يعد لديك رقم إصدار افتراضي)
  3. قم بإرسال تحديث (PUT) من خلال DRF باستثناء معرف الإصدار

    سلوك متوقع

يجب ألا يتطابق معرّف الإصدار المفقود مع قاعدة البيانات ويسبب مشكلة التزامن.

السلوك الفعلي

يتم تعبئة معرف الإصدار المفقود بواسطة DRF بالمعرف الحالي حتى يمر التحقق من التزامن.

Enhancement

ال 68 كومينتر

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

موافق. أنا متأكد تمامًا من أن مشكلتي هي مزيج من عاملين:

  1. لا يتطلب DRF الحقل في PUT (على الرغم من أنه مطلوب في النموذج) لأنه يحتوي على حقل افتراضي (الإصدار = 0)
  2. يدمج DRF حقول PUT مع الكائن الحالي (بدون حقن الافتراضي)

نتيجة لذلك ، يستخدم DRF القيمة الحالية (قاعدة البيانات) ويكسر التحكم في التزامن. يرتبط النصف الثاني من المشكلة بالمناقشة في # 3648 (مذكورة أعلاه أيضًا) وهناك مناقشة (ما قبل 3.x) في # 1445 والتي لا تزال تبدو ذات صلة.

آمل أن تكون الحالة الملموسة (والشائعة بشكل متزايد) حيث يكون السلوك الافتراضي منحرفًا كافية لإعادة فتح المناقشة حول السلوك "المثالي" لبرنامج ModelSerializer. من الواضح ، أنا فقط بعمق بوصة واحدة على DRF ، لكن حدسي هو أن السلوك التالي مناسب لحقل مطلوب و PUT:

  • عند استخدام مُسلسل غير جزئي ، يجب إما أن نتلقى القيمة ، أو نستخدم الافتراضي ، أو (إذا لم يكن هناك افتراضي متاح) نرفع خطأ التحقق من الصحة. يجب تطبيق التحقق على مستوى النموذج على المدخلات / الافتراضيات فقط.
  • عند استخدام مُسلسل جزئي ، يجب أن نحصل على القيمة أو الرجوع عن القيم الحالية. يجب أن يتم تطبيق التحقق على مستوى النموذج على تلك البيانات المجمعة.
  • أعتقد أن برنامج التسلسل "غير الجزئي" الحالي شبه جزئي:

    • إنه غير جزئي للحقول المطلوبة وليس لها افتراضي

    • إنها جزئية للحقول المطلوبة ولديها افتراضي (حيث لم يتم استخدام الافتراضي)

    • إنها جزئية للحقول غير المطلوبة

لا يمكننا تغيير الرمز النقطي (1) أعلاه أو تصبح الإعدادات الافتراضية عديمة الفائدة (نحتاج إلى الإدخال على الرغم من أننا نعرف الافتراضي). هذا يعني أنه يتعين علينا إصلاح المشكلة عن طريق تغيير رقم 2 أعلاه. أتفق مع حجتك في # 2683 بأن:

النماذج الافتراضية هي نماذج افتراضية. يجب أن يحذف المسلسل القيمة وأن يرجئ المسؤولية إلى Model.object.create() للتعامل مع هذا الأمر.

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

تساعد محاولة وصف مسار الترحيل في إبراز مدى غرابة السلوك الحالي. الهدف النهائي هو

  1. إصلاح ModelSerializer ،
  2. أضف علامة لهذه الحالة شبه الجزئية ، و
  3. اجعل هذا العلم هو الافتراضي (للتوافق مع الإصدارات السابقة)

ما اسم هذا العلم؟ إن برنامج Model Serializer الحالي هو في الواقع مُسلسل جزئي (بشكل تعسفي إلى حد ما) يتطلب الحقول التي تفي بالشرط required==True and default==None . لا يمكننا استخدام علامة partial بشكل صريح دون كسر التوافق مع الإصدارات السابقة ، لذلك نحتاج إلى علامة جديدة (نأمل أن تكون مؤقتة). بقي لديّ quasi_partial ، لكن عدم قدرتي على التعبير عن المطلب التعسفي required==True and default==None هو السبب في أنه من الواضح جدًا بالنسبة لي أنه يجب إهمال هذا السلوك بشكل عاجل.

يمكنك إضافة extra_kwargs في Meta للمسلسل ، مما يجعل version حقلاً مطلوبًا.

class ConcurrentModelSerializer(serializers.ModelSerializer):
    class Meta:
        model = ConcurrentModel
        extra_kwargs = {'version': {'required': True}}

شكراanoopmalev. هذا سيبقيني في فرع الإنتاج.

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

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

هذا اقتراح موجز ... لمسلسل غير جزئي:

  1. لأي حقل غير مدرج في المسلسل (ضمنيًا أو صريحًا) أو تم تمييزه للقراءة فقط ، احتفظ بالقيمة الحالية
  2. لجميع الحقول الأخرى ، استخدم الخيار الأول المتاح:

    1. ملء مع القيمة المقدمة

    2. الملء افتراضيًا ، بما في ذلك القيمة التي يتضمنها blank و / أو null

    3. رفع استثناء

للتوضيح ، يتم إجراء التحقق من الصحة على المنتج النهائي لهذه العملية.

أي أنك تريد تعيين required=True على أي حقل مُسلسل لا يحتوي على نموذج افتراضي ، للتحديثات؟

هل فهمت ذلك بشكل صحيح؟

نعم (وأكثر). هكذا فهمت الفرق بين partial (جميع الحقول اختيارية) مقابل non-partial (جميع الحقول مطلوبة). المرة الوحيدة التي لا يتطلب فيها المسلسل non-partial حقلاً هو وجود افتراضي (محدد بشكل ضيق أو واسع) _ حيث يمكن للمسلسل استخدام هذا الإعداد الافتراضي إذا لم يتم توفير قيمة ._

القسم المائل هو ما لا يقوم به DRF حاليًا والتغيير الأكثر أهمية في اقتراحي. التنفيذ الحالي يتخطى المجال.

كان لديّ اقتراح ثانٍ مختلط ، لكنه حقًا سؤال منفصل حول مدى كرمك في أن تكون مع فكرة "التخلف عن السداد". السلوك الحالي "صارم" حيث يتم التعامل مع default على هذا النحو. إذا كنت تريد _ حقًا_ تقليل مقدار البيانات المطلوبة ، فيمكنك جعل الحقول blank=True اختيارية أيضًا ... بافتراض أن القيمة الغائبة هي قيمة فارغة.

claytondaley أنا أستخدم OOL مع DRF منذ 2x بهذه الطريقة:

class VersionModelSerializer(serializers.ModelSerializer, BaseSerializer):
    _initial_version = 0

    _version = VersionField()

    def __init__(self, *args, **kwargs):
        super(VersionModelSerializer, self).__init__(*args, **kwargs)

        # version field should not be required if there is no object
        if self.instance is None and '_version' in self.fields and\
                getattr(self, 'parent', None) is None:
            self.fields['_version'].read_only = True
            self.fields['_version'].required = False

        # version field is required while updating instance
        if self.instance is not None and '_version' in self.fields:
            self.fields['_version'].required = True

        if self.instance is not None and hasattr(self.instance, '_version'):
            self._initial_version = self.instance._version

    def validate__version(self, value):
        if self.instance is not None:
            if not value and not isinstance(value, int):
                raise serializers.ValidationError(_(u"This field is required"))

        return value
   # more code & helpers

إنه يعمل بشكل رائع مع كل أنواع منطق الأعمال ولا يسبب أي مشكلة.

هل ترك هذا مغلقا عن طريق الصدفة؟ أجبت على السؤال المحدد ولم أسمع سببًا ما هو الخطأ في الاقتراح.

claytondaley لماذا يجب أن تكون OOL جزءًا من DRF؟ تحقق من الكود الخاص بي - إنه يعمل فقط في تطبيق كبير (1400 اختبار). VersionField هو مجرد IntegerField .

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

أنا أستخدم django-concurrency الذي يضع منطق OOL في إجراء الحفظ (حيث ينتمي). أساسًا UPDATE... WHERE version = submitted_version . هذا ذري لذا ليس هناك حالة عرق. ومع ذلك ، فإنه يكشف عن خطأ في منطق التسلسل:

  • إذا تم تعيين الإعداد الافتراضي في حقل في النموذج ، فإن DRF يعين required=False . الفكرة (الصالحة) هي أن DRF يمكنه استخدام هذا الإعداد الافتراضي إذا لم يتم تقديم أي قيمة.
  • إذا كان هذا الحقل مفقودًا ، فإن DRF لا يستخدم الافتراضي. وبدلاً من ذلك ، يقوم بدمج البيانات المقدمة مع الإصدار الحالي من الكائن.

عندما لا نطلب الحقل ، فإننا نفعل ذلك لأن لدينا خيارًا افتراضيًا لاستخدامه. لا يفي DRF بهذا العقد لأنه لا يستخدم القيمة الافتراضية ... يستخدم القيمة الحالية.

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

تضمين التغريدة

لقد قمت بترميز OOL في المسلسل.

هل فعلت؟ هل وجدت أي منطق OOL في جهاز التسلسل الخاص بي بجانب متطلبات الحقل؟

هذا هو المكان الخطأ للقيام بذلك لأن لديك حالة سباق.

آسف ، أنا فقط لا أستطيع أن أرى أين حالة السباق هنا.

أنا أستخدم التزامن django الذي يضع منطق OOL في إجراء الحفظ (حيث ينتمي).

أنا أستخدم أيضًا django-concurrency :) ولكن هذا هو مستوى الطراز وليس المسلسل. على مستوى جهاز التسلسل ، تحتاج فقط إلى:

  • تأكد من أن حقل الإصدار مطلوب دائمًا (عندما يجب أن يكون)
  • تأكد من أن جهاز التسلسل يعرف كيفية التعامل مع أخطاء OOL (هذا الجزء الذي قمت بإنشائه)
  • تأكد من أن apiview الخاص بك يعرف كيفية التعامل مع أخطاء OOL ويرفع HTTP 409 مع سياق فرق محتمل

في الواقع ، أنا لا أستخدم django-concurrency بسبب مشكلة تم وضع علامة عليها تلقائيًا على أنها "لن تصلح": إنها تتجاوز OOL عندما يتم استخدام obj.save(update_fields=['one', 'two', 'tree']) والتي وجدت ممارسة سيئة ، لذلك قمت بتقسيم الحزمة.

ها هي طريقة save المفقودة للمسلسل التي ذكرتها سابقًا. يجب أن يحل كل مشاكلك:

    def save(self, **kwargs):
        try:
            self.instance = super(VersionModelSerializer, self).save(**kwargs)
            return self.instance
        except VersionException:
            # Use select_for_update so we have some level of guarantee
            # that object won't be modified at least here at the same time
            # (but it may be modified somewhere else, where select_for_update
            # is not used!)
            with transaction.atomic():
                db_instance = self.instance.__class__.objects.\
                    select_for_update().get(pk=self.instance.pk)
                diff = self._get_serializer_diff(db_instance)

                # re-raise exception, so api client will receive friendly
                # printed diff with writable fields of current serializer
                if diff:
                    raise VersionException(diff)

                # otherwise re-try saving using db_instance
                self.instance = db_instance
                if self.is_valid():
                    return super(VersionModelSerializer, self).save(**kwargs)
                else:
                    # there are errors that could not be displayed to a user
                    # so api client should refresh & retry by itself
                    raise VersionException

        # instance.save() was interrupted by application error
        except ApplicationException as logic_exc:
            if self._initial_version != self.instance._version:
                raise VersionException

            raise logic_exc

آسف. لم أقرأ الكود الخاص بك لمعرفة ما كنت تفعله. رأيت مسلسلا. من الواضح أنه يمكنك التغلب على المشكلة عن طريق اختراق برنامج التسلسل ولكن لا يجب عليك ... لأن الخلل في منطق DRF يقف من تلقاء نفسه. أنا فقط أستخدم OOL لتوضيح هذه النقطة.

ويجب أن تجرب هذا الرمز مقابل أحدث إصدار من django-concurrency (باستخدام IGNORE_DEFAULT=False ). كان django-concurrency يتجاهل أيضًا القيم الافتراضية ، لكني أرسلت تصحيحًا. كانت هناك حالة زاوية غريبة اضطررت إلى البحث عنها لجعلها تعمل مع الحالات العادية.

أعتقد أن هذا يسمى توسيع الوظائف الافتراضية ، وليس القرصنة حقًا. أعتقد أن أفضل مكان لدعم هذه الميزات هو الحزمة django-concurrency .

لقد أعدت قراءة مناقشة القضية بأكملها ووجدت أن اقتراحك واسع جدًا وسوف يفشل في العديد من الأماكن (بسبب الاستخدام السحري للقيم الافتراضية من مصادر مختلفة في ظل ظروف مختلفة). أصبح DRF 3.x أسهل بكثير ويمكن التنبؤ به من 2.x ، فلنحافظ عليه بهذه الطريقة :)

لا يمكنك إصلاح هذا في طبقة النموذج لأنه مكسور في المسلسل (قبل أن يصل إلى النموذج). ضع OOL جانبًا ... لماذا لا نطلب حقلاً إذا تم تعيين default ؟

المتسلسل غير الجزئي "يتطلب" جميع الحقول (بشكل أساسي) ومع ذلك فقد تركنا هذا واحدًا. هل هذه حقيب؟ أو هل لدينا سبب منطقي؟

كما ترون في مثال الكود الخاص بي - مطلوب دائمًا حقل الإصدار _ بشكل صحيح في جميع الحالات الممكنة.

راجع للشغل ، اتضح أنني اقترضت كود نموذج lvl من https://github.com/gavinwahl/django-optimistic-lock وليس من django-concurrency وهو طريق إلى التعقيد بدون سبب تقريبًا.

... لذا فإن الخطأ هو "المتسلسلات غير الجزئية عيَّنت بشكل غير صحيح بعض الحقول على غير مطلوب". هذا هو البديل. لأن هذا هو الالتزام (الضمني) الذي يقوم به المسلسل غير الجزئي.

يمكنني اقتباسه :

بشكل افتراضي ، يجب أن يتم تمرير القيم المتسلسلة لجميع الحقول المطلوبة وإلا ستعرض أخطاء التحقق من الصحة.

لا يشير هذا إلى أي شيء مطلوب (إلا في حالة توفير القيمة الافتراضية).

(وأنا أتحدث عن مستويين مختلفين ، لكن ModelSerializer لا ينبغي أن يطلب الحقول إذا لم يكن سيتحمل المسؤولية عن هذا القرار)

أعتقد أنني فقدت وجهة نظرك ..

(وأنا أتحدث عن مستويين مختلفين ، لكن ModelSerializer لا ينبغي أن يطلب الحقول إذا لم يكن سيتحمل المسؤولية عن هذا القرار)

ما الخطأ فى ذلك؟

حسنًا ، دعني أجرب زاوية مختلفة.

  • افترض أن لديّ مُسلسل نموذج غير جزئي (تحرير: جميع الإعدادات الافتراضية) يغطي جميع الحقول في النموذج الخاص بي.

هل يجب أن ينتج عن إنشاء أو تحديث بنفس البيانات كائنًا مختلفًا (باستثناء المعرف)

هل يمكنك وصف أفكارك باستخدام بعض النماذج والمسلسلات البسيطة حقًا وبعض الأسطر التي تُظهر السلوك الفاشل / المتوقع؟

سأجمع شيئًا ما غدًا لأن الوقت متأخر هنا ... ولكن كلما تعمقت أكثر ، كلما كان # 3648 أكثر منطقية يجعله متسلسلًا غير جزئي. في غضون ذلك ، لماذا لا يتطلب ModelSerializer جميع الحقول في النموذج؟ ربما يختلف منطقك عن منطقتي.

ModelSerializer يتفقد النموذج المحدد ويقرر ما إذا كان يجب أن يكون مطلوبًا أليس كذلك؟

لا أقصد كيف ميكانيكيا. الافتراض الأساسي للمسلسل غير الجزئي هو طلب كل شيء (مقتبس أعلاه). إذا كان get_field_kwargs سينحرف عن هذا الافتراض (على وجه التحديد ، هنا ) ، فيجب أن يكون له سبب وجيه. ما هذا السبب؟

إجابتي المفضلة هي الإجابة التي أستمر في تقديمها ، "لأنه يمكن استخدام هذا الإعداد الافتراضي إذا لم يتم تقديم أي قيمة" (ولكن بعد ذلك يجب على DRF أن يستخدم القيمة الافتراضية بالفعل). هل هناك إجابة أخرى مفقودة؟ ما سبب عدم طلب الحقول ذات الإعدادات الافتراضية؟

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

في الأساس ، يجعل المسلسل غير الجزئي غير جزئي حقًا.

الآن أنا على الأقل أعرف ما تعنيه. هل راجعت ما هو سلوك ModelForm في مثل هذه الحالة؟ (لا يمكنني القيام بذلك بنفسي على الهاتف المحمول)

تقول مستندات Django أن "فارغ" يتحكم في ما إذا كان الحقل مطلوبًا أم لا. أقترح عليك فتح تذكرة منفصلة لهذه المشكلة لأن هذه البطاقة تحتوي على الكثير من التعليقات غير ذات الصلة. في رأيي ، قد يعمل modelerizer مثل modelform: عناصر تحكم الخيار الفارغة مطلوبة ، 'null' تخبر ما إذا كان لا شيء هو إدخال مقبول و 'الافتراضي' ليس له أي تأثير على هذا المنطق.

أنا على استعداد لفتح تذكرة ثانية ، لكنني قلق من أن الفراغ يتطلب رمزًا مشابهًا. من مجموعة مناقشة django :

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

لكي نكون متسقين ، سيكون لدينا التزام بالوفاء بالنصف الثاني من العقد ، وتحديد القيمة الغائبة إلى فارغة. هذا أقل إشكالية إلى حد ما لأنه يمكن ملء الفراغ دون الرجوع إلى نموذج ، ولكنه مشابه جدًا (وأعتقد أنه متوافق مع # 3648).

tomchristie هل يمكنك إعطاء بعض المدخلات القصيرة حول هذا: لماذا تعتمد الحالة required على حقل النموذج defaults property؟

لماذا تعتمد الحالة المطلوبة على خاصية افتراضيات حقل النموذج؟

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

في الواقع أنا أتفق مع هذا السلوك. ModelForm على الرغم من أن الكود يفعل الشيء نفسه (سيوفر html الإعدادات الافتراضية). إذا كان DRF سيكون منطقًا مختلفًا ، فلن يتم تطبيق "افتراضي" أبدًا. انتهيت من هذه القضية.

pySilver في الواقع ، هذا هو سلوك ModelForm:

# models.py

from django.db import models

class MyModel(models.Model):
    no_default = models.CharField(max_length=100)
    has_default = models.CharField(max_length=100, default="iAmTheDefault")

من أجل الوضوح ، لا تزال الأشياء تسمى "جزئية" لأن _update_ جزئية. كنت أقوم أيضًا باختبار تحديث كامل ("كامل") ، ولكن لم يكن الرمز ضروريًا لإظهار السلوك:

# in manage.py shell
>>> from django import forms
>>> from django.conf import settings
>>> from form_serializer.models import MyModel
>>>
>>> class MyModelForm(forms.ModelForm):
...     class Meta:
...         model = MyModel
...         fields = ['no_default', 'has_default']
...
>>>
>>> partial = MyModel.objects.create()
>>> partial.id = 2
>>> partial.no_default = "Must replace me"
>>> partial.has_default = "I should be replaced"
>>> partial.save()
>>>
>>>
>>> POST_PARTIAL = {
...     "id": 2,
...     "no_default": "must change me",
... }
>>>
>>>
>>> form_partial = MyModelForm(POST_PARTIAL)
>>> form_partial.is_valid()
False
>>> form_partial._errors
{'has_default': [u'This field is required.']}

يتطلب ModelForm هذا الإدخال حتى يعتقد أنه يحتوي على افتراضي. هذا هو أحد السلوكين المتسقين داخليًا.

لماذا تعتمد الحالة المطلوبة على خاصية افتراضيات حقل النموذج؟

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

tomchristie توافق من حيث المبدأ. لكن ما هو السلوك المتوقع؟

  • عند الإنشاء ، أحصل على القيمة الافتراضية (تافهة ، يتفق الجميع على أن هذا صحيح)
  • عند التحديث ، ما الذي يجب أن أحصل عليه؟

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

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

(إذا كان أي شيء أعتقد أنه من الأفضل في الواقع أن تكون جميع التحديثات عبارة عن دلالات جزئية لجميع الحقول - ستظل PUT معطلة ، وهذا هو الجانب المهم ، من المحتمل أن يكون تغيير السلوك الحالي محرجًا)

أنا بالتأكيد لا أشاركك التفضيلات ؛ أريد أن تكون جميع واجهاتي صارمة ما لم أجعلها غير ذلك عمداً. ومع ذلك ، فإن التمييز الجزئي مقابل غير الجزئي يوفر بالفعل (من الناحية النظرية) ما نريده كلانا.

أعتقد أن التصرف الجزئي يتصرف كما تريد تمامًا:

  • التحديثات جزئية بنسبة 100٪
  • الإنشاءات (أفترض) جزئية بالنسبة إلى default و blank (استثناءات منطقية). في جميع الحالات الأخرى ، ترتبط قيود النموذج / قاعدة البيانات.

أنا فقط أحاول الحصول على تناسق في المسلسل غير الجزئي. إذا قمت بإزالة الحالة الخاصة لـ default ، فإن المسلسلات الحالية غير الجزئية تصبح المسلسل الصارم الذي أريده. يصلون أيضًا إلى التكافؤ مع ModelForm.

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

الأهم من ذلك ، إذا كنت تريد أن تكون المسلسلات الخاصة بك هي الأمر الواقع الجديد لـ Django ، فسوف ينتهي بك الأمر بإجراء هذا التغيير على أي حال. سيتجاوز عدد الأشخاص الذين يقومون بالتحويل من ModelForm إلى حد كبير قاعدة المستخدمين الحالية وسيتوقعون هذا التغيير على الأقل.

إدخال سنتي:
أنا أميل إلى الاتفاق مع claytondaley. PUT هو استبدال موارد غير فعالة ، PATCH هو تحديث للمورد الحالي. خذ المثال التالي:

class Profiles(models.Model):
    username = models.CharField()
    role = models.CharField(default='member', choices=(
        ('member', 'Member'), 
        ('moderator', 'Moderator'),
        ('admin', 'Admin'), 
    ))

ملفات التعريف الجديدة منطقية لها دور العضو الافتراضي. لنأخذ الطلبات التالية:

POST /profiles username=moe
PUT /profiles/1 username=curly
PATCH /profiles/1 username=larry&role=admin
PUT /profiles/1 username=curly

كما هو الحال حاليًا ، بعد PUT الأول ، ستحتوي بيانات الملف الشخصي على {'username': 'curly', 'role': 'member'} . بعد PUT الثاني ، سيكون لديك {'username': 'curly', 'role': 'admin'} . ألا يكسر هذا العاطفة؟ (لست متأكدًا تمامًا - أنا أسأل بشكل شرعي)

تعديل:
أعتقد أن الجميع على نفس الصفحة حول دلالات PATCH.

بعد PUT الثاني ، سيكون لديك {'username': 'curly'، 'role': 'admin'}

أنا شخصياً سأتفاجأ إذا عاد الدور إلى الوضع الافتراضي (إذا رأيت سبب مناقشة الكائن replace ، لم أواجه أي مشاكل حقيقية معه حتى الآن)

لم أواجه أي مشاكل حقيقية معه حتى الآن

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

اسمحوا لي أن أبدأ بالإقرار بأن المسلسل لا يحتاج بالضرورة إلى اتباع RESTful RFC. ومع ذلك ، يجب عليهم على الأقل تقديم أوضاع متوافقة - خاصة في الحزمة التي تقدم دعم REST.

كانت حجتي الأصلية من المبادئ الأولى ، لكن RFC (القسم 4.3.4) تقول تحديدًا (التشديد مضاف):

يتم تمييز الاختلاف الأساسي بين طريقتي POST و PUT من خلال النية المختلفة للتمثيل المرفق. الغرض من المورد الهدف في طلب POST هو معالجة التمثيل المغلق وفقًا لدلالات المورد الخاصة ، بينما يتم تعريف التمثيل المُضمن في طلب PUT على أنه استبدال حالة المورد الهدف.
...
يجب أن يرسل خادم الأصل الذي يسمح PUT على مورد هدف معين استجابة 400 (طلب غير صالح) لطلب PUT الذي يحتوي على حقل رأس نطاق المحتوى (القسم 4.2 من [RFC7233]) ، حيث من المحتمل أن تكون الحمولة عبارة عن محتوى جزئي الذي تم عن طريق الخطأ PUT كتمثيل كامل . تحديثات المحتوى الجزئية ممكنة عن طريق استهداف مورد محدد بشكل منفصل مع حالة تتداخل مع جزء من المورد الأكبر ، أو باستخدام طريقة مختلفة تم تحديدها بشكل خاص للتحديثات الجزئية (على سبيل المثال ، طريقة التصحيح المحددة في [RFC5789])

لذلك يجب ألا تكون PUT جزئية أبدًا (انظر أيضًا هنا ). ومع ذلك ، يوضح القسم الخاص بـ PUT أيضًا:

تطلب طريقة PUT إنشاء حالة المورد الهدف أو استبدالها بالحالة المحددة بواسطة التمثيل المضمن في حمولة رسالة الطلب. قد يشير PUT الناجح لتمثيل معين إلى أن GET التالي على نفس المورد المستهدف سيؤدي إلى إرسال تمثيل مكافئ في استجابة 200 (موافق).

النقطة المتعلقة بـ GET (رغم أنها ليست إلزامية) تدافع عن الحل "الوسط" الخاص بي. بينما يعد حقن الفراغات / الإعدادات الافتراضية أمرًا ملائمًا ، إلا أنه لن يوفر هذا السلوك. ربما يكون المسمار الموجود في التابوت هو أن هذا الحل يقلل من الالتباس لأنه لن يكون هناك أي حقول مفقودة لإثارة الشك.

من الواضح أن PATCH هو خيار محدد للتحديثات الجزئية ، لكنه يوصف بأنه "مجموعة من الإرشادات" بدلاً من مجرد PUT جزئيًا ، لذا فهو دائمًا ما يجعلني أشعر بالضيق قليلاً. ينص القسم الخاص بـ POST (4.3.3) في الواقع على ما يلي:

تطلب طريقة POST أن يقوم المورد الهدف بمعالجة التمثيل المضمن في الطلب وفقًا لدلالات المورد الخاصة. على سبيل المثال ، يتم استخدام POST للوظائف التالية (من بين أمور أخرى):

  • توفير كتلة من البيانات ، مثل الحقول التي تم إدخالها في نموذج HTML ، لعملية معالجة البيانات ؛

...

  • إلحاق البيانات بالتمثيل (التمثيلات) الحالي للمورد.

أعتقد أن هناك حجة لاستخدام POST لتحديثات جزئية منذ:

  • من الناحية المفاهيمية ، لا يختلف تعديل البيانات عن الإلحاق
  • يُسمح لـ POST باستخدام قواعدها الخاصة بحيث يمكن أن تكون هذه القواعد تحديثًا جزئيًا
  • يمكن تمييز هذه العملية بسهولة عن "إنشاء" من خلال وجود المعرّف

حتى إذا لم يطمح DRF إلى الامتثال الكامل ، فنحن بحاجة إلى مُسلسل متوافق مع عملية PUT للمواصفات (أي استبدال الكائن بأكمله). أبسط إجابة (والأقل إرباكًا بشكل واضح) هي طلب جميع الحقول. يقترح أيضًا أن يكون PUT غير جزئي افتراضيًا وأن التحديثات الجزئية يجب أن تستخدم كلمة رئيسية مختلفة (PATCH أو حتى POST).

أعتقد أنني واجهت للتو مشكلة PUT الأولى أثناء ترحيل تطبيقنا إلى drf3.4.x :)

<strong i="6">@cached_property</strong>
    def _writable_fields(self):
        return [
            field for field in self.fields.values()
            if (not field.read_only) or (field.default is not empty)
        ]

هذا يجعل .validated_data الخاصة بي تحتوي على بيانات لم أقم بتقديمها في طلب PUT ولم أقم بتوفيرها يدويًا داخل المُسلسل. تم استرداد القيم من default= على مستوى المُسلسل. لذلك في الأساس ، بينما كنت أنوي تحديث حقل معين ، قمت أيضًا بالكتابة فوق بعض تلك الحقول بقيم افتراضية باللون الأزرق.

سعيد بالنسبة لي ، أنا أستخدم ModelSerializer المخصص ، حتى أتمكن من حل المشكلة بسهولة.

pySilver أنا لا أفهم محتوى آخر تعليق.

rpkilby "لنأخذ الطلبات التالية ... ألا يكسر هذا العاطفة"

كلا ، فكل طلب PUT غير فعال لأنه يمكن تكراره عدة مرات مما يؤدي إلى نفس الحالة. هذا لا يعني أنه إذا تم تعديل جزء آخر من الحالة في هذه الأثناء ، فستتم إعادة تعيينه بطريقة ما.

إليك بعض الخيارات المختلفة لسلوك PUT .

  • الحقول مطلوبة ما لم يكن required=False أو لديهم default . (موجود)
  • جميع الحقول مطلوبة. (دلالات أكثر صرامة وتوافقًا مع التحديث الكامل _ ولكنها _ محرجة لأنها في الواقع أكثر صرامة من دلالات الإنشاء الأولية لـ POST)
  • لا توجد حقول مطلوبة (أي. مجرد عكس سلوك التصحيح)

من الواضح أنه لا توجد إجابة صحيحة "مطلقة" ، لكنني أعتقد أن لدينا السلوك الأكثر عملية كما هو الحال حاليًا.

أعتقد أن بعض حالات الاستخدام قد تجدها مشكلة إذا كان هناك حقل لا يلزم توفيره لطلبات POST ، ولكنه لا يلزم توفيره لاحقًا لطلبات PUT . علاوة على ذلك ، فإن PUT-as-create هي نفسها عملية صالحة ، لذا مرة أخرى ، سيكون من الغريب أن يكون لذلك دلالات مختلفة لـ POST.

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

tomchristie ما منة لأقول:

لدي مُسلسل يحتوي على حقل للقراءة فقط language ونموذج:

class Book(models.Model):
      title = models.CharField(max_length=100)
      language = models.ChoiceField(default='en', choices=(('pl', 'Polish'), ('en', 'English'))

class BookUpdateSerialzier(serializers.ModelSerializer):
      # language is readonly, I dont want to let users update that field using this serializer
      language = serializers.ChoiceField(default='en', choices=(('pl', 'Polish'), ('en', 'English'), read_only=True)
      class Meta:
          model = MyModel
          fields = ('title', 'language', )

book = Book(title="To be or 42", language="pl")
book.save()

s = BookUpdateSerialzier(book, data={'title': 'Foobar'}, partial=True)
s.is_valid()
assert 'language' in s.validated_data # !!! 
assert 'pl' == s.validated_data # AssertionError... here :(
  • لم أقدم طلب language ولا أتوقع رؤية ذلك في البيانات التي تم التحقق من صحتها. تمريره إلى update سيؤدي إلى استبدال المثيل الخاص بي بالافتراضيات على الرغم من حقيقة أن الكائن قد تم بالفعل تعيين بعض القيم غير الافتراضية.
  • سيكون أقل إشكالًا إذا كان validated_data['language'] سيكون book.language في هذه الحالة.

pySilver - نعم ، تم حل ذلك في https://github.com/tomchristie/django-rest-framework/pull/4346 اليوم فقط.

كما يحدث ، فأنت لست بحاجة إلى default= في حقل المسلسل في المثال الذي لديك ، حيث أن لديك قيمة افتراضية على ModelField .

tomchristie هل توافق على الأقل على أن سلوك PUT الحالي ليس من مواصفات RFC؟ وأن كلا من اقتراحي (يتطلب الكل أو إدخال الإعدادات الافتراضية) سيجعل الأمر كذلك؟

tomchristie أخبار رائعة!

عند حدوث ذلك ، لن تحتاج إلى الإعداد الافتراضي = في حقل جهاز التسلسل في المثال الذي لديك ، نظرًا لأن لديك افتراضيًا في ModelField.

نعم ، أردت فقط أن أجعلها صريحة جدًا للعرض التوضيحي.

لقد غرق أخيرًا في أن tomchristie لا تجادل لصالح / ضد سلوك المسلسل بمعزل عن غيرها. أعتقد أن اعتراضاته تنبع (ضمنيًا) من مطلب أن يدعم جهاز تسلسلي واحد جميع أوضاع REST. هذا يظهر نفسه في شكواه حول كيفية تأثير المسلسل الصارم على POST. نظرًا لأن أوضاع REST غير متوافقة ، فإن الحل الحالي هو برنامج تسلسلي غير محدد لأي وضع فردي.

إذا كان هذا هو الجذر الحقيقي للاعتراض ، فلنتناوله بشكل مباشر. كيف يمكن لمسلسل واحد توفير سلوك المواصفات لجميع أوضاع REST؟ إجابتي غير المنتظمة هي أن PARTIAL مقابل NON-PARTIAL يتم تنفيذها على المستوى الخاطئ:

  • لدينا مسلسلات جزئية وغير جزئية. يعني هذا النهج أننا بحاجة إلى العديد من المتسلسلات لدعم سلوك المواصفات لجميع الأوضاع.
  • نحتاج في الواقع إلى التحقق الجزئي مقابل التحقق غير الجزئي (أو أي شيء في هذا السياق). تحتاج أوضاع REST المختلفة إلى طلب أوضاع تحقق مختلفة من جهاز التسلسل.

لتوفير فصل المخاوف ، يجب ألا يعرف المتسلسل وضع REST لذلك لا يمكن تنفيذه كمسلسل تابع لجهة خارجية (ولا أظن أن المسلسل لديه حق الوصول إلى الوضع). بدلاً من ذلك ، يجب أن يمرر DRF جزءًا إضافيًا من المعلومات إلى المسلسل (تقريبًا replace=True مقابل PUT ). يمكن للمسلسل تحديد كيفية تنفيذ ذلك (طلب جميع الحقول أو إدخال الإعدادات الافتراضية).

من الواضح أن هذا مجرد اقتراح تقريبي ، لكنه ربما يكسر الجمود.

علاوة على ذلك ، فإن PUT-as-create هي في حد ذاتها عملية صالحة ، لذا مرة أخرى ، سيكون من الغريب أن يكون لها دلالات مختلفة لـ POST.

أوافق على أنه يمكنك الإنشاء باستخدام PUT ، لكنني لا أوافق على أن الدلالات هي نفسها. يعمل PUT على مورد معين:

تطلب طريقة PUT إنشاء حالة المورد الهدف أو استبدالها بالحالة المحددة بواسطة التمثيل المضمن في حمولة رسالة الطلب.

لذلك أعتقد أن دلالات الخلق تختلف في الواقع:

  • بريدإلى /citizen/ يتوقع إنشاء رقم الضمان الاجتماعي (SSN)
  • وضعإلى /citizen/<SSN> يقوم بتحديث بيانات SSN محدد. إذا لم تكن هناك بيانات في SSN هذا ، فسيؤدي ذلك إلى إنشاء.

نظرًا لأنه يجب تضمين "المعرف" في URI الخاص بـ PUT ، يمكنك التعامل معه على النحو المطلوب. على النقيض من ذلك ، فإن "المعرف" اختياري في POST.

نظرًا لأنه يجب تضمين "المعرف" في URI الخاص بـ PUT ، يمكنك التعامل معه على النحو المطلوب. على النقيض من ذلك ، فإن "المعرف" اختياري في POST.

بالفعل. كنت أشير على وجه التحديد إلى حقيقة أن التغيير المقترح لـ "جعل PUT تتطلب بدقة جميع الحقول" سيعني أن PUT-as-create سيكون له سلوك مختلف عن POST-as-create wrt. إذا كانت الحقول مطلوبة أم لا.

بعد أن قلت إنني أدركت القيمة في وجود خيار PUT- هو سلوك صارم.

(افرض أن _all_ الحقول مطلوبة تمامًا في هذه الحالة ، وفرض أن _لا_ الحقول مطلوبة في التصحيح ، واستخدم علامة required= لـ POST)

كيف يمكن لمسلسل واحد توفير سلوك المواصفات لجميع أوضاع REST؟

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

لقد أوضحت بالفعل أنه يمكنك create باستخدام PUT أو POST . لديهم دلالات مختلفة ومتطلبات مختلفة لذلك يجب أن يكون create محايدًا لوضع REST. أعتقد أن التمييز يحدث حقًا كجزء من is_valid . نطلب وضع التحقق المحدد:

  • لا يوجد التحقق من صحة التواجد الميداني (تصحيح)
  • التحقق على أساس required flags (POST)
  • التحقق الصارم من التواجد الميداني (PUT)

من خلال الاحتفاظ بالمنطق الخاص بالكلمات الرئيسية بعيدًا عن عمليات CRUD ، نقوم أيضًا بتقليل الاقتران بين المسلسل و DRF. إذا كانت أوضاع التحقق قابلة للتكوين ، فستكون للأغراض العامة تمامًا (حتى لو قمنا بتنفيذ 3 حالات محددة لكلماتنا الرئيسية الثلاث).

تقوم بعمل جيد في مناقشة هذه الوظيفة هناك. :)

يعد الاختلاف في "أوضاع التحقق من الصحة" عند استدعاء .is_valid () اضطرابًا لن يحدث.

يمكننا _could_ اعتبار نظير "كامل = صحيح" لوحدة kwarg الموجودة "جزئي = صحيح". سيتناسب ذلك بسهولة مع كيفية عمل الأشياء حاليًا وسيظل يدعم حالة "الحقول الصارمة".

هل المسلسل المكان المناسب لحل هذه المشكلة؟ يرتبط هذا المطلب بإحكام بالكلمات الرئيسية لـ REST ، لذا ربما يكون هذا هو المكان المناسب لفرضه. لدعم هذا الأسلوب ، يحتاج المسلسل فقط إلى كشف قائمة الحقول التي يقبلها كمدخلات ،

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

  1. يجب أن يكون النموذج مسؤولاً عن التحقق من الاتساق الداخلي و
  2. يجب أن يكون "العرض" (في هذه الحالة ، معالج وضع REST) ​​مسؤولاً عن فرض قواعد العمل (مثل RFC) المتعلقة بهذا العرض.

إذا اختفت مسؤولية التحقق من الصحة ، يمكن أن تكون المسلسلات جزئية بنسبة 100٪ (افتراضيًا) ومتخصصة لقواعد الإدخال / الإخراج مثل "للقراءة فقط". سوف يدعم ModelSerializer الذي تم إنشاؤه بهذه الطريقة مجموعة متنوعة من طرق العرض.

هل المسلسل المكان المناسب لحل هذه المشكلة؟

نعم.

مستندات التسلسل لـ 1.9 لا تذكر حتى التحقق من الصحة.

تسلسل Django المدمج ليس مفيدًا لـ Web APIS ، إنه يقتصر حقًا على الإغراق وتركيبات التحميل.

أنت تعرف الافتراضات المعمارية لكل من Django و DRF أفضل مني لذا يجب أن أراعي لك كيف. من المؤكد أن init kwarg لديه الإحساس الصحيح به ... إعادة تكوين المسلسل "عند الطلب". القيد الوحيد هو أنه لا يمكن إعادة تكوينها "سريعًا" ، لكنني أفترض أن الحالات تستخدم مرة واحدة ، لذا فهذه ليست مشكلة كبيرة.

سأقوم بإلغاء معلم هذا الآن. يمكننا إعادة التقييم بعد الإصدار 3.7

متروك لكم يا رفاق ، لكني أريد أن أتأكد من أنك واضح أن هذه ليست تذكرة لإضافة دعم التزامن. المشكلة الحقيقية هي أن المسلسل الفردي لا يمكنه التحقق بشكل صحيح من كل من PUT و POST في البنية الحالية. قدم التزامن للتو "اختبار الفشل".

TL ؛ DR يمكنك معرفة سبب حظر هذه المشكلة بالبدء في الإصلاح الذي اقترحه توم .

باختصار ، الحل المقترح هو جعل جميع الحقول مطلوبة لطلب PUT . هناك (على الأقل) مشكلتان في هذا النهج:

  1. يعتقد المسلسلون في الإجراءات وليس طرق HTTP ، لذلك لا يوجد تعيين واحد لواحد. المثال الواضح هو create لأنه مشترك بين PUT و POST . لاحظ أن create-by- PUT معطلة بشكل افتراضي لذا فإن الإصلاح المقترح ربما يكون أفضل من لا شيء.
  2. لا نحتاج إلى طلب جميع الحقول في PUT (شعور مشترك بواسطة # 3648 ، # 4703). إذا كان حقل nillable غائبًا ، فنحن نعلم أنه يمكن أن يكون لا شيء. إذا كان هناك حقل افتراضي غائب ، فنحن نعلم أنه يمكننا استخدام الافتراضي. PUT s لها نفس متطلبات الحقل (المشتقة من النموذج) مثل POST .

المشكلة الحقيقية هي كيف نتعامل مع البيانات المفقودة والاقتراح الأساسي في # 3648 ، # 4703 ، وهنا يبقى الحل الصحيح. يمكننا دعم جميع أوضاع HTTP (بما في ذلك create-by- PUT ) إذا قدمنا ​​مفهومًا مثل if_missing_use_default . قدمه اقتراحي الأصلي كبديل لـ partial ، لكن من الأسهل (وقد يكون ضروريًا) التفكير فيه كمفهوم متعامد.

إذا قدمنا ​​مفهومًا مثل if_missing_use_default.

لا يوجد شيء يمنع أي شخص من تنفيذ هذا ، أو "تتطلب جميع الحقول" الصارمة كفئة مسلسلة أساسية ، وتغليفها كمكتبة تابعة لجهة خارجية.

رأيي هو أن وضع "يتطلب جميع الحقول" الصارم قد يكون قادرًا أيضًا على تحويله إلى جوهر ، إنه سلوك واضح جدًا ، ويمكنني أن أرى سبب كون ذلك مفيدًا.

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

في كلتا الحالتين ، فإن الطريقة الصحيحة للتعامل مع ذلك هي التحقق من صحتها كحزمة تابعة لجهة خارجية ، ثم تحديث مستنداتنا حتى نتمكن من الارتباط بذلك.

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

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

الوصول إلى القيمة في وجود خيار PUT- هو سلوك صارم.

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

يبدو أن هذا سيقدم سلوكًا غير بديهي للغاية (على سبيل المثال ، حقول "created_at" ، والتي تنتهي تلقائيًا بتحديث نفسها).

يجب أن يكون الحقل created_at read_only (أو مستبعد من المسلسل). في كلتا الحالتين ، لن يتغير (سلوك المسلسل العادي). في الحالة غير البديهية التي لا يكون فيها الحقل للقراءة فقط في المسلسل ، ستحصل على سلوك غير بديهي يتمثل في تغييره تلقائيًا.

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

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

أغلق Tomchristie هذا منذ 4 ساعات

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

ربما تفكر في إضافة تصنيف مثل "ترحيب العلاقات العامة" أو "مكوّن إضافي تابع لجهة خارجية"

سيكون هذا معقولًا بما يكفي ، لكننا نود أن يعكس متتبع المشكلات لدينا العمل النشط أو القابل للتنفيذ في المشروع نفسه.

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

إذا تكرر ذلك مرارًا وتكرارًا ، ولم يكن هناك حل لطرف ثالث ، فربما نعيد تقييمه.

ترك قضايا صالحة / معترف بها مثل هذه مفتوحة.

سياق أكثر قليلاً حول أسلوب إدارة المشكلات - https://www.dabapps.com/blog/sustainable-open-source-management/

هل كانت هذه الصفحة مفيدة؟
0 / 5 - 0 التقييمات