سریال‌سازی و دسریال‌سازی در Django: راهنمای کامل کار با Serialization Framework

این مقاله سیستم سریال‌سازی Django را توضیح می‌دهد؛ از نحوهٔ تبدیل مدل‌ها به JSON، XML، YAML و JSONL گرفته تا دسریال‌سازی داده‌ها، سریال‌سازی فیلدهای انتخابی، کار با مدل‌های ارث‌بری، مدیریت روابط، و نکات مهم هنگام ذخیرهٔ داده‌های دسریال‌شده.

Django serialization, Django deserializationJSON serializer, XML serializer, YAML serializer,JSONL, DeserializedObject, Django ORM

~10 دقیقه مطالعه • بروزرسانی ۲۴ اسفند ۱۴۰۴

مقدمه

فریم‌ورک سریال‌سازی Django ابزاری قدرتمند برای تبدیل مدل‌های Django به فرمت‌های مختلف داده است. این فرمت‌ها معمولاً متنی هستند—مثل JSON یا XML—و برای انتقال داده، بکاپ‌گیری یا ارتباط با سرویس‌های خارجی استفاده می‌شوند.

سریال‌سازی یعنی تبدیل یک شیء Django به دادهٔ ساخت‌یافته. دسریال‌سازی یعنی تبدیل آن داده‌ها به شیء Django.


سریال‌سازی داده‌ها

ساده‌ترین روش سریال‌سازی:


from django.core import serializers

data = serializers.serialize("json", SomeModel.objects.all())

آرگومان اول فرمت (json، xml، yaml و …) و آرگومان دوم یک QuerySet یا هر iterable از مدل‌هاست.


استفادهٔ مستقیم از Serializer

می‌توانید یک Serializer را مستقیماً دریافت و استفاده کنید:


JSONSerializer = serializers.get_serializer("json")
json_serializer = JSONSerializer()
json_serializer.serialize(queryset)
data = json_serializer.getvalue()

این روش برای نوشتن مستقیم در فایل یا stream مناسب است:


with open("file.json", "w") as out:
    json_serializer.serialize(SomeModel.objects.all(), stream=out)

اگر فرمت ناشناخته باشد، Django خطای SerializerDoesNotExist می‌دهد.


سریال‌سازی بخشی از فیلدها

می‌توانید فقط برخی فیلدها را سریال‌سازی کنید:


data = serializers.serialize(
    "json",
    SomeModel.objects.all(),
    fields=["name", "size"]
)

کلید اصلی (pk) همیشه سریال‌سازی می‌شود، حتی اگر در فهرست فیلدها نباشد.

نکته: اگر فیلدهای ضروری مدل سریال‌سازی نشده باشند، دسریال‌سازی ممکن است شکست بخورد.


سریال‌سازی مدل‌های ارث‌بری

ارث‌بری از کلاس پایهٔ abstract

در این حالت نیازی به کار خاصی نیست؛ سریال‌سازی کامل انجام می‌شود.

ارث‌بری چندجدولی (Multi‑Table)

در این حالت Django فقط فیلدهای تعریف‌شده در مدل فرزند را سریال‌سازی می‌کند. مثال:


class Place(models.Model):
    name = models.CharField(max_length=50)

class Restaurant(Place):
    serves_hot_dogs = models.BooleanField(default=False)

سریال‌سازی Restaurant فقط فیلد serves_hot_dogs را شامل می‌شود:


serializers.serialize("json", Restaurant.objects.all())

برای سریال‌سازی کامل:


all_objects = [*Restaurant.objects.all(), *Place.objects.all()]
data = serializers.serialize("json", all_objects)

دسریال‌سازی داده‌ها

دسریال‌سازی مشابه سریال‌سازی است:


for obj in serializers.deserialize("json", data):
    do_something_with(obj)

اما خروجی DeserializedObject است، نه شیء Django.

ذخیرهٔ شیء دسریال‌شده

برای ذخیره:


for deserialized in serializers.deserialize("json", data):
    deserialized.save()

اگر pk موجود نباشد یا null باشد، یک شیء جدید ساخته می‌شود.

نادیده گرفتن فیلدهای نامعتبر

اگر دادهٔ سریال‌شده شامل فیلدهای ناموجود باشد، Django خطای DeserializationError می‌دهد مگر اینکه:


serializers.deserialize("json", data, ignorenonexistent=True)

فرمت‌های سریال‌سازی

فرمتتوضیح
jsonسریال‌سازی استاندارد JSON
jsonlفرمت JSON Lines
xmlفرمت XML ساده
yamlنیازمند نصب PyYAML

نمونهٔ سریال‌سازی XML



    
        2013-01-16T08:16:59.844560+00:00
    

فیلدهای رابطه‌ای

ForeignKey:


9

ManyToMany:



    
    

کاراکترهای کنترل

XML 1.0 برخی کاراکترهای کنترل را نمی‌پذیرد. اگر دادهٔ شما شامل این کاراکترها باشد، سریال‌سازی با ValueError شکست می‌خورد.


جمع‌بندی

فریم‌ورک سریال‌سازی Django ابزاری قدرتمند برای انتقال داده، بکاپ‌گیری و یکپارچه‌سازی سیستم‌هاست. با شناخت نحوهٔ سریال‌سازی مدل‌ها، مدیریت ارث‌بری، روابط، و دسریال‌سازی امن، می‌توانید داده‌ها را به‌صورت ساخت‌یافته و قابل‌اعتماد مدیریت کنید.

سریال‌سازی JSON در Django

JSON یکی از رایج‌ترین فرمت‌ها برای تبادل داده است. Django خروجی JSON را به‌صورت ساختاریافته و استاندارد تولید می‌کند. نمونهٔ خروجی JSON برای یک مدل Session به شکل زیر است:


[
    {
        "pk": "4b678b301dfd8a4e0dad910de3ae245b",
        "model": "sessions.session",
        "fields": {
            "expire_date": "2013-01-16T08:16:59.844Z"
        }
    }
]

در JSON:

  • pk کلید اصلی است
  • model نام مدل به‌صورت app_label.model_name است
  • fields شامل فیلدهای مدل و مقدار آن‌هاست

سریال‌سازی روابط

  • ForeignKey → مقدار pk شیء مرتبط
  • ManyToMany → لیستی از pkها

سریال‌سازی انواع دادهٔ خاص (Custom Types)

اگر مدل شما شامل نوع دادهٔ سفارشی باشد، Django نمی‌تواند آن را مستقیماً به JSON تبدیل کند. در این حالت باید یک JSONEncoder سفارشی بسازید:


from django.core.serializers.json import DjangoJSONEncoder

class LazyEncoder(DjangoJSONEncoder):
    def default(self, obj):
        if isinstance(obj, YourCustomType):
            return str(obj)
        return super().default(obj)

و سپس:


from django.core.serializers import serialize

serialize("json", SomeModel.objects.all(), cls=LazyEncoder)

GeoDjango نیز یک GeoJSON Serializer اختصاصی ارائه می‌دهد.


DjangoJSONEncoder

DjangoJSONEncoder یک نسخهٔ توسعه‌یافته از JSONEncoder است که انواع زیر را پشتیبانی می‌کند:

  • datetime → فرمت استاندارد ECMA-262
  • date → YYYY-MM-DD
  • time → HH:MM:ss.sss
  • timedelta → فرمت ISO-8601
  • Decimal، UUID، Promise → تبدیل به رشته

سریال‌سازی JSONL

JSONL یا JSON Lines برای داده‌های حجیم بسیار مناسب است. در این فرمت هر خط یک JSON مستقل است:


{"pk": "...", "model": "sessions.session", "fields": {...}}
{"pk": "...", "model": "sessions.session", "fields": {...}}
{"pk": "...", "model": "sessions.session", "fields": {...}}

مزیت اصلی JSONL این است که می‌توان داده‌ها را خط‌به‌خط پردازش کرد بدون اینکه کل فایل در حافظه بارگذاری شود.


سریال‌سازی YAML

YAML شباهت زیادی به JSON دارد اما خوانایی بیشتری دارد. برای استفاده از YAML باید PyYAML نصب باشد.


- model: sessions.session
  pk: 4b678b301dfd8a4e0dad910de3ae245b
  fields:
    expire_date: 2013-01-16 08:16:59.844560+00:00

روابط نیز مانند JSON با pk یا لیست pkها نمایش داده می‌شوند.


ساخت Serializer سفارشی (مثال: CSV)

Django اجازه می‌دهد فرمت‌های سریال‌سازی سفارشی بسازید. در این مثال یک Serializer و Deserializer برای CSV تعریف می‌کنیم.

Serializer سفارشی


# path/to/custom_csv_serializer.py

import csv
from django.apps import apps
from django.core import serializers
from django.core.serializers.base import DeserializationError

class Serializer(serializers.python.Serializer):
    def get_dump_object(self, obj):
        dumped = super().get_dump_object(obj)
        row = [dumped["model"], str(dumped["pk"])]
        row += [str(value) for value in dumped["fields"].values()]
        return ",".join(row), dumped["model"]

    def end_object(self, obj):
        dumped_str, model = self.get_dump_object(obj)
        if self.first:
            fields = [f.name for f in apps.get_model(model)._meta.fields]
            header = ",".join(fields)
            self.stream.write(f"model,{header}\n")
        self.stream.write(f"{dumped_str}\n")

Deserializer سفارشی


class Deserializer(serializers.python.Deserializer):
    def __init__(self, stream_or_string, **options):
        if isinstance(stream_or_string, bytes):
            stream_or_string = stream_or_string.decode()
        if isinstance(stream_or_string, str):
            stream_or_string = stream_or_string.splitlines()
        try:
            objects = csv.DictReader(stream_or_string)
        except Exception as exc:
            raise DeserializationError() from exc
        super().__init__(objects, **options)

    def _handle_object(self, obj):
        try:
            model_fields = apps.get_model(obj["model"])._meta.fields
            obj["fields"] = {
                field.name: obj[field.name]
                for field in model_fields
                if field.name in obj
            }
            yield from super()._handle_object(obj)
        except Exception as exc:
            raise DeserializationError(f"Error deserializing object: {exc}") from exc

افزودن فرمت به تنظیمات Django


SERIALIZATION_MODULES = {
    "csv": "path.to.custom_csv_serializer",
    "json": "django.core.serializers.json",
}

جمع‌بندی

Django ابزارهای قدرتمندی برای سریال‌سازی داده‌ها ارائه می‌دهد—از JSON و XML گرفته تا JSONL و YAML. با استفاده از DjangoJSONEncoder می‌توان انواع دادهٔ پیچیده را مدیریت کرد. همچنین امکان ساخت Serializerهای سفارشی مانند CSV وجود دارد که برای یکپارچه‌سازی سیستم‌ها یا خروجی‌گیری داده بسیار مفید است.

Natural Keys چیست؟

به‌طور پیش‌فرض، Django هنگام سریال‌سازی روابط ForeignKey و ManyToMany از مقدار Primary Key استفاده می‌کند. این روش معمولاً مناسب است، اما در برخی موارد مشکل‌ساز می‌شود—به‌خصوص زمانی که مدل‌هایی مانند ContentType، User، Group یا Permission درگیر باشند که PK آن‌ها قابل پیش‌بینی نیست.

برای حل این مشکل، Django قابلیتی به نام Natural Keys ارائه می‌دهد. Natural Key یک تاپل از فیلدها است که بدون نیاز به PK می‌تواند یک شیء را به‌طور یکتا شناسایی کند.


چرا Natural Keys مهم هستند؟

  • وابسته نبودن به PKهای غیرقابل پیش‌بینی
  • خوانایی بهتر داده‌های سریال‌شده
  • قابل‌حمل بودن داده‌ها بین محیط‌های مختلف
  • جلوگیری از خطاهای IntegrityError هنگام بارگذاری fixtureها

هشدار: هرگز اشیاء تولیدشدهٔ خودکار (مثل Permission یا ContentType) را در fixture قرار ندهید.


دسریال‌سازی Natural Keys

برای استفاده از Natural Key در دسریال‌سازی، باید یک Manager سفارشی با متد get_by_natural_key() تعریف کنید.

مثال:


class PersonManager(models.Manager):
    def get_by_natural_key(self, first_name, last_name):
        return self.get(first_name=first_name, last_name=last_name)

سپس مدل را به این Manager مجهز می‌کنیم:


class Person(models.Model):
    first_name = models.CharField(max_length=100)
    last_name = models.CharField(max_length=100)
    birthdate = models.DateField()

    objects = PersonManager()

    class Meta:
        constraints = [
            models.UniqueConstraint(
                fields=["first_name", "last_name"],
                name="unique_first_last_name",
            ),
        ]

حالا Book می‌تواند نویسنده را با Natural Key ارجاع دهد:


{
    "pk": 1,
    "model": "store.book",
    "fields": {
        "name": "Mostly Harmless",
        "author": ["Douglas", "Adams"]
    }
}

Django هنگام دسریال‌سازی، مقدار ["Douglas", "Adams"] را به کمک get_by_natural_key() به یک Person واقعی تبدیل می‌کند.


سریال‌سازی Natural Keys

برای اینکه Django هنگام سریال‌سازی از Natural Key استفاده کند، باید متد natural_key() را در مدل تعریف کنید:


def natural_key(self):
    return (self.first_name, self.last_name)

سپس هنگام سریال‌سازی:


serializers.serialize(
    "json",
    [book1, book2],
    use_natural_foreign_keys=True,
    use_natural_primary_keys=True
)

تفاوت دو گزینه:

  • use_natural_foreign_keys=True → روابط FK با Natural Key سریال می‌شوند
  • use_natural_primary_keys=True → خود شیء بدون PK سریال می‌شود

این کار زمانی مفید است که PK در دیتابیس مقصد ممکن است متفاوت باشد.


Natural Keys و Forward References

گاهی یک شیء به شیء دیگری ارجاع می‌دهد که هنوز دسریال نشده است. این حالت را forward reference می‌نامند.

برای مدیریت آن:


objs_with_deferred_fields = []

for obj in serializers.deserialize("json", data, handle_forward_references=True):
    obj.save()
    if obj.deferred_fields is not None:
        objs_with_deferred_fields.append(obj)

for obj in objs_with_deferred_fields:
    obj.save_deferred_fields()

نکته: فیلد FK باید null=True باشد.


کنترل ترتیب سریال‌سازی با Dependencies

اگر Natural Key یک مدل به مدل دیگری وابسته باشد، باید ترتیب سریال‌سازی را مشخص کنید.

مثال:


def natural_key(self):
    return (self.name,) + self.author.natural_key()

natural_key.dependencies = ["example_app.person"]

این کار تضمین می‌کند که Person قبل از Book سریال شود.


جمع‌بندی

Natural Keys در Django راهی قدرتمند برای سریال‌سازی داده‌ها بدون وابستگی به Primary Key هستند. با تعریف natural_key() و get_by_natural_key() می‌توانید داده‌هایی قابل‌حمل، خوانا و مستقل از PK تولید کنید. همچنین با مدیریت forward references و dependencies می‌توانید سریال‌سازی پیچیده را نیز کنترل کنید.

نوشته و پژوهش شده توسط دکتر شاهین صیامی