ادامه آموزش فریم ورک جنگو – مدل ها

ادامه آموزش فریم ورک جنگو – مدل ها

کد محصول: مدل ها
وضعیت انبار: در انبار

همانطور که پیش تر در این فصل توضیح داده شد، "M" در "MTV" مخفف "Model" می باشد. model جنگو توصیف و شرح داده در پایگاه داده ی شما می باشد، که به صورت کد پایتون نمایش داده می شود.

آموزش فریم ورک جنگو - مقدمه  

آموزش فریم ورک جنگو – فرم هاآموزش فریم ورک جنگو – Session ها ، کاربران و عضویت

آموزش فریم ورک جنگو – شروع کار

آموزش فریم ورک جنگو –  View ها و UrlConf های پیشرفته آموزش فریم ورک جنگو – مبحث Caching  

آموزش فریم ورک جنگو – View ها و UrlConf ها    

آموزش فریم ورک جنگو – Template های پیشرفته  آموزش فریم ورک جنگو – پکیج Django.contrib

آموزش فریم ورک جنگو – Template ها  

آموزش فریم ورک جنگو – مدل های پیشرفتهآموزش فریم ورک جنگو – مبحث Middleware

آموزش فریم ورک جنگو – مدل ها 

آموزش فریم ورک جنگو – Viewهای Generic  آموزش فریم ورک جنگو – یکپارچه سازی برنامه ها و دیتابیس Legacy  

آموزش فریم ورک جنگو – سایت مدیر 

آموزش فریم ورک جنگو – تولید محتوای غیر Html ی    آموزش فریم ورک جنگو – بین المللی سازی   


آموزش فریم ورک جنگو – امنیت

 

ادامه آموزش فریم ورک جنگو – مدل ها

در ادامه دوره ی آموزش فریم ورک جنگو – مدل ها قصد داریم تا مدل ها را بررسی و آموزش دهیم.پس با رولیکا همراه باشید تا مدل را از نظر بگذرانیم.

   تعریف Model ها در پایتون

همانطور که پیش تر در این فصل توضیح داده شد، "M" در "MTV" مخفف "Model" می باشد. model جنگو توصیف و شرح داده در پایگاه داده ی شما می باشد، که به صورت کد پایتون نمایش داده می شود. model لایه ی داده ی شما می باشد معادل عبارات SQL مانند CREATE TABLE با این تفاوت که این عبارات بجای SQL درون پایتون می باشند و همچنین آن ها شامل مواردی بیشتر از تعریف ستون های پایگاه داده می باشند. جنگو برای اجرای کد های SQL در پشت صحنه و برگرداندن ساختارهای داده ی پایتون مناسب از model ها استفاده می کند که از طریق آن ها ردیف های جداول پایگاه داده را نمایش می دهد. جنگو همچنین از model ها برای نمایش مفاهیم سطح بالا که SQL لزوما قادر به کنترل آن ها نمی باشد نیز استفاده می شود.

در صورتیکه با پایگاه های داده آشنا می باشید، این تفکر برای شما ایجاد می شود که "آیا تعریف کردن data model ها بجای SQL درون پایتون کار زائد و اضافه ای نیست؟" جنگو به چندین دلیل به این روش عمل می کند:

  • درون گرایی (استفاده از کد های SQL) مستلزم بار اضافی بوده و همچنین ناقص می باشد. به منظور تهیه ی API ها برای دسترسی به داده، جنگو به طریقی نیاز به شناختن لایه ی پایگاه داده دارد، و دو روش برای انجام آن وجود دارد. روش اول به طور واضح توضیح دادن داده در پایتون می باشد، و روش دوم تعیین data model ها درون پایگاه داده در هنگام اجرا می باشد.

    روش دوم تمیز تر به نظر می رسد، زیرا داده های جداول شما در یک جا می باشند، ولی این روش دارای مشکلاتی می باشد. اول اینکه تعیین داده های درون پایگاه داده در زمان اجرا بدیهی است که نیازمند یک بار اضافه خواهد بود. در صورتیکه فریم ورک در هر زمان بخواهد درون پایگاه داده اعمالی را انجام دهد خود به خود یک درخواست را پردازش کرده است، و یا حتی، در زمان اولیه وب سرور ممکن است یک بار اضافی در سطح غیر قابل قبول را متحمل شود. دوم آنکه برخی از پایگاه های داده، به ویژه نسخه های قدیمی MySQL، metadata مناسبی را به طور دقیق ذخیره نمی کنند.

  • کد نویسی در پایتون لذت بخش می باشد، و نگه داشتن همه چیز در محدوده ی کد پایتون باعث می شود تعداد باری که شما را مجبور کند محیط کد نویسی را تغییر دهد کم می کند. این موضوع یعنی نگه داشتن برنامه نویس در یک محیط کد نویسی بهره وری و راندمان را تا حد امکان افزایش می دهد. نوشتن کد SQL و سپس پایتون و دوباره SQL کاری ذهنیت برنامه نویس را مختل خواهد کرد.
  • داشتن data model های ذخیره شده به صورت کد بجای استفاده مستقیم از پایگاه داده، کنترل model هار بسیار آسان تر خواهد کرد. با این روش می توان به سادگی رد تغییرات در لایه های داده را دنبال کرد.
  • SQL تنها اجازه ی استفاده از داده های قطعی موجود می دهد، اغلب سیستم های پایگاه داده، به عنوان مثال؛ داده های تخصصی برای نمایش دادن آدرس های email یا URL را تهیه نمی کنند. در صورتیکه model های جنگو این کار را انجام می دهند. مزیت داده های نوع سطح بالا بهره وری بیشتر آن ها و قابلیت دوباره استفاده شدن آن ها می باشد.
  • SQL در پایگاه های داده ی مختلف یکجور نبوده و ناسازگار می باشد. بدین معنی که جملات و عبارت SQL برای مثال join ها و یا ... در پایگاه های داده ی مختلف مانند MySQL، PostgreSQL و یا SQLite ممکن است متفاوت از یکدیگر پیاده سازی شوند و هرکدام به روش خود آن را پیاده سازی کنند.

تنها ایراد در این روش (استفاده از data model پایتون) این است که کدهای پایتون حالت همزمانی و موازات را به طور واقعی با پایگاه داده ندارند. در صورتیکه در model جنگو تغییر ایجاد کنید، نیاز می باشد که همان تغییرات را نیز درون پایگاه داده انجام دهید تا پایگاه داده با model شما سازگاری خود را حفظ کند. در ادامه ی این فصل استراتژی هایی توضیح داده خواهد شد که از طریق آن ها خواهید توانست این مشکلات را کنترل کنید.

   اولین Model شما

برای داشتن مثالی که هم در این فصل و فصل بعدی بتوان از آن استفاده کرد و آن را پیشرفت داد، بر روی لایه ی داده ی book/author/publisher تمرکز خواهد شد. از این مثال به دلیل اینکه دارای رابطه های شناخته شده ای بین books، authors و publishers می باشد، و داده های استفاده شده داده های مقدماتی استفاده شده در SQL می باشد.

داده های استفاده شده با خصوصیات زیر فرض شده اند:

  • یک نویسنده دارای یک نام، یک فامیلی و یک نشانی پست الکترونیک می باشد.
  • یک ناشر دارای یک نام، یک نشانی کوچه، یک شهر، یک استان، یک کشور و یک وب سایت می باشد.
  • یک کتاب دارای یک عنوان و یک تاریخ انتشار می باشد. همچنین هر کتاب دارای یک یا بیشتر نویسنده (رابطه ی چند به چند با authors) و یک ناشر (رابطه ی یک به چند به publishers) می باشد.

اولین قدم برای استفاده کردن لایه ی پایگاه داده با جنگو، بیان آن به صورت کد پایتون می باشد. درون فایل models.py که با استفاده از دستور startapp ساخته شده است، کد زیر را وارد کنید:

from django.db import models

class Publisher(models.Model):
    name = models.CharField(max_length=30)
    address = models.CharField(max_length=50)
    city = models.CharField(max_length=60)
    state_province = models.CharField(max_length=30)
    country = models.CharField(max_length=50)
    website = models.URLField()

class Author(models.Model):
    first_name = models.CharField(max_length=30)
    last_name = models.CharField(max_length=40)
    email = models.EmailField()

class Book(models.Model):
    title = models.CharField(max_length=100)
    authors = models.ManyToManyField(Author)
    publisher = models.ForeignKey(Publisher)
    publication_date = models.DateField()

اجازه دهید کد فوق را به طور اجمالی مورد بررسی قرار دهیم. اولین نکته ی قابل توجه این است که هر model به صورت یک کلاس پایتون نمایش داده شده است و هر model کلاس فرزند از کلاس پدر django.db.models.Model می باشد. کلاس پدر Model، حاوی تمام ابزار آلات ضروری برای ساختن شیء هایی می باشد که توانایی تعامل با یک پایگاه داده را داشته باشند. مشاهده می کنید که تعریف فیلدها به چه اندازه مختصر و ساده می باشند. باور کنید یا نه، این تمام کدی می باشد که برای داشتن دسترسی داده ی اولیه با جنگو لازم است.

هر model عموما با یک جدول پایگاه داده و هر attribute در یک model با یک ستون جدول در پایگاه داده مطابق می باشد، نام attribute مطابق با نام ستون، و نوع فیلد (مانند CharField) مطابق با نوع ستون (مانند varchar) می باشد. برای مثال مدل Publisher برابر با جدول زیر می باشد (با فرض عبارت CREATE TABLE درون پایگاه داده ی PostgreSQL):

CREATE TABLE "books_publisher" (
    "id" serial NOT NULL PRIMARY KEY,
    "name" varchar(30) NOT NULL,
    "address" varchar(50) NOT NULL,
    "city" varchar(60) NOT NULL,
    "state_province" varchar(30) NOT NULL,
    "country" varchar(50) NOT NULL,
    "website" varchar(200) NOT NULL
);

در واقع، جنگو می تواند عبارت CREATE TABLE را به صورت خودکار تولید کند که در کد فوق مشاهده کردید.

در این قانون که برای هر جدول پایگاه داده، یک کلاس در نظر گرفته می شود، در مورد رابطه های چند به چند یک استثنا وجود دارد. در مثال مدل های فوق، Book دارای یک فیلد چند به چند با نام authors می باشد. این فیلد مشخص می کند که هر کتاب دارای یک یا چند نویسنده می باشد، در صورتیکه جدول پایگاه داده Book دارای ستونی به نام authors نمی باشد. در عوض، جنگو یک جدول اضافه می سازد (یک "join table" چند به چند) که رابطه بین کتاب ها و نویسندگان را کنترل می کند.

در پایان، توجه داشته باشید که به طور صریح برای هر یک از مدل ها یک کلید اصلی (primary key) تعریف نشده است. جنگو به صورت خودکار برای هر مدل یک فیلد auto_incremen integer primary key ایجاد می کند که id نام دارد. هر مدل جنگو لازم است یک ستون primary key داشته باشد.

   نصب کردن Model

کد مربوط به مدل ها نوشته شد، حالا اجازه دهید جدول ها را درون پایگاه داده نیز ایجاد کنیم. به منظور انجام این کار؛ قدم اول این است که مدل های ساخته شده درون پروژه جنگو را فعال کنیم. برای انجام این کار باید app مورد نظر یعنی books را به لیست "installed apps" درون فایل settings اضافه کنیم.

فایل settings.py را دوباره باز کرده، و تنظیم INSTALLED_APPS را پیدا کنید. INSTALLED_APPS به جنگو می گوید که کدام app ها برای پروژه مورد نظر فعال هستند. به طور پیشفرض، این تنظیم به این شکل خواهد بود:

INSTALLED_APPS = (
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.sites',
)

به طور موفت با گذاشتن علامت (#) در ابتدای هر کدام از رشته ها آن ها را کامنت کنید. (این رشته ها موارد کامنت شده ای برای راحتی کار می باشند که در فصل های بعدی آن ها را فعال کرده و در مورد آن ها بحث خواهیم کرد.) همچنین تنظیمات مربوط به MIDDLEWARE_CLASSES را نیز کامنت کنید؛ مقادیر پیشفرض در MIDDLEWARE_CLASSES به برخی از app هایی که ما آن ها را کامنت کردیم وابسته می باشند. سپس 'mysite.books'را به لیست INSTALLED_APPS اضافه کنید، در پایان تنظیم انجام داده شده چیزی شبیه به مثال زیر خواهد بود:

MIDDLEWARE_CLASSES = (
    # 'django.middleware.common.CommonMiddleware',
    # 'django.contrib.sessions.middleware.SessionMiddleware',
    # 'django.contrib.auth.middleware.AuthenticationMiddleware',
)

INSTALLED_APPS = (
    # 'django.contrib.auth',
    # 'django.contrib.contenttypes',
    # 'django.contrib.sessions',
    # 'django.contrib.sites',
    'mysite.books',
)

(همانطور که در فصل گذشته، هنگام تنظیم TEMPLATE_DIRS گفته شد، لازم است حتما یک علمت کاما (,) در انتهای mysite.books قرار دهید، زیرا mysite.books در اینجا یک تک المان تاپل پایتون می باشد، اتفاقا، نویسندگان این کتاب ترجیح می دهند بعد از هر المان تاپل، بدون در نظر گرفتن این که یک تک المان است یا خیر، یک کاما در انتهای آن قرار میدهند. این کار باعث می شود از فراموش کردن قرار دادن کاما در انتهای المان های تک تاپل جلوگیری شود، و گذاشتن کامای اضافه هیچ مشکلی به وجود نخواهد آورد.)

'mysite.books' به app ای که با کار می کنیم اشاره می کند. هر app ای که در تنظیم INSTALLED_APPS قرار دارد با آدرس کامل پایتون آن نمایش داده می شود (مسیر پکیج ها با نقطه جدا شده و به پکیج app هدایت می شوند.)

اکنون که app مورد نظر در فایل settings فعال شد، می توانیم جداول پایگاه داده را درون پایگاه داده ایجاد کنیم. ابتدا، اجازه دهید با دستور زیر از معتبر بودن کد های برنامه اطمینان حاصل کنیم:

python manage.py validate

دستور validate بررسی می کند که ایا کدها و منطق مدل های نوشته صحیح می باشد یا خیر. در صورتیکه همه چیز درست باشد، شما پیام message 0 errors found را مشاهده خواهید کرد. در غیر اینصورت، اطمینان حاصل کنید کدهای مدل شما صحیح می باشد. خطای خروجی، اطلاعات مفیدی درباره ی ایراد موجود در کد، در اختیار شما می گذارد.

هر زمان که تصور کردید مشکلاتی درون مدل ها وجود دارد، دستور python manage validate را اجرا کنید. دستور فوق به شما کمک می کند تا تمام مشکلات موجود در مدل را بر طرف کنید.

در صورتیکه کد مربوط به مدل شما معتبر می باشد، دستور زیر را برای تولید عبارت های CREATE TABE مربوط به مدل ها در app مورد نظر (books) وارد کنید:

python manage.py sqlall books

در دستور فوق، books نام app می باشد. این نام همان چیزی است که شما با اجرای دستور manage.py startapp ایجاد کرده اید. هنگامی که شما دستور فوق manage.py sqlall books را اجرا می کنید چیزی شبیه به این را در خروجی مشاهده خواهید کرد:

BEGIN;
CREATE TABLE "books_publisher" (
    "id" serial NOT NULL PRIMARY KEY,
    "name" varchar(30) NOT NULL,
    "address" varchar(50) NOT NULL,
    "city" varchar(60) NOT NULL,
    "state_province" varchar(30) NOT NULL,
    "country" varchar(50) NOT NULL,
    "website" varchar(200) NOT NULL
)
;
CREATE TABLE "books_author" (
    "id" serial NOT NULL PRIMARY KEY,
    "first_name" varchar(30) NOT NULL,
    "last_name" varchar(40) NOT NULL,
    "email" varchar(75) NOT NULL
)
;
CREATE TABLE "books_book" (
    "id" serial NOT NULL PRIMARY KEY,
    "title" varchar(100) NOT NULL,
    "publisher_id" integer NOT NULL REFERENCES "books_publisher" ("id") DEFERRABLE INITIALLY DEFERRED,
    "publication_date" date NOT NULL
)
;
CREATE TABLE "books_book_authors" (
    "id" serial NOT NULL PRIMARY KEY,
    "book_id" integer NOT NULL REFERENCES "books_book" ("id") DEFERRABLE INITIALLY DEFERRED,
    "author_id" integer NOT NULL REFERENCES "books_author" ("id") DEFERRABLE INITIALLY DEFERRED,
    UNIQUE ("book_id", "author_id")
)
;
CREATE INDEX "books_book_publisher_id" ON "books_book" ("publisher_id");
COMMIT;

به نکات زیر توجه کنید:

  • نام جدول ها به طور خودکار با ترکیب نام app (books) و نام مدل (publisher، book و author) به صورت حروف کوچک تولید می شود.
  • همانطور که پیش تر توضیح داده شد، جنگو برای هر جدول به طور خودکار یک کلید اصلی (با نام id) اضافه می کند.
  • رابطه ی کلید خارجی با عبارت REFERENCES، صریح و روشن ساخته شده است.
  • عبارت CREATE TABLE برای پایگاه داده ای که شما استفاده می کنید مناسب خواهد بود، بنابراین تعیین نوع فیلد مانند auto_increment (MySQL)، serial (PostgreSQL)، یا integer primary key (SQLite) به طور خودکار توسط جنگو انجام خواهد شد. همچنین در مورد کتیشن برای نام ستون ها (مانند استفاده از دابل کتیشن یا تک کتیشن) نیز این موضوع صدق می کند. مثال فوق خروجی برای PostgreSQL می باشد.

دستور sqlall، در حقیقت جداول پایگاه داده را تولید نمی کند و به عبارت دیگر پایگاه داده نیز لمس نمی کند، تنها خروجی تولید شده توسط جنگو را به زبان SQL مورد نظر نشان می دهد بنابراین شما می توانید آنچه را که جنگو درون پایگاه داده می خواهد اجرا کند را مشاهده کنید. در صورت تمایل، می توانید این خروجی SQL را درون پایگاه داده ی کلاینت کپی کنید، یا با استفاده از علامت (|) یونیکس آن را به صورت مستقیم ارسال کنید (مانند python manage.py sqlall books | psql mydb). با این وجود، جنگو روشی ساده را برای ارسال خروجی تولید شده به پایگاه داده ارائه کرده است: دستور syncdb:

python manage.py syncdb

بعد از اجرای دستور فوق، خروجی شبیه به مثال زیر مشاهده خواهید کرد:

Creating table books_publisher
Creating table books_author
Creating table books_book
Installing index for books.Book model

دستور syncdb یک هماهنگی ساده بین مدل ها و پایگاه داده می باشد. دستور فوق تمام مدل های موجود در هر app را درون تنظیم INSTALLED_APPS بررسی می کند، و در صورتیکه جدول مناسب برای مدل های مورد نظر وجود نداشته باشد آن ها را ایجاد می کند. توجه داشته باشید که syncdb تغییرات بوجود آمده در مدل ها و یا حذف مدل ها را با پایگاه داده هماهنگ نمی کند؛ در صورتیکه شما یک تغییر را در مدل ایجاد کرده و یا مدلی را حذف کنید، هنگامی که بخواهید پایگاه داده را با این تغییرات به روز رسانی کنید، دستور syncdb نمی تواند این کار را انجام دهد. (در انتهای همین فصل این موضوع بحث خواهد شد.)

در صورتیکه که دستور python manage.py syncdb را دوباره اجرا کنید، اتفاقی رخ نخواهد داد، زیرا هیچ مدل به app مورد نظر (books) اضافه نشده است و یا هیچ app ای به تنظیم INSTALLED_APPS اضافه نشده است. بنابراین اجرای دستور python manage.py syncdb همواره مشکلی بوجود نخواهد آورد.

در صورتیکه کنجکاو هستید، می توانید برای لحظاتی به درون خط فرمان پایگاه داده رفته جداول ایجاد شده درون پایگاه داده ی خود را مشاهده کنید. می توانید به صورت دستی دستوراتی را که می خوهید درون خط فرمان کلاینت اجرا کنید (مانند psql برای PostrgreSQL) یا اینکه می توانید دستور python manage.py dbshell، را اجرا کنید، و بسته به تنظیم DATABASE_SERVER، خواهید فهمید کدام خط فرمان اجرا می شود. شیوه ی دوم تقریبا همیشه مناسب تر می باشد.

قبلی

نظر بدهید

توجه: HTML ترجمه نمی شود!

امتیاز بد           خوب

اصول اولیه ی دسترسی به داده

هنگامی که شما یک مدل ساخته می شود، جنگو به طور خودکار یک API سطح بالا پایتون را برای کار با آن مدل ها ایجاد می کند. دستور python manage.py shell را اجرا کرده و کدهای زیر را امتحان کنید:

>>> from books.models import Publisher
>>> p1 = Publisher(name='Apress', address='2855 Telegraph Avenue',
...     city='Berkeley', state_province='CA', country='U.S.A.',
...     website='http://www.apress.com/')
>>> p1.save()
>>> p2 = Publisher(name="O'Reilly", address='10 Fawcett St.',
...     city='Cambridge', state_province='MA', country='U.S.A.',
...     website='http://www.oreilly.com/')
>>> p2.save()
>>> publisher_list = Publisher.objects.all()
>>> publisher_list
[<Publisher: Publisher object>, <Publisher: Publisher object>]

چند خط کد فوق کار زیادی را انجام می دهند. نکات برجسته در کد فوق:

  • ابتدا، مدل Publisher به import شده است. با این کار می توان با جدول پایگاه داده که حاوی اطلاعات ناشران می باشد در ارتباط بود.
  • یک شیء Publisher با مقدار دهی مقدار دهی اولیه ی آن با مقادیری برای هر فیلد (name، address و غیره ...) ساخته شده است.
  • برای ذخیره ی شیء درون پایگاه داده، متد save() آن فراخوانی شده است. در پشت صحنه، جنگو عبارت INSERT برای SQL را در اینجا اجرا می کند.
  • برای بازیابی اطلاعات ناشران از پایگاه داده، از attribute مورد نظر Publisher.objects برای بدست آوردن مجموعه تمام ناشران استفاده شده است. لیست تمام شیء های Publisher با استفاده از عبارت Publisher.objects.all() واکشی شده است. در پشت صحنه جنگو یک عبارت SELECT را به صورت SQL در اینجا اجرا می کند.

نکته ای با اهمیتی که در این مورد واضح و یا روشن به نظر نمی رسد اینکه، هنگامی که شما با استفاده از API مدل جنگو در حال ساختن شیء ها می باشید، جنگو تا وقتی که متد save() را فراخوانی نکنید شیء ها را درون پایگاه داده ذخیره نمی کند.

p1 = Publisher(...)
# At this point, p1 is not saved to the database yet!
p1.save()
# Now it is.

در صورتیکه می خواهید یک شیء ساخته و آن را درون پایگاه داده با یک حرکت ذخیره کنید، می توانید از متد objects.create() استفاده کنید. مثال زیر با مثال قبلی برابر است:

>>> p1 = Publisher.objects.create(name='Apress',
...     address='2855 Telegraph Avenue',
...     city='Berkeley', state_province='CA', country='U.S.A.',
...     website='http://www.apress.com/')
>>> p2 = Publisher.objects.create(name="O'Reilly",
...     address='10 Fawcett St.', city='Cambridge',
...     state_province='MA', country='U.S.A.',
...     website='http://www.oreilly.com/')
>>> publisher_list = Publisher.objects.all()
>>> publisher_list

به طور طبیعی می توانید کارهای بسیار زیادی را به استفاده از API پایگاه داده ی جنگو انجام دهید، اما در ابتدا با کارهای کوچک بسنده می کنیم.

‫اضافه كردن نمايش رشته اي براي مدل‬

هنگامی که لیستی از ناشران را چاپ می کنیم، خروجی مفیدی نمایش داده نمی شود و بخش های شیء به هیچ وجه قابل تشخیص نیستند:

[<Publisher: Publisher object>, <Publisher: Publisher object>]

می توان این مشکل را به راحتی با اضافه کردن متد __unicode__() به کلاس Publisher حل کرد. متد __unicode__() به پایتون می گوید که یک شیء را به چه شکل در خروجی نمایش دهد. می توانید نحوه ی استفاده از آن را در عمل با اضافه کردن یک متد __unicode__() درون سه مدل فوق مشاهده کنید:

from django.db import models

class Publisher(models.Model):
    name = models.CharField(max_length=30)
    address = models.CharField(max_length=50)
    city = models.CharField(max_length=60)
    state_province = models.CharField(max_length=30)
    country = models.CharField(max_length=50)
    website = models.URLField()

    def __unicode__(self):
        return self.name

class Author(models.Model):
    first_name = models.CharField(max_length=30)
    last_name = models.CharField(max_length=40)
    email = models.EmailField()

    def __unicode__(self):
        return u'%s %s' % (self.first_name, self.last_name)

class Book(models.Model):
    title = models.CharField(max_length=100)
    authors = models.ManyToManyField(Author)
    publisher = models.ForeignKey(Publisher)
    publication_date = models.DateField()

    def __unicode__(self):
        return self.title

همانطور که مشاهده می کنید، متد __unicode__() می تواند هر آنچه را که برای برای نمایش یک شیء نیاز است انجام دهید. در مثال فوق متدهای __unicode__() برای Publisher و Book به سادگی نام و عنوان شیء را به ترتیب برمی گردانند، ولی متد __unicode__() برای Author کمی پیچیده تر از بقیه می باشد، بدین صورت که فیلد های first_name و last_name را به یک فاصله به هم وصل کرده و بر می گرداند.

تنها الزام برای متد __unicode__() این است که یک شیء یونیکد را بر می گرداند. در صورتیکه متد __unicode__() یک شیء یونیکد را بر نگرداند به عنوان مثال یک integer بر گرداند، در اینصورت پایتون خطای TypeError را با پیامی مانند "coercing to Unicode: need string or buffer, int found"ایجاد خواهد کرد.

یادداشت

‫آبجكت هاي يونيكد‬

شیء یونیکد چیست؟

می توانید بدین شکل تصور کنید که شیء یونیکد یک رشته ی پایتون است که می تواند با بیشتر از یک میلیون نوع محتلف حروف را کار کرده و آن ها را کنترل کند، از نسخه های حروف لهجه دار لاتین، حروف غیر لاتین گرفته تا نمادها و علامت های مبهم و نا مفهوم.

رشته های معمولی پایتون رمزی شده (encoded) می باشند، بدین معنی که آن ها به صورت رمز شده مانند ASCII، ISO-8859-1 یا UTF-8 استفاده می شوند. در صورتیکه بخواهید حروف تجملی (هرچیزی خارج از 128 حرف ASCII مانند 0-9 و A-Z) را درون یک رشته ی معمولی پایتون ذخیره کنید، این حروف هنگام چاپ و یا نمایش به صورت به هم ریخته در می ایند. مشکلات زمانی رخ می دهند که شما داده ای را درون یک encoding ذخیره کرده و سعی می کنید آن را با یک encoding متفاوت دیگر ترکیب کنید و یا سعی می کنید آن را درون یک برنامه که دارای یک encoding مشخص می باشد نمایش دهید. همه ی ما صفحات وب و پست الکترونیکی را مشاهده کرده ایم که با حالت "??? ??????" و یا دیگر حروف خراب شده اند؛ این مشکلات عموما مشکلات encoding تلقی می شوند.

شیء های یونیکد، اگر چه encoding ندارند؛ ولی آن ها از یک مجموعه از حروف جهانی و سازگار که "Unicode" نامیده می شوند استفاده می کنند. هنگامی که شما با شیء های یونیکد در پایتون سر و کار دارید، می توانید بدون هیچگونه نگرانی نسبت به مسائل encoding آن ها را با یکدیگر ترکیب و استفاده کنید.

جنگو در سرتاسر فریم ورک از شیء های یونیکد استفاده می کند. شیء های مدل به صورت شیء های یونیکد بازیابی شده اند، view ها با داده ی یونیکد ارتباط برقرار می کنند و template ها به صورت یونیکد ارائه می شوند. عموما، توسعه دهندگان درون فریم ورک جنگو هیچگونه نگرانی نسبت به درست بودن encoding درون برنامه های نوشته شده توسط جنگو نخواهند داشت.

توجه داشته باشید که سطح بالا بودن مطالب در اینجا باعث می شود که اطلاعات شما در مورد شیء های یونیکد کمی گمگ و مبهم باشد، در صورتیکه می خواهید می توانید در نشانی زیر مورد آن اطلاعات بیشتری کسب کنید.

http://www.joelonsoftware.com/articles/Unicode.html

برای اینکه تغییرات ایجاد شده درون مدل ها (اضافه کردن متد __unicode__()) اعمال شود، از shell پایتون خارج شده و با دستور python manage.py shell دوباره وارد آن شوید. (این ساده ترین راه برای اعمال تغییرات ایجاد شده می باشد) حالا لیست شیء های Publisher قابل فهم تر شده اند:

>>> from books.models import Publisher
>>> publisher_list = Publisher.objects.all()
>>> publisher_list
[<Publisher: Apress>, <Publisher: O'Reilly>]

اطمینان حاصل کنید که تمام مدل های تعریف شده دارای متد __unicode__() می باشند، نه فقط برای راحتی خودتان هنگامی که از interactive interpreter استفاده می کنید، بلکه جنگو نیز در مکان های زیادی از خروجی __unicode__() برای نمایش شیء ها استفاده می کند.

در پایان، توجه داشته باشید که __unicode__() یک مثال خوب برای اضافه کردن یک رفتار برای مدل ها می باشد. یک مدل جنگو بیشتر از جدول لایه پایگاه داده برای یک شیء توضیح می دهد؛ همچنین مدل جنگو هر عملکردی را که شیء نحوه انجام آن را می داند را توضیح دهد. __unicode__() یک مثال برای عملکرد می باشد بدین معنی که یک مدل نحوه ی نمایش خود را می داند.

‫درج و به روز رساني داده‬

طریقه ی درج کردن داده درون پایگاه داده را مشاهده کردید: ابتدا یک نمونه از یک مدل را با استفاده از ارگومان های آن مانند زیر ساخته:

>>> p = Publisher(name='Apress',
...         address='2855 Telegraph Ave.',
...         city='Berkeley',
...         state_province='CA',
...         country='U.S.A.',
...         website='http://www.apress.com/')

همانطور که در کد فوق ملاحظه می کنید، حرکت فوق تعریف اولیه ی یک کلاس مدل می باشد و پایگاه داده به هیچ وجه لمس نشده است. رکورد مورد نظر تا زمانی که متد save() فراخوانی نشود درون پایگاه داده ذخیره نخواهد شد:

>>> p.save()

عملیات بالا را تقریبا می تواند به شکل زیر به زبان SQL ترجمه کرد:

INSERT INTO books_publisher
    (name, address, city, state_province, country, website)
VALUES
    ('Apress', '2855 Telegraph Ave.', 'Berkeley', 'CA',
     'U.S.A.', 'http://www.apress.com/');

به دلیل آنکه مدل Publisher از یک کلید اصلی به نام id که با خاصیت افزایش خودکار تعریف شده است استفاده می کند، نخستین فراخوانی save() یک کار بیشتر انجام می دهد: ارزش کلید اصلی را برای رکورد محاسبه کرده و آن را درون attribute مورد نظر یعنی id که درون نمونه (instance) می باشد، قرار می دهد:

>>> p.id
52    # this will differ based on your own data

فراخوانی های بعدی save() رکورد را در مکانی ذخیره می کند، بدون ساختن رکورد جدید (مانند عملکرد عبارت Upadate به جای INSERT در SQL)

>>> p.name = 'Apress Publishing'
>>> p.save()

عملیات فوق را می توان تقریبا به شکل زیر به SQL تبدیل کرد:

UPDATE books_publisher SET
    name = 'Apress Publishing',
    address = '2855 Telegraph Ave.',
    city = 'Berkeley',
    state_province = 'CA',
    country = 'U.S.A.',
    website = 'http://www.apress.com'
WHERE id = 52;

بله، توجه داشته باشید که نه تنها فیلد مورد نظر بلکه تمام فیلدها به روز رسانی خواهند شد. برای پی بردن به نحوه ی اجرای پرس و جوی زیر بخش "به روز رسانی چندین شیء در یک عبارت" را مطالعه کنید:

UPDATE books_publisher SET
    name = 'Apress Publishing'
WHERE id=52;
Has no item to show!