অক্ষরে রূপান্তর করুন জ্যাঙ্গো মডেলটিকে সমস্ত ক্ষেত্র অক্ষত রেখে


257

একজন জ্যাঙ্গো মডেলকে তার সমস্ত ক্ষেত্রের সাথে কীভাবে কোনও ডাকে রূপান্তর করতে পারে ? সমস্ত আদর্শ সহ বিদেশী কী এবং ক্ষেত্র অন্তর্ভুক্ত editable=False

আমাকে বিস্তারিত জানাতে দিন। আসুন ধরা যাক আমার মতো জ্যাঙ্গো মডেল রয়েছে নীচের মতো:

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}

অসন্তুষ্ট উত্তর সহ প্রশ্নগুলি:

জ্যাঙ্গো: কোনও মডেলের সামগ্রীর পুরো সেটকে একক অভিধানে রূপান্তর করা

আমি কীভাবে জাজানো মডেল অবজেক্টগুলিকে একটি অভিধানে পরিণত করতে পারি এবং তার বিদেশী কীগুলি এখনও থাকতে পারি?


1
আপনি ডাকা একটি পদ্ধতি ঘোষণা করতে পারেন to_dictএবং এটি আপনার পছন্দ মতো পরিচালনা করতে পারেন।
karthikr

@ কর্মার্থিক হ্যাঁ, আমি পারতাম। প্রশ্ন হল এই জাতীয় পদ্ধতি কীভাবে তৈরি করা যায়। মডেলের সমস্ত ক্ষেত্র থেকে ম্যানুয়ালি একটি অভিধান তৈরি করা উপযুক্ত উত্তর নয়।
জাগস

আমি জ্যাঙ্গো রেস্ট ফ্রেমওয়ার্ক, টেস্টিপি বা পিস্টনের মতো একটি বিদ্যমান আরএসটি লাইব্রেরি নিয়েছি কারণ তারা সকলেই জ্যাঙ্গো মডেল দৃষ্টান্তগুলিকে সিরিয়ালের জন্য আদিম রূপান্তরিত করার প্রক্রিয়া সরবরাহ করে। আপনি যদি আরও কৌতূহলী হন তবে কীভাবে আপনি তাদের কোডটি সন্ধান করতে পারেন তবে মডেলটির _metaসাথে সম্পর্কিত ক্ষেত্রগুলি খুঁজে পেতে এবং উদাহরণস্বরূপ তাদের মানগুলি পুনরুদ্ধার করার জন্য এটি বেশিরভাগই মডেলের সংজ্ঞাগুলির মধ্য দিয়ে চলে walking
কেভিন স্টোন

উত্তর:


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. কাস্টম ফাংশন

জাঙ্গোর জন্য কোডটির 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}

Ser. সিরিয়ালাইজার ব্যবহার করুন

জ্যাঙ্গো রেস্ট ফ্রেমওয়ার্কের মডেলসিরিয়েজার আপনাকে একটি মডেল থেকে স্বয়ংক্রিয়ভাবে একটি সিরিয়াল তৈরি করতে দেয়।

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}

এটি কাস্টম ফাংশনের মতো প্রায় ভাল, তবে অটো_নো_এডিডি একটি ডেটটাইম অবজেক্টের পরিবর্তে একটি স্ট্রিং।


বোনাস রাউন্ড: আরও ভাল মডেল মুদ্রণ

যদি আপনি এমন একটি জাঙ্গো মডেল চান যা একটি অজগর কমান্ড-লাইন প্রদর্শন করতে পারে তবে আপনার মডেলগুলি নিম্নোক্ত শিশু-শ্রেণিতে থাকুন:

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
ধোবস

1
@Dobobs আমি সেই কোডটি জাঙ্গোর কোড থেকে বন্ধ করে দিয়েছি model_to_dict, যা ব্যবহার করে isinstance। কেন তারা এই পছন্দটি করেছেন তা আমি নিশ্চিত নই তবে এর জন্য একটি ভাল কারণ থাকতে পারে (যেমন many_to_manyসম্পত্তি পরবর্তী সংস্করণে প্রবর্তন করা হচ্ছে)
Zags

এটা কি @propertyমাঠ ফিরবে ?
রাগ করুন

1
আমি ভাবছি কীভাবে এই পদ্ধতিগুলি টীকাগুলি / একত্রিত ক্ষেত্রগুলির সাথে আচরণ করবে?
মেহমেট

আমি যা করি তা হ'ল get_FOO_display পরীক্ষা করে দেখুন এবং যে মানটি সেখানে থাকতে পারে পরিবর্তে সেই মানটি ফিরিয়ে দেয়।
বোবার্ট

9

ফলাফল পেতে আমি একটি ঝরঝরে সমাধান পেয়েছি:

ধরুন আপনার কাছে কোনও মডেল অবজেক্ট রয়েছে o:

শুধু কল:

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

10
এটি আমার উত্তরের কেবল # 4 বিকল্প
জাগস 21

7

@ জাগস দ্রবণটি দারুণ ছিল!

আমি ডেটফিল্ডসকে জেএসএন বান্ধব করার জন্য একটি শর্ত যুক্ত করব।

বোনাস রাউন্ড

আপনি যদি এমন একটি জাঙ্গো মডেল চান যাতে অজগর কমান্ড-লাইনটি আরও ভাল থাকে তবে আপনার মডেলগুলি নিম্নরূপে শিশু শ্রেণি করুন:

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 এ এবং রূপান্তর করতে চান তবে আপনার জাজানো রেস্ট ফ্রেমওয়ার্কটি সন্ধান করা উচিত বা এর মতো কিছু ব্যবহার করা উচিত: stackoverflow.com/a/22238613/2800876
Zags

নিশ্চিত! তবে আপনার কোডে এই ছোট পরিবর্তনটি সুবিধার জন্য একটি দুর্দান্ত চুক্তি যুক্ত করেছে!
দিয়েগো ফ্রেইটাস কোয়েলহো

4

সহজতম উপায়,

  1. যদি আপনার ক্যোয়ারী মডেল হয় Oঅবজেক্টস.জেট ():

    get () একক নজরে ফিরে আসবে যাতে আপনি __dict__আপনার উদাহরণ থেকে সরাসরি ব্যবহার করতে পারেন

    মডেল_ডিক্ট = Model.Objects.get().__dict__

  2. জন্য ফিল্টার () / সমস্ত ():

    সমস্ত () / ফিল্টার () উদাহরণগুলির তালিকা ফিরিয়ে দেবে যাতে আপনি values()বস্তুর তালিকা পেতে ব্যবহার করতে পারেন ।

    মডেল_ভ্যালু = মডেল.অবজেক্টস.ল ()। মানগুলি ()


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

হালনাগাদ

@ জাগগুলি পোস্ট করা নতুন সামগ্রিক উত্তর আমার নিজের চেয়ে আরও সম্পূর্ণ এবং মার্জিত। পরিবর্তে উত্তরটি দেখুন।

মূল

আপনি যদি @ কার্ত্তিকারের পরামর্শ অনুসারে আপনার নিজের_ডিক্ট পদ্ধতিটি সংজ্ঞায়িত করতে ইচ্ছুক হন, তবে এটি কেবল এই সমস্যাটিকে একটি সেট সমস্যার জন্য সিদ্ধ করে দেয়।

>>># 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}

আমাদের অন্য ডিক্ট থেকে বিভ্রান্তিকর বিদেশী কীগুলি সরানো দরকার ।

এটি করার জন্য, আমরা একটি লুপ ব্যবহার করতে পারি যা একটি নতুন অভিধান তৈরি করে যার প্রত্যেকটি আইটেমের আন্ডারস্কোরগুলি বাদ দিয়ে থাকে। অথবা, সময় সাশ্রয় করার জন্য, আমরা কেবল সেগুলি মূল ডিকের সাথে যুক্ত করতে পারি কারণ অভিধানগুলি হুডের নীচে কেবল সেট থাকে।

>>>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}

এবং আপনি ঠিক যে ফিরে।

খারাপ দিক থেকে, আপনি আপনার সম্পাদনাযোগ্য = মিথ্যা ক্ষেত্রের নামগুলিতে আন্ডারস্কোর ব্যবহার করতে পারবেন না। উল্টো দিকে, এটি এমন কোনও ক্ষেত্রের জন্য কাজ করবে যেখানে ব্যবহারকারী-তৈরি ক্ষেত্রগুলি আন্ডারস্কোরগুলি না করে।

এটি করার সর্বোত্তম উপায় নয়, তবে আরও সরাসরি পদ্ধতি না পাওয়া পর্যন্ত এটি অস্থায়ী সমাধান হিসাবে কাজ করতে পারে।

নীচের উদাহরণের জন্য, মডেল_ট_ডিক্টের উপর ভিত্তি করে ডিক গঠন করা হবে এবং অন্যান্য ডিক্ট ফিল্টারগুলির মান পদ্ধতি দ্বারা গঠিত হবে। আমি নিজেরাই মডেলগুলির সাথে এটি করতাম, তবে আমি আমার মেশিনটিকে অন্য মডেল গ্রহণ করতে পারি না।

>>> 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এবং বৈধ কলামগুলির নামে আন্ডারস্কোর থাকতে পারে।
Zags

পুনরায় ম্যাচ ("_", "রেফারেন্স 1_id") কিছুই ফেরায় না, এটি হওয়া উচিত ছিল: পুনরায় ম্যাচ ("। * _। *", "রেফারেন্স 1_id")
গ্যাজেট

আমি খারাপ উদাহরণটি মুছে ফেলার জন্য কিছু পরিবর্তন করেছি এবং আরও ভাল একটি অন্তর্ভুক্ত করেছি। আমি প্রকাশ করার জন্য কিছু জিনিসও পরিবর্তন করেছি যে এটি সমস্ত মডেলের একটি সাবসেটের জন্য একটি অস্থায়ী সমাধান হবে। মডেলগুলির editable=falseক্ষেত্রগুলিতে আন্ডারস্কোর সহ আপনি কী করবেন তা আমার কোনও ধারণা নেই । আমি কেবল এমন কিছু সরবরাহ করার চেষ্টা করছিলাম যাতে আপনি আরও বেশি ক্যানন সমাধান সরবরাহ না করা পর্যন্ত কাজ করতে সক্ষম হবেন able
গ্যাজেট

সে ক্ষেত্রে "_" in stringনা থেকে বরং ব্যবহার করুন re
Zags

হ্যাঁ, এটি করার আরও সহজ উপায়। এটি এটিকে ব্যবহার করার জন্য আমার কাছে ঘটেনি, তবে এটি এখন পুরোপুরি ভাল ধারণা তৈরি করে। আমি inপরিবর্তে ব্যবহারের উত্তর পরিবর্তন করেছি re
গ্যাজেট

2

এখানে আকর্ষণীয় সমাধান প্রচুর। আমার সমাধানটি ছিল আমার মডেলটিতে ডিক বোঝার সাথে একটি আস-ডিক্ট পদ্ধতি যুক্ত করা।

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
এটি স্ট্রিং এবং ইনটসের মতো মান ক্ষেত্রের জন্য সূক্ষ্মভাবে কাজ করে তবে বিদেশী কীগুলি এবং অনেকগুলি ক্ষেত্রে অনেক ক্ষেত্রে আরও কিছু সমস্যা থাকবে
Zags

খুব ভাল পয়েন্ট! বিশেষত অনেকের কাছে। এই কেসগুলি যথাযথভাবে পরিচালনা করতে কেউ কিছু শর্ত রাখতে চাইবে, বা এই সমাধানটি সহজ মডেলগুলিতে সীমাবদ্ধ করুন। ধন্যবাদ।
t1m0

1

(মন্তব্য করার অর্থ নয়)

ঠিক আছে, এটি সত্যিকারের ধরণের উপর নির্ভর করে না। আমি এখানে মূল প্রশ্নটি ভুল বুঝতে পেরেছি তাই যদি এটি হয় তবে আমাকে ক্ষমা করুন। আপনি যদি সেরলিয়াজার.পি তৈরি করেন তবে সেখানে আপনি ক্লাস তৈরি করেন যার মেটা ক্লাস রয়েছে।

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 ফিরিয়ে দেয়।

যেমনটি আমি বলেছিলাম এটি জ্যাঙ্গোরেস্ট ফ্রেমওয়ার্কের সৌজন্যে তাই এটি দেখার পক্ষে এটি মূল্যবান।


1

সহজ উপায় হ'ল কেবল ব্যবহার করা pprint, যা পাইথনের বেসে রয়েছে

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

এটি আউটপুট দেয় যা দেখতে অনুরূপ json.dumps(..., indent = 4)তবে এটি সঠিকভাবে অদ্ভুত ডেটা হ্যান্ডেলগুলি পরিচালনা করে যা আপনার মডেল উদাহরণগুলিতে এম্বেড হতে পারে যেমন ModelStateএবং এবং UUIDইত্যাদি etc.

পাইথন ৩.7 এ পরীক্ষা করা হয়েছে


0

হতে পারে এটি আপনাকে সাহায্য করবে। এটি অনেককে অনেকগুলি সম্পর্কিত সম্পর্কিত দিকে গোপন করতে না পারে, তবে আপনি যখন জেসন ফর্ম্যাটে আপনার মডেলটি প্রেরণ করতে চান তখন বেশ কার্যকর।

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 দৃষ্টান্ত এবং সমস্ত সম্পর্কিত ফরেনকে, ম্যান্টিটোম্যানিফিল্ড এবং @ প্রোপার্টি ফাংশন ক্ষেত্রগুলিকে ডিকে রূপান্তর করুন।

"""
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 serializable হয় - রূপান্তর দ্বারা 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

আপনি কী ত্রুটি পেয়েছেন? আমি উত্তরটি আপডেট করতে পেরে খুশি
Zags

বর্তমানে লুপগুলির কার্যকারিতা concrete_fieldsএবং m2m_fieldsঅভিন্ন দেখতে দেখতে তাই লুপটির m2m_fieldsএখানে একটি ভুল বাস্তবায়ন রয়েছে বলে ধরে নেওয়া হচ্ছে ।
ড্যানিয়েল হিমেলস্টেইন

@ জাগস ত্রুটিটি হ'ল AttributeError: 'list' object has no attribute 'values_list' যা এর পিছনে কারণটি আমি খুঁজে পেলাম না। আমি
জাজানো

@ ড্যানিয়েল-হিমেলস্টেইন আপনাকে নির্দেশ করার জন্য আপনাকে ধন্যবাদ, আমি কোডটি স্থির করেছি। অভিন্ন লুপগুলির কারণটি ছিল আমার স্থানীয় কোডে বিভিন্ন অপারেশন করানো এবং আমি এসও উত্তরের জন্য এটি অপ্টিমাইজ করতে ভুলে গিয়েছিলাম।
আরমিন হেমাতি নিক

@ আরমিনহেমতি জ্যাঙ্গো এর field.value_from_objectফলশ্রুতিতে এবং এর ফলশ্রুতিতে পরিবর্তন করেছে model_to_dict। এটি প্রতিফলিত করার জন্য আমি আমার উত্তরের 5 অনুচ্ছেদ আপডেট করেছি।
Zags
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.