Oruji.org
Oruji.orgPersian Tutorials
ورود
ویرایش: 1396/11/2 22:27

آموزش مدل ها در جنگو (Django)

در آموزش view و urlconf جنگو از این کتاب، اصول ساختن وب سایت های پویا در جنگو (Django) شرح داده شد به عبارت دیگر اصول راه اندازی view ها و URLconf ها را بررسی کردیم. همانطور که توضیح داده شد، view مسئولیت انجام برخی منطق های اختیاری و برگرداندن یک پاسخ را به عهده دارد. در یکی از مثال ها، منطق اختیاری، محاسبه کردن زمان و تاریخ فعلی بود.

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

بسیاری از وب سایت های پیچیده یک سری ترکیب از دو موضوع را تهیه می کنند. به عنوان نمونه Amazon.com، یک مثال عالی برای یک سایت پایگاه داده محور می باشد. هر صفحه ی محصول اساسا یک پرس وجو (Query) قالب بندی شده به صورت HTML، درون پایگاه داده ی محصول آمازون می باشد و هنگامی که شما یک بررسی مشتری را ارسال می کنید، آن بررسی ها درون پایگاه داده درج می شوند.

جنگو برای ساختن وب سایت های پایگاه داده محور مناسب می باشد، زیرا جنگو (Django) با استفاده از پایتون (Python) ابزار قدرتمندی را برای اجرای پرس و جوهای پایگاه داده ایجاد کرده است. در این آموزش به عملکرد لایه ی پایگاه داده ی جنگو پرداخته می شود.

(نکته: بهتر است با تئوری های پایگاه داده ی relational و SQL تاحدودی آشنا باشید. آشنا سازی برای این مفاهیم خارج از حوصله ی این کتاب می باشد، ولی حتی اگر شما یک کاربر جدید پایگاه داده می باشید باز هم این کتاب را بخوانید. ممکن است بتوانید مفاهیم و اصول اولیه پایگاه داده را درک کنید.)

روش اولیه ی اجرای پرس و جوهای پایگاه داده در view ها

همانطور که در آموزش view و urlconf جنگو توضیح داده شد، روش اولیه ی برای تولید خروجی درون یک view (از طریق نوشتن کد به طور مستقیم درون view) برای بازیابی داده از یک پایگاه داده درون یک view می باشد. این روش ساده می باشد زیرا فقط نیاز به استفاده از کتابخانه ی پایتون برای اجرای یک پرس و جوی SQL و کار با نتایج بدست آمده می باشد.

در مثال view زیر، از کتابخانه ی MySQLdb (قابل دسترس از طریق آدرس http://wwww.djangoproject.com/r/python-mysql/) استفاده شده است. برای اتصال به پایگاه داده MySQL، بازیابی برخی رکوردها و پر کردن آن برای یک template جهت نمایش به صورت یک صفحه ی وب:

from django.shortcuts import render_to_response import MySQLdb def book_list(request): db = MySQLdb.connect(user='me', db='mydb', passwd='secret', host='localhost') cursor = db.cursor() cursor.execute('SELECT name FROM books ORDER BY name') names = [row[0] for row in cursor.fetchall()] db.close() return render_to_response('book_list.html', {'names': names})

روش فوق می تواند جوابگوی نیاز ما باشد، اما معایبی دارد که در ادامه به آنها اشاره شده است:

همانطور که انتظار داریم، لایه ی پایگاه داده ی جنگو راه حلی برای حل این مشکلات ارائه کرده است. مثال زیر کد بازنویسی شده ی قبلی را با استفاده از API پایگاه داده ی جنگو نشان می دهد:

from django.shortcuts import render_to_response from mysite.books.models import Book def book_list(request): books = Book.objects.order_by('name') return render_to_response('book_list.html', {'books': books})

کد فوق کمی بعد در همین فصل شرح داده خواهد شد. تنها برای حالا کافی است دید کلی نسبت به این API پیدا کنید.

الگوی توسعه ی MTV (یا MVC)

تاکنون در این کتاب، همواره به درون کد تمرکز شده است، اجازه دهید برای لحظاتی به بررسی یک برنامه ی وب پایگاه داده محور جنگو بپردازیم.

همانطور که در فصل گذشته بیان شد، جنگو به نحوی طراحی شده است که برنامه نویس را تشویق کند تا اصول loose coupling و جداسازی بین قسمت های یک برنامه را رعایت کند. در صورتیکه این فلسفه را دنبال کنید، ایجاد تغییرات در یک قسمت مشخص از برنامه هیچ تاثیری بر روی قسمت های دیگر برنامه نخواهد داشت. برای نمونه در توابع view، اهمیت جداسازی منطق برنامه از قسمت ظاهر برنامه با استفاده از template توضیح داده شد. در لایه ی پایگاه داده، همین فلسفه را برای دسترسی به داده بکار خواهیم برد.

این سه قسمت با یکدیگر (دسترسی به داده، منطق برنامه و ظاهر برنامه) یک مفهومی را در بر دارد که الگوی Model-View-Controller (MVC) از معماری نرم افزار نامیده می شود. در این الگو، Model به لایه ی دسترسی داده اشاره می کند، View به بخشی از سیستم که به انتخاب آنچه را که باید نمایش دهد و اینکه چطور باید آن را نمایش دهد اشاره می کند و Controller به بخشی از سیستم که بسته به ورودی کاربر تصمیم می گیرد کدام view باید استفاده شود اشاره دارد.

نکته

چرا از شکل مخفف استفاده می شود؟

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

جنگو الگوی MVC را به اندازه ی کافی از نزدیک دنبال می کند به طوری که می توان آن را یک فریم ورک یا چارچوب MVC نامید. در زیر نحوه ی تقسیم بندی M، V و C به درون جنگو را مشاهده می کنید:

به دلیل آنکه C ("Controler") توسط خود فریم فرک کنترل می شود و بیشترین تحرکات در models ،template و view ها اتفاق می افتد، جنگو به صورت یک فریم ورک یا چارچوب MTV نیز شناخته می شود. در الگوی توسعه ی MTV:

در صورتیکه با چارچوب یا فریم ورک های دیگر توسعه ی وب مانند Ruby on Rails کار کرده باشید، ممکن است تصور کنید view های جنگو نقش "Controller" را بازی می کنند و template ها هم در حکم "views" می باشند. همچین تفسیری درباره ی MVC مایه ی تاسف می باشد. تفسیر جنگو نسبت به MVC، این است که "view" ارائه دادن داده به کاربر را شرح می دهد، این لزوما تنها ظاهر داده نمی باشد، بلکه منظور داده ی ارائه شده می باشد. در مقابل، Ruby on Rails و فریم ورک های مانند آن پیشنهاد می کنند که تصمیم گیری درباره ی اینکه کدام داده باید به کاربر ارائه داده شود از جمله وظایف controller می باشد، در حالیکه، ظاهر داده به طور موکد بر عهده ی view می باشد.

پیکربندی پایگاه داده

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

فرض بر این است که سرور پایگاه داده نصب و فعال شده است، و همچنین یک پایگاه داده درون آن ساخته شده است (به عنوان مثال، با استفاده از دستور CREATE DATABASE STATEMENT). در صورتیکه از SQLite استفاده می کنید، به هیچگونه نصب نیاز نخواهد بود، زیر SQLite از فایل های مستقلی روی سیستم برای ذخیره ی داده های خود استفاده می کند.

درست مانند TEMPLATE_DIRS که در فصل گذشته استفاده شد، پیکربندی مربوط به پایگاه داده نیز درون فایل settings می باشد:

DATABASE_ENGINE = '' DATABASE_NAME = '' DATABASE_USER = '' DATABASE_PASSWORD = '' DATABASE_HOST = '' DATABASE_PORT = ''

در زیر خلاصه هایی از هر تنظیم توضیح داده شده است:

DATABASE_ENGINE = 'postgresql_psycopg2'

DATABASE_NAME نام پایگاه داده ی شما را به جنگو اطلاع می دهد:

DATABASE_NAME = 'mydb'

در صورتیکه از SQLite استفاده می کنید، آدرس کامل پایگاه داده ی خود را درون این تنظیم قرار دهید:

DATABASE_NAME = '/home/django/mydata.db'
  • DATABASE_USER نام کاربری که برای اتصال به پایگاه داده لازم است را به جنگو اطلاع می دهد.
  • DATABASE_PASSWORD رمز عبوری که برای اتصال به پایگاه داده لازم است را به جنگو اطلاع می دهد. در صورتیکه از SQLite استفاده می کنید یا اینکه می خواهید پسوردی در نظر نگیرید، می توانید آن را خالی بگذارید.
  • DATABASE_HOST host مورد نظری که برای اتصال به پایگاه داده لازم است را به جنگو اطلاع می دهد. در صورتیکه پایگاه داده ی شما همانند نصب جنگو در یک رایانه می باشد (مانند localhost) آن را خالی بگذارید. همچنین اگر از SQLite استفاده می کنید نیز می توانید آن را خالی بگذارید.

    MySQL در اینجا یک مورد خاص می باشد. در صورتیکه مقدار این تنظیم (DATABASE_HOST) با علامت (/) شروع شود و شما از MySQL استفاده کنید، MySQL از طریق یک Unix socket برای socket تعیین شده متصل خواهد شد:

    DATABASE_HOST = '/var/run/mysql'
  • هنگامی که تنظیمات فوق را انجام داده و فایل settings.py ذخیره کردید، ایده ی خوب است که پیکربندی انجام شده را مورد آزمون قرار دهید. برای انجام این کار، مانند فصل گذشته درون دایرکتوری پروژه ی mysite دستور python manage.py shell را اجرا کنید. (همانطور که در فصل گذشته اشاره شد دستور manage.py shell روشی برای اجرای interpreter پایتون، با تنظیمات صحیح فعال شده ی جنگو می باشد. در این مورد این ضروری است، زیرا نیاز است جنگو تنظیمات فایل را به منظور به دست آوردن اطلاعات connection پایگاه داده برای استفاده بداند.)

    درون خط فرمان، دستورات زیر را به منظور آزمودن پیکربندی پایگاه داده تایپ کنید:

    >>> from django.db import connection >>> cursor = connection.cursor()

    در صورتیکه اتفاقی رخ ندهد پایگاه داده پیکربندی شده است. در غیر این صورت، پیام خطا را برای بدست آوردن دلیل خطا بررسی کنید. جدول 2-5 برخی از این خطاها را نشان می دهد.

    جدول

    جدول ۲-۵

    راه حل پیام خطا
    تنظیم DATABASE_ENGINE را با چیزی به غیر از رشته ی خالی پر کنید. مقادیر معتبر برای این تنظیم در جدول 1-5 وجود دارد. You haven't set the DATABASE_ENGINE setting yet.
    به جای دستور python از دستور python manage.py shell باید استفاده کرد. Environment variable DJANGO_SETTINGS_MODULE is undefined.
    Adapter پایگاه داده ی مناسبی نصب نشده است (مانند psycopg یا MySQLdb). Adapter ها با جنگو مچ نشده اند، بنابراین می بایست Adapter مورد نظر را دانلود و نصب کنید. Environment variable DJANGO_SETTINGS_MODULE is undefined.
    SQLite Error loading _____ module: No module named _____.
    تنظیم DATABASE_ENGINE را با یک موتور پایگاه داده که در جدول 1-5 وجود دارد پر کنید. _____ isn't an available database backend.
    تنظیم مربوط به DATABASE_USER باید تغییر کنید و همچنین تنظیمی باشد که وجود دارد، و یا یک نام کاربری برای پایگاه داده باید ساخته شود. role _____ does not exist
    اطمینان حاصل کنید که DATABASE_HOST و DATABASE_PORT صحیح بوده و سرور پایگاه داده در حال اجرا می باشد. could not connect to server

    ایجاد اولین App

    اکنون که مشخص شد اتصال به پایگاه داده با موفقیت انجام شده است، زمان آن رسیده است که یک app برای جنگو ایجاد کنیم، app یک بسته از کد جنگو می باشد که model ها و view ها در آن قرار می گیرد، که همگی با هم درون یک پکیج پایتون قرار گرفته اند و یک برنامه (application) جنگو را نمایش می دهند.

    در شروع کار جنگو نحوه ی ساختن یک پروژه ی جنگو توضیح داده شد، اکنون فرق بین یک پروژه با یک app(اپلیکیشن)در چیست؟ تفاوت آن در پیکربندی در مقابل کد است:

    مقدار بسیار کمی قوانین سخت و محکم نسبت به وفق دادن کد جنگو با این طرح وجود دارد. در صورتیکه بخواهید یک وب سایت ساده بسازید، ممکن است تنها از یک app استفاده کنید. و اگر می خواهید یک وب سایت بزرگ و پیچیده با چندین قسمت مرتبط به هم مانند یک سیستم تجارت الکترونیک و یک تابلوی پیام (message board) بسازید، احتمالا این قسمت ها را درون app ها جدا قرار خواهید داد، به طوری که قادر باشید در صورت نیاز آن ها را به صورت منحصر به فرد در اینده استفاده کنید.

    در واقع، لزوما همیشه نیاز به ساختن app ها در پروژه نیست، به عنوان نمونه توابع view که تاکنون ساخته شده است حاکی این موضوع می باشد. در آن مواردبه سادگی یک فایل views.py ساخته شده و با توابع view مورد نیاز درون آن پر می شد، و URLconf نیز به آن توابع اشاره می کرد. نیازی به app ها نبود.

    با این وجود، در یک صورت باید از app ها استفاده شود: در صورتیکه شما از لایه ی پایگاه داده ی (models) جنگو استفاده می کنید، باید یک app جنگو بسازید. model ها باید درون app ها ایجاد شوند. در نتیجه، به منظور ساختن model ها، نیزا به ساختن یک app جدید می باشد.

    درون دایرکتوری پروژه ی mysite، دستور زیر را برای ساختن app مورد نظر با نام books اجرا کنید:

    python manage.py startapp books

    دستور فوق هیچ خروجی ای را تولید نمی کند، در عوض دایرکتوری books را درون دایرکتوری mysite می سازد. در زیر محتویات این دایرکتوری را مشاهده می کند:

    books/ __init__.py models.py tests.py views.py

    این فایل ها حاوی model ها و view ها برای این app می باشد.

    درون ویرایشگر متن مورد علاقه ی خود نگاهی به فایل های models.py و views.py بیاندازید. جفت فایل ها خالی هستند، به غیر از کامنت ها و یک import که درون فایل models.py قرار دارد.

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

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

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

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

    اولین Model شما

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

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

    اولین قدم برای استفاده کردن لایه ی پایگاه داده با جنگو، بیان آن به صورت کد پایتون می باشد. درون فایل 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;

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

    دستور 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، خواهید فهمید کدام خط فرمان اجرا می شود. شیوه ی دوم تقریبا همیشه مناسب تر می باشد.

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

    هنگامی که شما یک مدل ساخته می شود، جنگو به طور خودکار یک 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>]

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

    نکته ای با اهمیتی که در این مورد واضح و یا روشن به نظر نمی رسد اینکه، هنگامی که شما با استفاده از 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"ایجاد خواهد کرد.

    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;

    ‫واكشي آبجكت ها‬

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

    >>> Publisher.objects.all() [<Publisher: Apress>, <Publisher: O'Reilly>]

    مدل کد فوق در SQL چیزی شبیه به کد زیر خواهد بود:

    SELECT id, name, address, city, state_province, country, website FROM books_publisher;جدول

    ‫نكته‬

    توجه داشته باشید که جنگو هنگامی که به دنبال داده ها می باشد از SELECT * استفاده نمی کند، در عوض لیست تمام فیلدها را به صورت واضح بازیابی می کند. در بعضی شرایط SELECT * می تواند کندتر باشد و (خیلی مهم است) لیست کردن فیلدها به طرز نزدیکی از مکتب پایتون (Zen of Python) پیروی کند: "صراحت بهتر از ابهام است".

    اجازه دهید از نزدیک بخش های Publisher.objects.all() را مورد بررسی قرار دهیم:

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

    به طور طبیعی، کم پیش می اید که بخواهیم همه چیز را از پایگاه داده یکباره واکشی کنیم؛ در اغلب موارد، می خواهید با قسمتی از داده ها سر و کار داشته باشید. در API جنگو، شما می توانید داده ی خود را با استفاده از متد filter() فیلتر کنید:

    >>> Publisher.objects.filter(name='Apress') [<Publisher: Apress>]

    filter() یک آرگومان به صورت کیورد در یافت می کند که معادل آن در SQL عبارت WHERE می باشد. معادل کد SQL مثال قبلی چیزی مانند کد زیر بود:

    SELECT id, name, address, city, state_province, country, website FROM books_publisher WHERE name = 'Apress';

    جهت محدود کردن بیشتر خروجی می توانید چندین آرگومان را به درون filter() ارسال کنید:

    >>> Publisher.objects.filter(country="U.S.A.", state_province="CA") [<Publisher: Apress>]

    می توان ارسال چندین آرگومان به متد filter() درون SQL مانند عبارت AND داست. در نتیجه، مثال فوق می تواند به شکل زیر یه کد SQL تبدیل شود:

    SELECT id, name, address, city, state_province, country, website FROM books_publisher WHERE country = 'U.S.A.' AND state_province = 'CA';

    توجه داشته باشید که به طور پیشفرض جستجو درون SQL با علامت = دقیقا یکسان بودن را بررسی می کند. نوع دیگر جستجو نیز در دسترس می باشد:

    >>> Publisher.objects.filter(name__contains="press") [<Publisher: Apress>]

    همانطور که مشاهده می کنید دو علامت (_) بین name و contains قرار دارد. مانند خود پایتون، جنگو از این خصوصیت برای اشاره به این که چیزی به صورت "magic" در حال اتفاق افتادن می باشد استفاده می کند (در اینجا قسمت __contains به عبارت LIKE در SQL تبدیل می شود.)

    SELECT id, name, address, city, state_province, country, website FROM books_publisher WHERE name LIKE '%press%';

    انواع دیگر جستجو نیز در دسترس می باشد، از جمله icontains (عبارت LIKE که به حروف کوچک و بزرگ حساس می باشد)، starstwith، endswith و range (پرس و جوی BETWEEN در SQL).

    بازیابی شیء های تک

    مثال های filter() فوق همگی یک QuerySET را بر می گردانند، که می توان با آن ها مانند لیست ها کار کرد. گاهی اوقات بسیار مناسب می باشد که تنها یک تک شیء را از پایگاه داده واکشی کنیم. برای این منظور متد get() در دسترس می باشد:

    >>> Publisher.objects.get(name="Apress") <Publisher: Apress>

    بجای یک لیست (QuerySet) یک تک شیء برگشت داده شده است. به دلیل آنکه در صورتیکه نتیجه پرس و جو (query) چند شیء باشد موجب بروز خطای MultipleObjectsReturned خواهد شد:

    >>> Publisher.objects.get(country="U.S.A.") Traceback (most recent call last): ... MultipleObjectsReturned: get() returned more than one Publisher -- it returned 2! Lookup parameters were {'country': 'U.S.A.'}

    همچنین در صورتیکه هیچ شیءی برگدانده نشود موجب بروز خطای DoesNotExist خواهد شد

    >>> Publisher.objects.get(name="Penguin") Traceback (most recent call last): ... DoesNotExist: Publisher matching query does not exist.

    خطای DoesNotExist یک attribute از کلاس مدل می باشد (Publisher.DoesNotExist). در برنامه های خود می توانید مانند زیر خطاها را کنترل کنید:

    try: p = Publisher.objects.get(name='Apress') except Publisher.DoesNotExist: print "Apress isn't in the database yet." else: print "Apress is in the database."

    مرتب سازی داده ها

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

    در برنامه های جنگو، ممکن است بخواهید نتیجه استخراج شده از پایگاه داده را بر اساس یکی از معیارها مرتب کنید (برای مثال بر اساس حروف الفبا). برای انجام این کار از متد order_by() استفاده می شود:

    >>> Publisher.objects.order_by("name") [<Publisher: Apress>, <Publisher: O'Reilly>]

    مثال فوق فرق چندانی با متد قبلی یعنی all() ندارد، تنها فرق در این است که حالا SQL ترتیب تعیین شده را نیز لحاظ می کند:

    SELECT id, name, address, city, state_province, country, website FROM books_publisher ORDER BY name;

    شما می توانید بر اساس هر فیلدی که مایلید خروجی را مرتب کنید:

    >>> Publisher.objects.order_by("address") [<Publisher: O'Reilly>, <Publisher: Apress>] >>> Publisher.objects.order_by("state_province") [<Publisher: Apress>, <Publisher: O'Reilly>]

    برای مرتب کردن بر اساس چندین فیلد (در مواردی استفاده می شود که آرگومان اول درون هر دو فیلد یکی باشد، در آن زمان برای رفع ابهام از آرگومان دوم استفاده می شود.) مانند زیر:

    >>> Publisher.objects.order_by("state_province", "address") [<Publisher: Apress>, <Publisher: O'Reilly>]

    همچنین می توان ترتیب چیدمان را با استفاده از یک علامت (-) به صورت بر عکس انجام داد:

    >>> Publisher.objects.order_by("-name") [<Publisher: O'Reilly>, <Publisher: Apress>]

    در اغلب موارد شما همواره می خواهید در حالت پیشفرض خروجی داده های شما بر اساس یکی از فیلد های چیده شده باشد، در این صورت جنگو این امکان را فراهم می کند که به صورت پیشفرض درون مدل خود این کار انجام دهید، این امکان زمانی مفید واقع می شود که بخواهید به صورت مکرر از order_by() استفاده کنید، در این صورت منطقی این است که روش زیر را انتخاب کنید:

    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 Meta: ordering = ['name']

    در مثال فوق، یک مفهوم جدید معرفی شده است: class Meta، کلاسی می باشد که درون کلاس Publisher تعریف شده است (این کلاس درون class Publisher به صورت داخل رفته indented قرار گرفته است). می توان از کلاس Meta روی هر مدل برای تعیین اختیارات مختلفی استفاده کرد. که در اینجا ما از اختیار مرتب کردن آن استفاده کرده ایم. این اختیار به جنگو می گوید که اگر به صورت واضح برای چیدمان داده از order_by() استفاده نشده است، تمام شیء های Publisher هر زمان که با API پایگاه داده بازیابی شدند، باید بر اساس فیلد name مرتب شوند.

    جستجوی زنجیری

    نحوه ی فیلتر کردن داده را مشاهده کردید، همچنین نحوه ی مرتب کردن آن ها را نیز مشاهده نمودید. اغلب، نیز می باشد هر دو مورد فوق را انجام دهید. در این موارد می توان به سادگی با استفاده از قابلیت جستجوی زنجیری هر دوی موارد فوق در یک خط انجام داد:

    >>> Publisher.objects.filter(country="U.S.A.").order_by("-name") [<Publisher: O'Reilly>, <Publisher: Apress>]

    همانطور که انتظار می رود، معادل کد فوق در SQL استفاده از یک WHERE و یک ORDER BY می باشد:

    SELECT id, name, address, city, state_province, country, website FROM books_publisher WHERE country = 'U.S.A' ORDER BY name DESC;

    تقسیم کردن داده

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

    >>> Publisher.objects.order_by('name')[0] <Publisher: Apress>

    کد فوق به شکل زیر تبدیل می شود:

    SELECT id, name, address, city, state_province, country, website FROM books_publisher ORDER BY name LIMIT 1;

    به همین صورت، می توان زیر مجموعه ای از داده را نیز بازیابی کرد:

    >>> Publisher.objects.order_by('name')[0:2]

    مثال فوق دو شیء را بر می گرداند، و درون SQL به شکل زیر تبدیل خواهد شد:

    SELECT id, name, address, city, state_province, country, website FROM books_publisher ORDER BY name OFFSET 0 LIMIT 2;

    توجه داشته باشید که قسیم کردن به صورت منفی در اینجا پشتیبانی نمی شود:

    >>> Publisher.objects.order_by('name')[-1] Traceback (most recent call last): ... AssertionError: Negative indexing is not supported.

    با وجود این می توانید به راحتی محدودیت فوق را دور بزنید. تنها کافیست عبارت order_by() را به صورت زیر تغییر دهید:

    >>> Publisher.objects.order_by('-name')[0]

    به روز رسانی چند شیء در یک عبارت

    در بخش "درج و به روز رسانی داده" اشاره شد که متد save() تمام ستون های یک ردیف را به روز رسانی می کند. بسته به برنامه ی شما، ممکن است بخواهید تنها یک قسمت از ستون ها را به روز رسانی کنید.

    به عنوان مثال، تصور کنید می خواهیم Apress را درون Publisher از 'Apress' به 'Apress Publishing' تغییر دهیم. با استفاده از save() به این صورت عمل می توان کرد:

    >>> p = Publisher.objects.get(name='Apress') >>> p.name = 'Apress Publishing' >>> p.save()

    که درون SQL نیز به این شکل تبدیل خواهد شد:

    SELECT id, name, address, city, state_province, country, website FROM books_publisher WHERE name = 'Apress'; 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;

    (توجه داشته باشید که مثال فوق فرض را بر این گرفته است که Apress دارای id = 52 می باشد.)

    می توان در مثال فوق مشاهده نمود که متد save() جنگو نه تنها ستون name را بلکه ارزش تمام ستون ها را به روز رسانی می کند. منطقی تر و بهتر آن است که تنها ستون مورد نظر تغییر کند. برای انجام چنین کاری می توان از متد update() موجود در شیء های QuerySet استفاده مانند زیر استفاده کرد:

    >>> Publisher.objects.filter(id=52).update(name='Apress Publishing')

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

    UPDATE books_publisher SET name = 'Apress Publishing' WHERE id = 52;

    متد update() بر روی هر QuerySet ای کار می کند، بدین معنی که می توان چندین رکورد را نیز ویرایش کرد. در مثال زیر نحوه تغییر country درون هر رکورد Publisher از 'U.S.A' به USA نشان داده شده است.

    >>> Publisher.objects.all().update(country='USA') 2

    متد update() یک integer بر می گرداند که تعداد رکوردهای تغییر داده شده می باشد، در مثال فوق 2 رکورد تغییر داده شده اند.

    حذف کردن شیء ها

    برای حذف کردن یک شیء از پایگاه داده، به سادگی متد delete() را می توان فراخوانی کرد:

    >>> p = Publisher.objects.get(name="O'Reilly") >>> p.delete() >>> Publisher.objects.all() [<Publisher: Apress Publishing>]

    همچنین می توان چندین شیء را نیز با فراخوانی متد delete() از هر QuerySet حذف کرد. این حالت مانند متد update() که در بخش گذشته نشان داده شد می باشد:

    >>> Publisher.objects.filter(country='USA').delete() >>> Publisher.objects.all().delete() >>> Publisher.objects.all() []

    هنگام حذف کردن داده ها مراقب باشید! برای احتیاط از حذف شدن تمام داده های موجود در یک جدول مشخص، در صورتیکه می خواهید هر آنچه که درون جدول می باشد را حذف کنید، می توان از متد all() استفاده کرد. به عنوان مثال کد زیر کار نخواهد کرد:

    >>> Publisher.objects.delete() Traceback (most recent call last): File "<console>", line 1, in <module> AttributeError: 'Manager' object has no attribute 'delete'

    ولی اگر متد all() را اضافه کنید کار خواهد کرد:

    >>> Publisher.objects.all().delete()

    در صورتیکه می خواهید تنها بخشی از داده را حذف کنید، نیازی به متد all() نمی باشد:

    >>> Publisher.objects.filter(country='USA').delete()