Django मॉडल ऑब्जेक्ट को सभी क्षेत्रों के साथ तानाशाही में परिवर्तित करें


257

कैसे एक Django मॉडल ऑब्जेक्ट को अपने सभी क्षेत्रों के साथ एक तानाशाही में परिवर्तित करता है ? सभी आदर्शों में विदेशी कुंजी और फ़ील्ड शामिल हैं editable=False

मुझे विस्तार से बताएं मान लें कि मेरे पास निम्नलिखित की तरह एक Django मॉडल है:

from django.db import models

class OtherModel(models.Model): pass

class SomeModel(models.Model):
    normal_value = models.IntegerField()
    readonly_value = models.IntegerField(editable=False)
    auto_now_add = models.DateTimeField(auto_now_add=True)
    foreign_key = models.ForeignKey(OtherModel, related_name="ref1")
    many_to_many = models.ManyToManyField(OtherModel, related_name="ref2")

टर्मिनल में, मैंने निम्नलिखित कार्य किया है:

other_model = OtherModel()
other_model.save()
instance = SomeModel()
instance.normal_value = 1
instance.readonly_value = 2
instance.foreign_key = other_model
instance.save()
instance.many_to_many.add(other_model)
instance.save()

मैं इसे निम्नलिखित शब्दकोश में बदलना चाहता हूं:

{'auto_now_add': datetime.datetime(2015, 3, 16, 21, 34, 14, 926738, tzinfo=<UTC>),
 'foreign_key': 1,
 'id': 1,
 'many_to_many': [1],
 'normal_value': 1,
 'readonly_value': 2}

असंतोषजनक उत्तर वाले प्रश्न:

Django: एक मॉडल के ऑब्जेक्ट के पूरे सेट को एक शब्दकोश में परिवर्तित करना

मैं Django मॉडल ऑब्जेक्ट्स को एक शब्दकोश में कैसे बदल सकता हूं और अभी भी उनकी विदेशी कुंजी है?


1
आप नामक एक विधि की घोषणा कर सकते हैं to_dictऔर इसे जिस तरह से आप चाहते हैं उसे संभाल सकते हैं।
कार्तिक

@Kikikr हाँ, मैं कर सकता था। सवाल यह है कि ऐसी विधि कैसे बनाई जाए। मॉडल के सभी क्षेत्रों से मैन्युअल रूप से एक शब्दकोश का निर्माण एक उपयुक्त उत्तर नहीं है।
ज़ैग्स

मैं Django रेस्ट फ्रेमवर्क, Tastypie या पिस्टन जैसी एक मौजूदा ReST लाइब्रेरी का लाभ उठाता हूं क्योंकि वे सभी धारावाहिकीकरण के लिए django मॉडल के उदाहरणों को आदिम में बदलने के लिए तंत्र प्रदान करते हैं। यदि आप अधिक उत्सुक हैं कि कैसे, आप उनके कोड के माध्यम से देख सकते हैं, लेकिन यह ज्यादातर मॉडल से _metaसंबंधित क्षेत्रों को खोजने और उदाहरण पर उनके मूल्यों को पुनः प्राप्त करने के लिए मॉडल की परिभाषाओं के माध्यम से चल रहा है ।
केविन स्टोन

जवाबों:


523

एक मामले को डिक्शनरी में बदलने के कई तरीके हैं, जिसमें कोने केस हैंडलिंग की अलग-अलग डिग्री और वांछित परिणाम के लिए निकटता है।


1। instance.__dict__

instance.__dict__

जो लौटता है

{'_foreign_key_cache': <OtherModel: OtherModel object>,
 '_state': <django.db.models.base.ModelState at 0x7ff0993f6908>,
 'auto_now_add': datetime.datetime(2018, 12, 20, 21, 34, 29, 494827, tzinfo=<UTC>),
 'foreign_key_id': 2,
 'id': 1,
 'normal_value': 1,
 'readonly_value': 2}

यह अब तक सबसे सरल है, लेकिन गायब है many_to_many, foreign_keyगलत है, और इसमें दो अवांछित अतिरिक्त चीजें हैं।


2। model_to_dict

from django.forms.models import model_to_dict
model_to_dict(instance)

जो लौटता है

{'foreign_key': 2,
 'id': 1,
 'many_to_many': [<OtherModel: OtherModel object>],
 'normal_value': 1}

यह केवल एक ही है many_to_many, लेकिन असमान क्षेत्रों को याद कर रहा है।


3। model_to_dict(..., fields=...)

from django.forms.models import model_to_dict
model_to_dict(instance, fields=[field.name for field in instance._meta.fields])

जो लौटता है

{'foreign_key': 2, 'id': 1, 'normal_value': 1}

यह मानक model_to_dictमंगलाचरण से कड़ाई से बदतर है ।


4। query_set.values()

SomeModel.objects.filter(id=instance.id).values()[0]

जो लौटता है

{'auto_now_add': datetime.datetime(2018, 12, 20, 21, 34, 29, 494827, tzinfo=<UTC>),
 'foreign_key_id': 2,
 'id': 1,
 'normal_value': 1,
 'readonly_value': 2}

यह एक ही आउटपुट है, instance.__dict__लेकिन अतिरिक्त फ़ील्ड के बिना। foreign_key_idअभी भी गलत है और many_to_manyअभी भी लापता है।


5. कस्टम समारोह

Django के कोड का model_to_dictअधिकांश उत्तर था। इसने गैर-संपादन योग्य क्षेत्रों को स्पष्ट रूप से हटा दिया है, इसलिए उस चेक को हटाकर कई फ़ील्ड्स के लिए विदेशी कुंजियों की आईडी प्राप्त करने के लिए निम्न कोड परिणाम है जो वांछित व्यवहार करता है:

from itertools import chain

def to_dict(instance):
    opts = instance._meta
    data = {}
    for f in chain(opts.concrete_fields, opts.private_fields):
        data[f.name] = f.value_from_object(instance)
    for f in opts.many_to_many:
        data[f.name] = [i.id for i in f.value_from_object(instance)]
    return data

जबकि यह सबसे जटिल विकल्प है, कॉलिंग to_dict(instance)हमें वांछित परिणाम देता है:

{'auto_now_add': datetime.datetime(2018, 12, 20, 21, 34, 29, 494827, tzinfo=<UTC>),
 'foreign_key': 2,
 'id': 1,
 'many_to_many': [2],
 'normal_value': 1,
 'readonly_value': 2}

6. सीरियल का उपयोग करें

Django रेस्ट फ्रेमवर्क 'ModelSerialzer आपको एक मॉडल से स्वचालित रूप से एक धारावाहिक बनाने की अनुमति देता है।

from rest_framework import serializers
class SomeModelSerializer(serializers.ModelSerializer):
    class Meta:
        model = SomeModel
        fields = "__all__"

SomeModelSerializer(instance).data

रिटर्न

{'auto_now_add': '2018-12-20T21:34:29.494827Z',
 'foreign_key': 2,
 'id': 1,
 'many_to_many': [2],
 'normal_value': 1,
 'readonly_value': 2}

यह लगभग कस्टम फ़ंक्शन के रूप में अच्छा है, लेकिन ऑटो_नो_डैट एक डेटाइम ऑब्जेक्ट के बजाय एक स्ट्रिंग है।


बोनस दौर: बेहतर मॉडल प्रिंटिंग

यदि आप एक django मॉडल चाहते हैं जिसमें एक बेहतर अजगर कमांड-लाइन डिस्प्ले है, तो अपने मॉडल को निम्न में से चाइल्ड-क्लास करें:

from django.db import models
from itertools import chain

class PrintableModel(models.Model):
    def __repr__(self):
        return str(self.to_dict())

    def to_dict(instance):
        opts = instance._meta
        data = {}
        for f in chain(opts.concrete_fields, opts.private_fields):
            data[f.name] = f.value_from_object(instance)
        for f in opts.many_to_many:
            data[f.name] = [i.id for i in f.value_from_object(instance)]
        return data

    class Meta:
        abstract = True

इसलिए, उदाहरण के लिए, यदि हम अपने मॉडलों को इस प्रकार परिभाषित करते हैं:

class OtherModel(PrintableModel): pass

class SomeModel(PrintableModel):
    normal_value = models.IntegerField()
    readonly_value = models.IntegerField(editable=False)
    auto_now_add = models.DateTimeField(auto_now_add=True)
    foreign_key = models.ForeignKey(OtherModel, related_name="ref1")
    many_to_many = models.ManyToManyField(OtherModel, related_name="ref2")

SomeModel.objects.first()अब कॉलिंग इस तरह से आउटपुट देती है:

{'auto_now_add': datetime.datetime(2018, 12, 20, 21, 34, 29, 494827, tzinfo=<UTC>),
 'foreign_key': 2,
 'id': 1,
 'many_to_many': [2],
 'normal_value': 1,
 'readonly_value': 2}

2
इस उत्तर के लिए धन्यवाद! आप isinstanceपरीक्षण को समाधान # 5 (और बोनस) में बदल सकते हैं if f.many_to_many
dobobbs

1
@dhobbs मैंने Django के model_to_dictकोड के कोड को मॉडल किया , जो उपयोग करता है isinstance। मुझे यकीन नहीं है कि उन्होंने यह चुनाव क्यों किया लेकिन इसके लिए एक अच्छा कारण हो सकता है (जैसे कि many_to_manyबाद के संस्करण में संपत्ति को पेश किया जा रहा है)
ज़ैग्स

क्या यह @propertyखेतों को भी लौटाएगा ?
नाराजगी

1
मुझे आश्चर्य है कि इन तरीकों से एनोटेट / एग्रीगेटेड खेतों का इलाज कैसे होगा?
mehmet

जो कुछ मैं करता हूं वह get_FOO_display के लिए जांचा जाता है और जो भी वास्तव में हो सकता है उसके बजाय उस मूल्य को वापस कर देता है।
बोबोर्ट

9

मुझे परिणाम प्राप्त करने के लिए एक साफ समाधान मिला:

मान लीजिए कि आपके पास एक मॉडल ऑब्जेक्ट है o:

बस कॉल करना:

type(o).objects.filter(pk=o.pk).values().first()

10
यह मेरे उत्तर में सिर्फ # 4 विकल्प है
ज़ैग्स

7

@Zags समाधान भव्य था!

हालाँकि, मैं इसे JSON के अनुकूल बनाने के लिए डेटफिल्ड के लिए एक शर्त जोड़ूंगा।

बोनस दौर

यदि आप एक django मॉडल चाहते हैं जिसमें एक बेहतर अजगर कमांड-लाइन डिस्प्ले है, तो अपने मॉडल को निम्न वर्ग में रखें:

from django.db import models
from django.db.models.fields.related import ManyToManyField

class PrintableModel(models.Model):
    def __repr__(self):
        return str(self.to_dict())

    def to_dict(self):
        opts = self._meta
        data = {}
        for f in opts.concrete_fields + opts.many_to_many:
            if isinstance(f, ManyToManyField):
                if self.pk is None:
                    data[f.name] = []
                else:
                    data[f.name] = list(f.value_from_object(self).values_list('pk', flat=True))
            elif isinstance(f, DateTimeField):
                if f.value_from_object(self) is not None:
                    data[f.name] = f.value_from_object(self).timestamp()
            else:
                data[f.name] = None
            else:
                data[f.name] = f.value_from_object(self)
        return data

    class Meta:
        abstract = True

इसलिए, उदाहरण के लिए, यदि हम अपने मॉडलों को इस प्रकार परिभाषित करते हैं:

class OtherModel(PrintableModel): pass

class SomeModel(PrintableModel):
    value = models.IntegerField()
    value2 = models.IntegerField(editable=False)
    created = models.DateTimeField(auto_now_add=True)
    reference1 = models.ForeignKey(OtherModel, related_name="ref1")
    reference2 = models.ManyToManyField(OtherModel, related_name="ref2")

SomeModel.objects.first()अब कॉलिंग इस तरह से आउटपुट देती है:

{'created': 1426552454.926738,
'value': 1, 'value2': 2, 'reference1': 1, u'id': 1, 'reference2': [1]}

यदि आप JSON से परिवर्तित करना चाहते हैं, तो आपको Django रेस्ट फ्रेमवर्क में देखना चाहिए या कुछ इस तरह का उपयोग करना चाहिए: stackoverflow.com/a/22238613/2800876
Zags

ज़रूर! लेकिन आपके कोड में यह छोटा सा बदलाव सुविधा का एक बड़ा हिस्सा जोड़ देता है!
डिएगो फ्रीटास

4

सबसे सरल तरीका,

  1. यदि आपकी क्वेरी Model.Objects.get () है:

    get () एकल उदाहरण लौटाएगा ताकि आप __dict__अपने उदाहरण से प्रत्यक्ष उपयोग कर सकें

    model_dict = Model.Objects.get().__dict__

  2. के लिए फिल्टर () / सब ():

    सभी () / फ़िल्टर () उदाहरणों की सूची वापस कर देंगे ताकि आप values()वस्तुओं की सूची प्राप्त करने के लिए उपयोग कर सकें।

    model_values ​​= Model.Objects.all ()। मान)


4

बस vars(obj), यह वस्तु के पूरे मूल्यों को बताएगा

>>> obj_attrs = vars(obj)
>>> obj_attrs
 {'_file_data_cache': <FileData: Data>,
  '_state': <django.db.models.base.ModelState at 0x7f5c6733bad0>,
  'aggregator_id': 24,
  'amount': 5.0,
  'biller_id': 23,
  'datetime': datetime.datetime(2018, 1, 31, 18, 43, 58, 933277, tzinfo=<UTC>),
  'file_data_id': 797719,
 }

आप इसे भी जोड़ सकते हैं

>>> keys = obj_attrs.keys()
>>> temp = [obj_attrs.pop(key) if key.startswith('_') else None for key in keys]
>>> del temp
>>> obj_attrs
   {
    'aggregator_id': 24,
    'amount': 5.0,
    'biller_id': 23,
    'datetime': datetime.datetime(2018, 1, 31, 18, 43, 58, 933277, tzinfo=<UTC>),
    'file_data_id': 797719,
   }

3

अपडेट करें

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

मूल

यदि आप अपने खुद के to_dict तरीके को परिभाषित करने के लिए तैयार हैं जैसे @karthiker ने सुझाव दिया है, तो बस इस समस्या को एक सेट समस्या में उबलता है।

>>># Returns a set of all keys excluding editable = False keys
>>>dict = model_to_dict(instance)
>>>dict

{u'id': 1L, 'reference1': 1L, 'reference2': [1L], 'value': 1}


>>># Returns a set of editable = False keys, misnamed foreign keys, and normal keys
>>>otherDict = SomeModel.objects.filter(id=instance.id).values()[0]
>>>otherDict

{'created': datetime.datetime(2014, 2, 21, 4, 38, 51, tzinfo=<UTC>),
 u'id': 1L,
 'reference1_id': 1L,
 'value': 1L,
 'value2': 2L}

हमें अन्य डिडिक्ट से गलत विदेशी कुंजी को हटाने की आवश्यकता है ।

ऐसा करने के लिए, हम एक लूप का उपयोग कर सकते हैं जो एक नया शब्दकोश बनाता है जिसमें हर आइटम होता है सिवाय उन में अंडरस्कोर के। या, समय बचाने के लिए, हम सिर्फ मूल करने के लिए उन में जोड़ सकते हैं dict के बाद शब्दकोशों हुड के नीचे सिर्फ सेट कर रहे हैं।

>>>for item in otherDict.items():
...    if "_" not in item[0]:
...            dict.update({item[0]:item[1]})
...
>>>

इस प्रकार हम निम्नलिखित तानाशाही से बचे हैं :

>>>dict
{'created': datetime.datetime(2014, 2, 21, 4, 38, 51, tzinfo=<UTC>),
 u'id': 1L,
 'reference1': 1L,
 'reference2': [1L],
 'value': 1,
 'value2': 2L}

और तुम अभी लौटते हो।

नकारात्मक पक्ष पर, आप अपने संपादन योग्य = झूठे फ़ील्ड नामों में अंडरस्कोर का उपयोग नहीं कर सकते। उल्टा, यह उन फ़ील्ड्स के किसी भी सेट के लिए काम करेगा जहाँ उपयोगकर्ता द्वारा बनाए गए फ़ील्ड में अंडरस्कोर नहीं होते हैं।

यह ऐसा करने का सबसे अच्छा तरीका नहीं है, लेकिन यह एक अस्थायी समाधान के रूप में काम कर सकता है जब तक कि अधिक प्रत्यक्ष विधि नहीं मिलती है।

नीचे दिए गए उदाहरण के लिए, model_to_dict के आधार पर तानाशाही का गठन किया जाएगा और फ़िल्टर के मान विधि द्वारा अन्य निर्णय का गठन किया जाएगा। मैंने खुद मॉडल के साथ ऐसा किया होगा, लेकिन मैं अपने मशीन को दूसरे मॉडल को स्वीकार नहीं कर सकता।

>>> import datetime
>>> dict = {u'id': 1, 'reference1': 1, 'reference2': [1], 'value': 1}
>>> otherDict = {'created': datetime.datetime(2014, 2, 21, 4, 38, 51), u'id': 1, 'reference1_id': 1, 'value': 1, 'value2': 2}
>>> for item in otherDict.items():
...     if "_" not in item[0]:
...             dict.update({item[0]:item[1]})
...
>>> dict
{'reference1': 1, 'created': datetime.datetime(2014, 2, 21, 4, 38, 51), 'value2': 2, 'value': 1, 'id': 1, 'reference2': [1]}
>>>

मुझे आपको अपने प्रश्न के उत्तर के मोटे अक्षरों में रखना चाहिए, मुझे आशा है।


1
सुनिश्चित नहीं हैं कि आप reयहाँ क्या उपयोग करने का प्रयास कर रहे हैं। यदि यह उन में अंडरस्कोर के साथ कुंजियों को फ़िल्टर करना है, तो यह न तो सही कोड है और न ही सही व्यवहार है। डेटाबेस में re.match("_", "reference1_id")रिटर्न Noneऔर वैध कॉलम उनके नाम में अंडरस्कोर हो सकते हैं।
ज़ैग

re.match ("_", "reference1_id") कोई नहीं लौटाता है, यह होना चाहिए था: re.match ((*। * _। * "," reference1_id ")
गैजेट

मैंने खराब उदाहरण को हटाने के लिए कुछ बदलाव किए हैं और उनमें एक बेहतर शामिल है। मैंने यह व्यक्त करने के लिए कुछ चीजें भी बदल दीं कि यह सभी मॉडलों के सबसेट के लिए एक अस्थायी समाधान होगा। मुझे नहीं पता कि आप उनके editable=falseक्षेत्रों में अंडरस्कोर वाले मॉडल के लिए क्या करेंगे । मैं बस कुछ प्रदान करने की कोशिश कर रहा था जब तक कि अधिक कैनन समाधान नहीं दिया जा सकता है तब तक आप काम कर सकते हैं।
गैजेट

शायद उस मामले में "_" in stringबजाय उपयोग करें re
झीग्स

हां, यह करने का एक बहुत आसान तरीका होगा। यह इस तरह से उपयोग करने के लिए मेरे साथ नहीं हुआ था, लेकिन यह अब पूरी तरह से अच्छा बनाता है। मैंने inइसके बजाय उपयोग करने का उत्तर बदल दिया है re
गैजेट

2

यहाँ दिलचस्प समाधान के बहुत सारे। मेरा समाधान यह था कि मैं अपने मॉडल में एक तानाशाही समझ के साथ एक as_dict तरीका जोड़ूं।

def as_dict(self):
    return dict((f.name, getattr(self, f.name)) for f in self._meta.fields)

एक बोनस के रूप में, यह समाधान एक क्वेरी पर एक सूची समझ के साथ जोड़ा गया है, एक अच्छा समाधान के लिए बनाता है यदि आप अपने मॉडल को किसी अन्य लाइब्रेरी में निर्यात करना चाहते हैं। उदाहरण के लिए, अपने मॉडल को पांडा डेटाफ़्रेम में डंप करना:

pandas_awesomeness = pd.DataFrame([m.as_dict() for m in SomeModel.objects.all()])

1
यह स्ट्रिंग्स और इन्टस जैसे मूल्य क्षेत्रों के लिए ठीक काम करता है, लेकिन विदेशी कुंजी के साथ कुछ समस्याएँ होंगी और कई क्षेत्रों के लिए बहुत अधिक के साथ
ज़ैग्स

बहुत अच्छी बात! खासतौर पर बहुतों को। कोई उन मामलों को उचित रूप से संभालने के लिए कुछ शर्तों को रखना चाहेगा, या इस समाधान को सरल मॉडल तक सीमित कर देगा। धन्यवाद।
t1m0

1

(टिप्पणी करने का मतलब यह नहीं था)

ठीक है, यह वास्तव में उस तरह के प्रकारों पर निर्भर नहीं करता है। हो सकता है कि मैंने यहां मूल प्रश्न को गलत समझा हो, अगर ऐसा है तो मुझे क्षमा करें। यदि आप serliazers.py बनाते हैं, तो वहां आप वे कक्षाएं बनाते हैं जिनमें मेटा कक्षाएं होती हैं।

Class MyModelSerializer(serializers.ModelSerializer):
    class Meta:
        model = modelName
        fields =('csv','of','fields')

फिर जब आप दृश्य वर्ग में डेटा प्राप्त कर सकते हैं:

model_data - Model.objects.filter(...)
serializer = MyModelSerializer(model_data, many=True)
return Response({'data': serilaizer.data}, status=status.HTTP_200_OK)

स्थानों की विविधता में मेरे पास बहुत कुछ है और यह JSONRenderer के माध्यम से अच्छा JSON देता है।

जैसा कि मैंने कहा कि यह DjangoRestFramework के सौजन्य से है इसलिए यह देखने लायक है।


1

आसान तरीका सिर्फ उपयोग करना है pprint, जो आधार पायथन में है

import pprint
item = MyDjangoModel.objects.get(name = 'foo')
pprint.pprint(item.__dict__, indent = 4)

यह आउटपुट देता है जो समान दिखता है, json.dumps(..., indent = 4)लेकिन यह सही ढंग से अजीब डेटा प्रकारों को संभालता है जो आपके मॉडल उदाहरण, जैसे ModelStateऔर UUID, आदि में एम्बेडेड हो सकते हैं ।

पायथन 3.7 पर परीक्षण किया गया


0

शायद यह आपकी मदद करे। हो सकता है कि यह बहुत से कई रिलेशनशिप को कवर न करे, लेकिन जब आप अपने मॉडल को json फॉर्मेट में भेजना चाहते हैं तो बहुत आसान है।

def serial_model(modelobj):
  opts = modelobj._meta.fields
  modeldict = model_to_dict(modelobj)
  for m in opts:
    if m.is_relation:
        foreignkey = getattr(modelobj, m.name)
        if foreignkey:
            try:
                modeldict[m.name] = serial_model(foreignkey)
            except:
                pass
  return modeldict

0

सबसे अच्छा समाधान जो आपने कभी देखा है।

कन्वर्ट django.db.models.Model उदाहरण और सभी संबंधित ForeignKey, ManyToManyField और @Property फ़ंक्शन फ़ील्ड्स को तानाशाही में।

"""
Convert django.db.models.Model instance and all related ForeignKey, ManyToManyField and @property function fields into dict.
Usage:
    class MyDjangoModel(... PrintableModel):
        to_dict_fields = (...)
        to_dict_exclude = (...)
        ...
    a_dict = [inst.to_dict(fields=..., exclude=...) for inst in MyDjangoModel.objects.all()]
"""
import typing

import django.core.exceptions
import django.db.models
import django.forms.models


def get_decorators_dir(cls, exclude: typing.Optional[set]=None) -> set:
    """
    Ref: /programming/4930414/how-can-i-introspect-properties-and-model-fields-in-django
    :param exclude: set or None
    :param cls:
    :return: a set of decorators
    """
    default_exclude = {"pk", "objects"}
    if not exclude:
        exclude = default_exclude
    else:
        exclude = exclude.union(default_exclude)

    return set([name for name in dir(cls) if name not in exclude and isinstance(getattr(cls, name), property)])


class PrintableModel(django.db.models.Model):

    class Meta:
        abstract = True

    def __repr__(self):
        return str(self.to_dict())

    def to_dict(self, fields: typing.Optional[typing.Iterable]=None, exclude: typing.Optional[typing.Iterable]=None):
        opts = self._meta
        data = {}

        # support fields filters and excludes
        if not fields:
            fields = set()
        else:
            fields = set(fields)
        default_fields = getattr(self, "to_dict_fields", set())
        fields = fields.union(default_fields)

        if not exclude:
            exclude = set()
        else:
            exclude = set(exclude)
        default_exclude = getattr(self, "to_dict_exclude", set())
        exclude = exclude.union(default_exclude)

        # support syntax "field__childField__..."
        self_fields = set()
        child_fields = dict()
        if fields:
            for i in fields:
                splits = i.split("__")
                if len(splits) == 1:
                    self_fields.add(splits[0])
                else:
                    self_fields.add(splits[0])

                    field_name = splits[0]
                    child_fields.setdefault(field_name, set())
                    child_fields[field_name].add("__".join(splits[1:]))

        self_exclude = set()
        child_exclude = dict()
        if exclude:
            for i in exclude:
                splits = i.split("__")
                if len(splits) == 1:
                    self_exclude.add(splits[0])
                else:
                    field_name = splits[0]
                    if field_name not in child_exclude:
                        child_exclude[field_name] = set()
                    child_exclude[field_name].add("__".join(splits[1:]))

        for f in opts.concrete_fields + opts.many_to_many:
            if self_fields and f.name not in self_fields:
                continue
            if self_exclude and f.name in self_exclude:
                continue

            if isinstance(f, django.db.models.ManyToManyField):
                if self.pk is None:
                    data[f.name] = []
                else:
                    result = []
                    m2m_inst = f.value_from_object(self)
                    for obj in m2m_inst:
                        if isinstance(PrintableModel, obj) and hasattr(obj, "to_dict"):
                            d = obj.to_dict(
                                fields=child_fields.get(f.name),
                                exclude=child_exclude.get(f.name),
                            )
                        else:
                            d = django.forms.models.model_to_dict(
                                obj,
                                fields=child_fields.get(f.name),
                                exclude=child_exclude.get(f.name)
                            )
                        result.append(d)
                    data[f.name] = result
            elif isinstance(f, django.db.models.ForeignKey):
                if self.pk is None:
                    data[f.name] = []
                else:
                    data[f.name] = None
                    try:
                        foreign_inst = getattr(self, f.name)
                    except django.core.exceptions.ObjectDoesNotExist:
                        pass
                    else:
                        if isinstance(foreign_inst, PrintableModel) and hasattr(foreign_inst, "to_dict"):
                            data[f.name] = foreign_inst.to_dict(
                                fields=child_fields.get(f.name),
                                exclude=child_exclude.get(f.name)
                            )
                        elif foreign_inst is not None:
                            data[f.name] = django.forms.models.model_to_dict(
                                foreign_inst,
                                fields=child_fields.get(f.name),
                                exclude=child_exclude.get(f.name),
                            )

            elif isinstance(f, (django.db.models.DateTimeField, django.db.models.DateField)):
                v = f.value_from_object(self)
                if v is not None:
                    data[f.name] = v.isoformat()
                else:
                    data[f.name] = None
            else:
                data[f.name] = f.value_from_object(self)

        # support @property decorator functions
        decorator_names = get_decorators_dir(self.__class__)
        for name in decorator_names:
            if self_fields and name not in self_fields:
                continue
            if self_exclude and name in self_exclude:
                continue

            value = getattr(self, name)
            if isinstance(value, PrintableModel) and hasattr(value, "to_dict"):
                data[name] = value.to_dict(
                    fields=child_fields.get(name),
                    exclude=child_exclude.get(name)
                )
            elif hasattr(value, "_meta"):
                # make sure it is a instance of django.db.models.fields.Field
                data[name] = django.forms.models.model_to_dict(
                    value,
                    fields=child_fields.get(name),
                    exclude=child_exclude.get(name),
                )
            elif isinstance(value, (set, )):
                data[name] = list(value)
            else:
                data[name] = value

        return data

https://gist.github.com/shuge/f543dc2094a3183f69488df2bfb51a52


0

@ ज़ैग्स से उत्तर व्यापक है और पर्याप्त होना चाहिए लेकिन # 5 विधि (जो कि सबसे अच्छा एक आईएमओ है) एक त्रुटि फेंकता है इसलिए मैंने सहायक फ़ंक्शन में सुधार किया।

जैसा कि ओपी ने many_to_manyवस्तुओं की एक सूची के बजाय प्राथमिक कुंजियों की सूची में खेतों को परिवर्तित करने के लिए अनुरोध किया था , मैंने फ़ंक्शन को बढ़ाया ताकि रिटर्न मूल्य अब JSON अनुक्रमिक हो - datetimeवस्तुओं को strऔर many_to_manyवस्तुओं को आईडी की सूची में परिवर्तित करके ।

import datetime

def ModelToDict(instance):
    '''
    Returns a dictionary object containing complete field-value pairs of the given instance

    Convertion rules:

        datetime.date --> str
        many_to_many --> list of id's

    '''

    concrete_fields = instance._meta.concrete_fields
    m2m_fields = instance._meta.many_to_many
    data = {}

    for field in concrete_fields:
        key = field.name
        value = field.value_from_object(instance)
        if type(value) == datetime.datetime:
            value = str(field.value_from_object(instance))
        data[key] = value

    for field in m2m_fields:
        key = field.name
        value = field.value_from_object(instance)
        data[key] = [rel.id for rel in value]

    return data

आपको क्या त्रुटि है? मुझे जवाब अपडेट करने में खुशी हो रही है
ज़ैग्स

वर्तमान में छोरों की कार्यक्षमता concrete_fieldsऔर m2m_fieldsसमान दिखती है, इसलिए यह मानते हुए कि m2m_fieldsलूप का यहां गलत कार्यान्वयन है।
डैनियल हिममेलस्टीन

@Zags त्रुटि है AttributeError: 'list' object has no attribute 'values_list' जो मुझे इसके पीछे का कारण नहीं मिला। Im Django 2.1.1 का उपयोग कर
Armin Hemati Nik

@ डेनियल-हेमेलस्टीन ने इशारा करने के लिए धन्यवाद दिया, मैंने कोड तय किया। समान छोरों का कारण मेरे स्थानीय कोड में अलग-अलग संचालन करने के कारण था और मैं एसओ उत्तर के लिए इसे अनुकूलित करना भूल गया था।
अर्मिन हेमती निक

@ArminHemati Django ने कार्यान्वयन को बदल दिया field.value_from_objectऔर परिणामस्वरूप, का model_to_dict। मैंने इसे दर्शाने के लिए अपने उत्तर की धारा 5 को अपडेट कर दिया है।
ज़ैग
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.