ویژگی تصویر

کتابخانه marshmallow در پایتون — معرفی، کاربرد و نمونه‌های عملی

  /  پایتون   /  کتابخانه marshmallow در پایتون
بنر تبلیغاتی الف

marshmallow یک کتابخانهٔ محبوب برای سریالایز (serialize)، دی‌سریالایز (deserialize) و اعتبارسنجی (validation) داده‌ها در پایتون است. این کتابخانه به‌ویژه در ساخت APIها، تبدیل داده‌ها بین فرمت‌های مختلف (مثل dict و JSON) و اتصال داده‌ها به مدل‌های ORM کاربرد زیادی دارد.

چرا marshmallow؟

  • نوشتن اسکیماها به‌صورت کد پایتون که خوانا و قابل تست باشند.
  • ادغام ساده با فریم‌ورک‌هایی مانند Flask و با افزونه‌هایی مثل marshmallow-sqlalchemy.
  • پشتیبانی از فیلدهای مختلف، اعتبارسنجی، و هوک‌های پیش‌پردازش و پس‌پردازش.

نصب

pip install marshmallow
# برای کار با SQLAlchemy:
pip install marshmallow-sqlalchemy

نصب ساده است. اگر از ORM استفاده می‌کنید، افزونهٔ مرتبط را هم نصب کنید تا تبدیل بین مدل‌های ORM و اسکیماها راحت‌تر شود.

مفاهیم پایه

  • Schema: تعریف ساختار داده‌ها و قوانین اعتبارسنجی.
  • Fields: انواع فیلدها مثل fields.String، fields.Int، fields.DateTime و …
  • load: تبدیل ورودی (مثلاً dict) به آبجکت پایتون یا dict پردازش‌شده و اعتبارسنجی آن.
  • dump: سریالایز کردن آبجکت پایتون به dict مناسب برای JSON یا ذخیره‌سازی.

مثال ساده

from marshmallow import Schema, fields, ValidationError

class UserSchema(Schema):
    id = fields.Int(required=True)
    name = fields.Str(required=True)
    email = fields.Email()

schema = UserSchema()
input_data = {"id": 1, "name": "Ali", "email": "ali@example.com"}

# Deserialize & validate
result = schema.load(input_data)
# Serialize
json_data = schema.dump(result)

در این مثال یک اسکیما برای کاربر تعریف شده است. متد load ورودی را اعتبارسنجی می‌کند و در صورت خطا استثناء ValidationError پرتاب می‌شود. متد dump هم داده‌ها را برای ارسال به کلاینت یا ذخیره‌سازی آماده می‌کند.

دسته‌بندی خروجی و مدیریت خطا

from marshmallow import ValidationError

try:
    data = schema.load({"id": "not-a-number", "name": "Ali"})
except ValidationError as err:
    print(err.messages)  # {'id': ['Not a valid integer.']}

در صورت خطای اعتبارسنجی، پیام‌های واضحی دریافت می‌کنید که می‌توانند مستقیماً به پاسخ API اضافه شوند.

فیلدهای متداول و گزینه‌ها

  • required: تعیین اجباری بودن فیلد
  • default / missing: مقدار پیش‌فرض برای dump و load
  • validate: پذیرش تابع یا callable برای اعتبارسنجی سفارشی
  • allow_none: اجازهٔ مقدار None

Nested و لیست‌ها

class AddressSchema(Schema):
    street = fields.Str()
    city = fields.Str()

class UserSchema(Schema):
    name = fields.Str()
    addresses = fields.List(fields.Nested(AddressSchema))

user = {
    "name": "Sara",
    "addresses": [{"street": "Valiasr", "city": "Tehran"}]
}

schema = UserSchema()
print(schema.load(user))

در این مثال از Nested برای مدل‌سازی روابط یک‌به‌چند استفاده شده است. marshmallow به‌خوبی داده‌های تو در تو را پردازش و اعتبارسنجی می‌کند.

هوک‌ها: pre_load و post_load

from marshmallow import pre_load, post_load

class UserSchema(Schema):
    name = fields.Str()
    age = fields.Int()

    @pre_load
    def strip_name(self, data, **kwargs):
        if 'name' in data:
            data['name'] = data['name'].strip()
        return data

    @post_load
    def make_user(self, data, **kwargs):
        return User(**data)  # تبدیل dict به آبجکت کاربردی

هوک‌های pre_load و post_load برای تغییر یا تبدیل داده‌ها قبل یا بعد از اعتبارسنجی مناسب‌اند. در مثال بالا نام را پاک‌سازی می‌کنیم و سپس یک نمونهٔ کلاس User می‌سازیم.

سفارشی‌سازی اعتبارسنجی

from marshmallow import validates, ValidationError

class ProductSchema(Schema):
    name = fields.Str(required=True)
    price = fields.Float(required=True)

    @validates('price')
    def validate_price(self, value):
        if value <= 0:
            raise ValidationError('price must be positive')

می‌توانید اعتبارسنجی فیلد را با دکوراتور @validates انجام دهید یا از آرگومان validate هنگام تعریف فیلد استفاده کنید.

تنظیم رفتار برای فیلدهای ناشناخته

تنظیمتوضیح
unknown=RAISEارزشیابی خطا برای فیلدهای ناشناخته
unknown=EXCLUDEنادیده گرفتن فیلدهای اضافی
unknown=INCLUDEشامل کردن فیلدهای اضافه در خروجی

با تعریف Meta در اسکیما می‌توانید نحوهٔ برخورد با فیلدهای اضافه را کنترل کنید.

مثال: استفاده در Flask و SQLAlchemy

# نمونهٔ سادهٔ ادغام با Flask
from flask import Flask, request, jsonify
from marshmallow import Schema, fields, ValidationError

app = Flask(__name__)

class PostSchema(Schema):
    title = fields.Str(required=True)
    content = fields.Str()

schema = PostSchema()

@app.route('/posts', methods=['POST'])
def create_post():
    try:
        data = schema.load(request.json)
    except ValidationError as err:
        return jsonify(err.messages), 400
    # ذخیره‌سازی مدل در DB
    return jsonify(schema.dump(data)), 201

در برنامه‌های واقعی بهتر است از marshmallow-sqlalchemy برای تبدیل مستقیم مدل‌های SQLAlchemy به اسکیماها استفاده کنید تا نگهداری کد ساده‌تر شود.

نکات عملکرد و بهترین شیوه‌ها

  • برای حجم بالای داده‌ها از parameter many=True هنگام لود/دامپ استفاده کنید تا پردازش دسته‌ای بهینه باشد.
  • در صورت نیاز به سرعت بیشتر، از نسخه‌های سبک‌تر فیلدها یا تبدیل‌های دستی (در بخش‌های بحرانی) استفاده کنید.
  • پیام‌های خطا را ساختاربندی کنید تا در پاسخ‌های API قابل مصرف برای کلاینت باشند.
  • اسکیماها را کوچک و متمرکز نگه دارید؛ از ارجاع‌های Nested برای جلوگیری از تکرار استفاده کنید.

بهبود: نمونهٔ بهتر برای تبدیل به مدل SQLAlchemy

from marshmallow_sqlalchemy import SQLAlchemyAutoSchema
from models import User  # مدل SQLAlchemy

class UserAutoSchema(SQLAlchemyAutoSchema):
    class Meta:
        model = User
        load_instance = True

استفاده از کلاس‌های اتوماتیک marshmallow-sqlalchemy باعث کاهش کد و هماهنگی بهتر بین مدل و اسکیما می‌شود. گزینهٔ load_instance=True باعث می‌شود که load مستقیماً یک نمونهٔ مدل برگرداند.

خلاصه و جمع‌بندی

marshmallow ابزاری قدرتمند و منعطف برای سریالایز و اعتبارسنجی داده‌ها در پایتون است. با استفاده از اسکیماها، فیلدها، هوک‌ها و افزونه‌های مرتبط می‌توان از آن در پروژه‌های کوچک تا سیستم‌های بزرگ backend و API استفاده کرد. رعایت بهترین شیوه‌ها مانند استفاده از nested، مدیریت خطاها و یکپارچه‌سازی با ORMها تجربهٔ توسعه‌ را بهبود می‌بخشد.

در صورت نیاز می‌توان مثال‌های بیشتر مانند استفاده از marshmallow-dataclass، پردازش جریان‌های بزرگ داده، یا سفارشی‌سازی پیام‌های خطا را نیز ارائه کرد.

آیا این مطلب برای شما مفید بود ؟

خیر
بله
موضوعات شما در انجمن: