Django-rest-framework: TypeError unhashable type:'ict 'مع RelatedField in Serializers

تم إنشاؤها على ٢٨ أبريل ٢٠١٧  ·  3تعليقات  ·  مصدر: encode/django-rest-framework

قائمة تدقيق

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

الشفرة

from rest_framework import serializers
from incidents.models import Incident

class NodeDataField(serializers.RelatedField):

    def to_representation(self, node):
        return {
            "id": node.id,
            "name": node.name,
            "ipaddress": node.ipv4
        }

    def to_internal_value(self, id):
        pass

هذا يعطي TypeError في / api / v1 / الحوادث /
نوع غير قابل للفصل: "ديكت"

unhashable type: 'dict'
5       <label class="col-sm-2 control-label {% if style.hide_label %}sr-only{% endif %}">
6         {{ field.label }}
7       </label>
8     {% endif %}
9   
10    <div class="col-sm-10">
11      <select class="form-control" name="{{ field.name }}">
12        {% if field.allow_null or field.allow_blank %}
13          <option value="" {% if not field.value %}selected{% endif %}>--------</option>
14        {% endif %}
15  

      {% for select in field.iter_options %}



16            {% if select.start_option_group %}
17              <optgroup label="{{ select.label }}">
18            {% elif select.end_option_group %}
19              </optgroup>
20            {% else %}
21              <option value="{{ select.value }}" {% if select.value|as_string == field.value|as_string %}selected{% endif %} {% if select.disabled %}disabled{% endif %}>{{ select.display_text }}</option>
22            {% endif %}
23       {% endfor %}
24     </select>

تتبع المكدس

/opt/grofers/firealarm-api/api/firealarm_api/lib/python3.4/_collections_abc.py in update
                                    self[key] = value
     ...
▶ Local vars
/opt/grofers/firealarm-api/api/firealarm_api/lib/python3.4/collections/__init__.py in __setitem__
            self.__update(*args, **kwds)
        def __setitem__(self, key, value,
                        dict_setitem=dict.__setitem__, proxy=_proxy, Link=_Link):
            'od.__setitem__(i, y) <==> od[i]=y'
            # Setting a new item creates a new link at the end of the linked list,
            # and the inherited dictionary is updated with the new key/value pair.
                        if key not in self:
     ...
                self.__map[key] = link = Link()
                root = self.__root
                last = root.prev
                link.prev, link.next, link.key = last, root, key
                last.next = link
                root.prev = proxy(link)
▼ Local vars
Variable    Value
self    
OrderedDict()
dict_setitem    
<slot wrapper '__setitem__' of 'dict' objects>
value   
'Node object'
proxy   
<built-in function proxy>
Link    
<class 'collections._Link'>
key     
{'id': 1, 'ipaddress': '172.31.84.130', 'name': 'abc123.con'}

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

  1. قم بإجراء مكالمة GET لعرض حيث يتم استخدام حقل Serializer المرتبط هذا و /؟ format = api فشل مع الخطأ الموصوف أعلاه بينما /؟ format = أعمال json ترجع الاستجابة كما هو متوقع.

    سلوك متوقع

يجب أن تعرض صفحة عرض واجهة برمجة تطبيقات Rest-framework القابلة للتصفح

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

الفشل مع TypeError في / api / v1 / الحوادث /
نوع غير قابل للفصل: "ديكت"

التعليق الأكثر فائدة

أحاول بطريقة ما تجنب الكتابة فوق الطرق create و update للمسلسل حيث يمكنني ذلك. لهذا ، كتبت فصلًا صغيرًا لمساعدتي في القيام بذلك ، لكن لسبب ما ، لدي خطأ متعلق بهذا.

class PrimaryKeyField(serializers.RelatedField):
    def __init__(self, serializer, **kwargs):
        self.serializer = serializer(**kwargs)
        if "queryset" not in kwargs:
            kwargs["queryset"] = self.serializer.Meta.model.objects.all()
        self.pk_field = serializers.PrimaryKeyRelatedField(**kwargs)

        super().__init__(**kwargs)

    def to_representation(self, instance):
        return self.serializer.to_representation(instance)

    def to_internal_value(self, data):
        try:
            return self.pk_field.to_internal_value(data["id"])
        except TypeError:
            return data

الشيء هو أنني أحصل على unhashable type: 'collections.OrderedDict' to_representation . وأنا لا أفهم لماذا.

ال 3 كومينتر

مرحبًا manjitkumar - RelatedField s بشكل عام تمثل كائنًا مرتبطًا كقيمة واحدة (على سبيل المثال ، slug ، مفتاح أساسي ، url ، إلخ ...). إذا كنت تريد تقديم تمثيل كائن متداخل ، فيجب عليك استخدام مُسلسل متداخل .

أحاول بطريقة ما تجنب الكتابة فوق الطرق create و update للمسلسل حيث يمكنني ذلك. لهذا ، كتبت فصلًا صغيرًا لمساعدتي في القيام بذلك ، لكن لسبب ما ، لدي خطأ متعلق بهذا.

class PrimaryKeyField(serializers.RelatedField):
    def __init__(self, serializer, **kwargs):
        self.serializer = serializer(**kwargs)
        if "queryset" not in kwargs:
            kwargs["queryset"] = self.serializer.Meta.model.objects.all()
        self.pk_field = serializers.PrimaryKeyRelatedField(**kwargs)

        super().__init__(**kwargs)

    def to_representation(self, instance):
        return self.serializer.to_representation(instance)

    def to_internal_value(self, data):
        try:
            return self.pk_field.to_internal_value(data["id"])
        except TypeError:
            return data

الشيء هو أنني أحصل على unhashable type: 'collections.OrderedDict' to_representation . وأنا لا أفهم لماذا.

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

class AnyRelatedField(serializers.RelatedField):
    def __init__(self, query_fields=tuple(), **kwargs):
        if not query_fields:
            raise NotImplementedError("AnyRelatedField requires a query field names to be provided as a tuple")

        self.query_fields = query_fields
        self.query_objects = Q()

        super().__init__(**kwargs)

    def to_internal_value(self, data):
        for field in self.query_fields:
            if field in ['pk', 'id'] and not isinstance(data, int):
                continue
            self.query_objects |= Q(**{field: data})
        try:
            self.instance = self.queryset.get(self.query_objects)
            return self.instance
        except self.queryset.model.DoesNotExist:
            raise serializers.ValidationError(
                detail="{} object does not exist with {}: {}".format(
                    self.queryset.model.__name__, ', '.join(self.query_fields), data
                ),
                code=self.field_name
            )

    def to_representation(self, val):
        return val
هل كانت هذه الصفحة مفيدة؟
0 / 5 - 0 التقييمات