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

 

خوش آمدید به انجمن تخصصی پایتون و جنگو (پایتونی ها)

لطفاً برای دسترسی به تمامی بخش های سایت مراحل ثبت نام و ایجاد حساب کاربری را طی نمایید.

جستجو در تالار: در حال نمایش نتایج برای برچسب های 'django'.



تنظیمات بیشتر جستجو

  • جستجو بر اساس برچسب

    برچسب ها را با , از یکدیگر جدا نمایید.
  • جستجو بر اساس نویسنده

نوع محتوا


تالار ها

  • پایتون ( Python )
    • تالار پایتون مقدماتی
    • تالار پایتون پیشرفته
    • تالار تفاوت زبان پایتون ورژن ۲ و ۳
  • جنگو ( django )
    • تالار جنگو مقدماتی
    • تالار جنگو پیشرفته
    • تالار کتاب جنگو ( جنگو بوک )
    • تالار آموزش پروژه محور جنگو
  • آموزش تکه کدهای کاربردی پایتون ( Python Code Snippet )
  • دریافت نسخه های پایتون
    • نرم افزار زبان برنامه نویسی پایتون
  • دریافت افزونه های پایتون
    • اجرای اسکریپتهای پایتون در اندروید
  • رفع مشكلات برنامه های پايتون
  • معرفی برنامه های تحت پايتون
  • بخش بایگانی

وبلاگ‌ها

  • مقایسه Python با هشت زبان برنامه نویسی مطرح جهان

دسته ها

  • مقاله های سایت

دسته ها

  • دانلود نرم افزار زبان برنامه نویسی پایتون
  • دریافت افزونه های پایتون
    • اجرای اسکریپتهای پایتون در اندروید
  • کتاب های آموزشی پایتون ( Python )
  • کتاب های آموزش فریم ورک جنگو ( Django )

دسته ها

  • آموزش پایتون
    • آموزش پایتون مقدماتی
    • آموزش پایتون پیشرفته
    • تفاوت های پایتون ۲ و پایتون ۳
  • آموزش جنگو
    • آموزش جنگو مقدماتی
    • آموزش جنگو پیشرفته
    • آموزش پروژه محور جنگو
  • تکه کدهای کاربردی پایتون ( Python Code Snippet )
  • آموزش گیت
    • گیت لب ( GitLab )
    • گیت هاب ( GitHub )

12 نتیجه پیدا شد

  1. سلام من یک کد سایت نوشته شده با جانگو در قسمت بک اند و انگولار در قسمت فرانت رو برام فرستادن اما تاحالا با جانگو کار نکردم و همیشه با php کار کردم میخواستم بدونم چطور میتونم این کد هارو روی هاستم اجرا کنم و سایتم رو بالا بیارم خیلی سرچ زدم اما نتونستم به جوابم برسم ممنون میشم اگه به صورت مقدماتی توضیح بدید
  2. با سلام من ی هاست با پشتیبانی پایتون گرفتم. پروژه و app جنگو رو هم میسازم اما واقعا دیگه نمیدونم چیکار کنم که بتونم app جنگو(حتی "it werked!" ساده) را هم اجرا کنم. ممنون میشم اگر راهنماییم کنید.
  3. این تاپیک پشتیبانی برای آموزش است آموزش ایجاد پنل مدیریت در جنگو ( جلسه ششم ) - بخش دوم 12/04/96 11:13 12/04/96 11:13 لطفا اگرهر سوال یا بازخوردی دارید اینجا ارسال کنید.
  4. آموزش سایت مدیرت پیشفرض در جنگو ( بخش دوم ) صفحه ی فوق تمام کاربران موجود در پایگاه داده را نمایش می دهد، می توانید این را به صورت پرس وجو پایگاه داده یک نسخه ی زیبا شده از عبارت SELECT * FROM auth_user تصور کنید. در صورتیکه همراه با مثال های کتاب حرکت می کنید، تنها یک کاربر را مشاهده خواهید کرد، ولی هنگامی که کاربران بیشتری وجود داشته باشد، امکانات مفیدی از قبیل فیلتر کردن، چیدن و جستجوی بین آیتم ها را مشاهده خواهید کرد. امکان فیلتر کردن در سمت راست صفحه موجود می باشد، چیدمان از طریق کلیک کردن روی یک header ستون عملی می شود، و جعبه ی جستجو (search box) در قسمت بالا صفحه می باشد اجازه می دهد بر اساس نام کاربری به جستجو بپردازید. بر روی نام کاربری که ساخته اید کلیک کنید، فرم ویرایش برای کاربر را مشاهده خواهید کرد. صفحه ی فوق این اجازه را می دهد که خصوصیات کاربر را تغییر دهید، مانند نام و نام خانوادگی و حق دسترسی های گوناگون. (توجه داشته باشید که برای تغییر رمز عبور کاربر به جای ویرایش کد hash، می بایست بر روی "change password form" در زیر فیلد رمز عبور کلیک کرد.) نکته ی دیگر قابل توجه اینکه فیلدهای مختلف به شکل های مختلف پیاده سازی شده اند؛ به عنوان مثال، فیلد زمان و تاریخ دارای کنترل تقویم، فیلدهای Boolean دارای checkbox ها و فیلدهای حروف حاوی فیلد ساده ی مربوط به متن می باشند. می توان برای حذف کردن یک رکورد بر روی دکمه ی delete در قسمت پایین سمت چپ از فرم ویرایش کلیک کرد. بسته به شیء هایی که قصد حذف کردن آن را دارید، صفحه ی مربوط به تایید برای حذف رکورد نمایان خواهد شد، به عنوان مثال، در صورتیکه یک ناشر را حذف کنید، هر کتاب مربوط به ناشر نیز حذف خواهد شد! همچنین می توان با کلیک کردن بر روی "Add" درون ستون مناسب از صفحه ی خانگی مدیر یک رکورد را اضافه کرد. بعد از کلیک صفحه ای با فیلدهای خصوصیات خالی نمایان می شود که آماده برای پر شدن است. همچنین متوجه این موضوع خواهید شد که رابط مدیر همچنین معتبر بودن ورودی ها را برای شما کنترل می کند. یکی از فیلدهایی را که باید حتما پر شود را خالی بگذارید و یا یک مقدار نا معتبر درون یکی از فیلدها قرار دهید، سپس شما خطاهایی را هنگام ذخیره مانند شکل 5-6 مشاهده خواهید نمود. هنگامی که یک شیء موجود را ویرایش می کنید، متوجه یک لینک History در قسمت راست بالای صفحه خواهید شد. هر تغییری درون رابط مدیر اتفاق بیافتد در اینجا ثبت خواهد شد، و می توان با کیک کردن بر روی لینک History آن تغییر را بررسی کرد. اضافه کردن مدل ها به سایت مدیر یک بخش بسیار مهمی هنوز انجام نشده است. اجازه دهید مدل های خود را به سایت مدیر اضافه کنیم، بنابراین می توان شیء های درون جداول پایگاه داده ی مورد نظر را با این رابط عالی حذف، اضافه و تغییر داد. در این فصل نیز مثال books را دنبال خواهیم کرد که در آن سه مدل به نام های Publisher، َAuthor و book تعریف شده است. درون دایرکتوری books (mysite/books)، یک فایل با نام admin.py ایجاد کرده و کد زیر درون آن وارد کنید: from django.contrib import admin from mysite.books.models import Publisher, Author, Book admin.site.register(Publisher) admin.site.register(Author) admin.site.register(Book) کد فوق برای هر یک از مدل ها یک رابط به مدیر جنگو اضافه می کند. هنگامی که این کار انجام داده شد، به صفحه ی خانگی مدیر درون مرورگر خود رفته (http://127.0.0.1/admin/)، شما باید قسمت "Books" را با لینک های Authors، Books و Publishers مشاهده کنید. (برای موثر واقع شدن تغییرات می بایست سرور را متوقف کرده و دوباره اجرا runserver کنید) شما هم اکنون برای هر از این سه مدل یک رابط مدیر در حال کار خواهید داشت. بسیار ساده است! می توانید زمانی را برای اضافه کردن و تغییر رکوردها اختصاص دهید، تا داده هایی را درون پایگاه داده اضافه کنید. در صورتیکه مثال های آموزش مدل جنگو (ساختن شیء های Publisher) را دنبال کرده و آن ها را حذف نکرده باشید، آن رکوردهای ساخته شده در آموزش مدل جنگو را در صفحه ی لیست تغییرات publisher مشاهده خواهید کرد. یکی از خصوصیات با ارزشی که می توان در اینجا ذکر کرد، کنترل سایت مدیر برای کلیدهای خارجی و رابطه های چند به چند می باشد، هر دوی این حالت ها در مدل Book وجود دارند، برای یادآوری کد زیر مدل Book می باشد: 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 درون صفحه ی "Add book" مدیر (http://127.0.0.1:8000/admin/books/book/add/)، Publisher (یک ForeignKey) با یک جعبه ی انتخاب (select box) نمایش داده شده است، و فیلد Authors (یک ManyToManyField) با یک جعبه ی چند انتخابی (multiple-select box) نمایش داده شده است. هر دو فیلد فوق دارای یک علامت سبز رنگ جمع در جلوی خود می باشند که برای اضافه کردن رکوردهای مرتبط به آن ها می باشد. برای مثال، در صورتیکه شما بر روی آن علامت سبز رنگ جلوی فیلد "Publisher" کلیک کنید، یک پنجره ی pop-up برای اضافه کردن یک ناشر باز می باشد. بعد از آنکه یک ناشر در پنجره ی باز شده ساخته شود، صفحه ی "Add book" با جدید ترین ناشر ساخته شده به روزرسانی می شود. نحوه ی کار سایت مدیر در پشت صحنه، سایت مدیر چه طور کار می کند؟ نحوه ی کار آن بسیار ساده می باشد. هنگامی که جنگو URLconf را هنگام اجرای سرور در urls.py بارگذاری می کند، عبارت admin.autodiscover() که در درون این برای فعال کردن سایت مدیر قرار داده شده است اجرا می شود. این تابع درون تنظیم INSTALLED_APPS به دنبال فایلی به نام admin.py که درون هر یک از ایتم ها جستجو می کند. در صورتیکه admin.py درون یکی از app های داده شده وجود داشته باشد، کد درون آن فایل اجرا می شود. در فایل admin.py درون app مورد نظر یعنی books، فراخوانی هر admin.site.register() به سادگی مدل داده شده را درون سایت مدیر عضو می کند. سایت مدیر تنها یک رابط ویرایش/تغییر برای مدل های عضو شده را نمایش می دهد. همانطور که مشاهده شد، سایت مدیر به صورت خودکار Users و Groups را نمایش می دهد که درون app خود یعنی django.contrib.auth می باشند که این app شامل فایل admin.py خود و Users و Groups درون آن می باشد. app های دیگر django.contrib، مانند django.contrib.redirects، نیز خودشان را درون سایت مدیر اضافه می کنند. از این گذشته، سایت مدیر جنگو تنها یک application جنگو با مدل های خود، view ها و URLpattern ها می باشد. با استفاده از URLconf آن را به برنامه ی خود اضافه می کنید، تنها درون view ها خود از آن استفاده می کنید. می توان template ها، view ها و URLpattern های آن را با رفتن به مسیر django.contrib/admin مشاهده و بازرسی کنید ولی تحریک به تغییر چیزی به طور مستقیم در آنجا نشوید چرا که امکانات استفاده ی غیر مستقیم زیادی برای شما وجود دارد. ایجاد فیلدهای اختیاری بعد از آنکه کمی با سایت مدیر آشنا شده و از آن استفاده کردید، ممکن است متوجه محدودیت هایی شده باشید، مانند اینکه هر فیلد باید پر شده باشد، در حالیکه در بسیاری از موارد شما می خواهید پر کردن بعضی از فیلدها اختیاری باشد، به عنوان مثال، می خواهیم فیلد email مدل Author اختیاری باشد یعنی بتوان فیلد را خالی گذاشت. در دنیای واقعی، شما ممکن است هیچ آدرس الکترونیکی نداشته باشید. برای تعیین کردن فیلد email اختیاری، مدل Book را ویرایش می کنیم (این مدل درون فایل mysite/books/models.py می باشد.) برای این کار به سادگی blank=True را به مانند مثال زیر به فیلد email اضافه می کنیم: class Author(models.Model): first_name = models.CharField(max_length=30) last_name = models.CharField(max_length=40) email = models.EmailField(blank=True) حرکت فوق به جنگو می گوید که برای آدرس پست الکترونیک نویسندگان می توان مقدار خالی را نیز در نظر گرفت. به صورت پیش فرض، تمام فیلدها blank=False می باشند، بدین معنی که مقدار خالی را نمی توان برای آن ها در نظر گرفت. تا حالا، بجز متد __unicode__()، مدل های ما به صورت جداول پایگاه داده ما بکار می رفتند یعنی مدل ها عبارات پایتونی معادل عبارات CREATE TABE در SQL بودند. با اضافه کردن blank=True، ما شروع به گسترش دادن مدل فراتر از تعریف ساده ی مشابه با جدول پایگاه داده کرده ایم. حال، کلاس مدل در حال تبدیل شدن به یک مجموعه ی غنی از دانش درباره ی آنچه که شیء های Author هستند و می توانند انجام دهند، می باشد. نه تنها فیلد email یک ستون VARCHAR در پایگاه داده می باشد، بلکه همچنین می دانیم که یک فیلد اختیاری در سایت مدیر جنگو نیز می باشد. این حالت بدین معنی می باشد که فیلد مورد نظر اختیاری می باشد. حالا می توان نویسندگان را بدون نیاز به تهیه ی آدرس الکترونیک اضافه کرد؛ در صورتیکه فرم مورد نظر را با فیلد خالی آدرس الکترونیک Submit کنید دیگر هیچ پیام "This field is required" با رنگ قرمز مشاهده نخواهید کرد. هنگامی که blank=True اضافه شد، فرم ویرایش "Add author" را دوباره بارگذاری کنید (http://127.0.0.1:8000/admin/books/author/add/)، متوجه خواهید شد که نام فیلد "Email" دیگر به صورت تو پر و پر رنگ نمی باشد. ایجاد فیلد های از نوع تاریخ و عددی به صورت اختیاری نکته ی مهم در رابطه با blank=True این است که انجام این حرکت بر روی فیلدهای از نوع عددی و تاریخ نیازمند مقداری توضیح و پیش زمینه می باشد. SQL برای تعیین مقدار خالی دارای روش خاص خودش می باشد – یک مقدار ویژه به نام NULL. NULL می تواند به معنای ناشناخته، نامعتبر یا ... معنی شود. در SQL یک مقدار NULL با یک مقدار رشته ی خالی متفاوت می باشد، درست مثال شیء None در پایتون که با یک رشته ی خالی پایتون ("") متفاوت می باشد. این بدان معنی است که ممکن است یک فیلد حرفی (مانند یک ستون VARCHAR) به طور همزمان هم حاوی مقدار NULL و هم حاوی یک رشته ی خالی باشد. این موضوع می تواند موجب ابهام و گیجی نا خواسته شود. "چرا این رکورد دارای مقدار NULL ولی آن رکورد دیگر دارای یک رشته ی خالی است؟ ایا تفاوتی وجود دارد، یا فقط داده به صورت نا سازگار وارد شده است؟" و: "چطور می توان تمام رکوردهایی که دارای مقدار خالی می باشند را بدست آورد – ایا می توان هر دو رکوردهای NULL و رشته ی خالی را جستجو کرد، یا یک از آن ها را با مقدار رشته ی خالی انتخاب کرد؟" برای کمک به خلاص شدن از این قبیل ابهامات، جنگو به صورت خودکار عبارت های CREATE TABLE (که در آموزش مدل جنگو توضیح داده شده اند) اضافه و برای هر ستون مقدار NOT NULL را در نظر می گیرد. برای مثال، کد زیر عبارت تولید شده برای مدل Author در آموزش مدل جنگو می باشد: 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 ) ; در اغلب موارد، این حالت پیشفرض برای برنامه مطلوب بوده و شما را از درد سر های تناقض و نا هماهنگی های داده حفظ می کند. و برای بقیه ی قسمت های جنگو به خوبی کار می کند، مانند سایت مدیر جنگو، که در زمان خالی گذاشتن یک فیلد یک رشته ی خالی (نه مقدار NULL) وارد می کند. ولی برای نوع ستون هایی که رشته ی خالی را به عنوان مقدار معتبر قبول نمی کنند – ازقبیل تاریخ ها، زمان ها، و اعداد، یک استثناء وجود دارد. در صورتیکه سعی کنید یک رشته ی خالی برای ستون های ذکر شده وارد کنید، بسته به نوع پایگاه داده ی شما احتمالا خطای پایگاه داده رخ خواهد. در این حالت، NULL تنها راه برای تعیین مقدار خالی می باشد. در مدل های جنگو، می توان مقدار NULL را با اضافه کردن null=True به یک فیلد تعیین کرد. در صورتیکه بخواهید اجازه دهید مقادیر خالی در فیلد تاریخ (مانند DateField، TimeField، DateTimeField) یا فیلد عددی (مانند IntegerField، DecimalField، FloatField) قرار گیرند نیاز است از null=True و blank=True با هم استفاده کنید. اجازه دهید مدل Book را برای اینکه بتوان فیلد publication_date را خالی گذاشت تغییر دهیم: class Book(models.Model): title = models.CharField(max_length=100) authors = models.ManyToManyField(Author) publisher = models.ForeignKey(Publisher) publication_date = models.DateField(blank=True, null=True) اضافه کردن null=True پیچیده تر از اضافه کردن blank=True می باشد، زیرا null=True از نظر معنایی پایگاه داده را تغییر می دهد – در این حالت عبارت CREATE TABLE تغییر می کند بدین شکل که NOT NULL از فیلد publication_date حذف می شود. برای کامل کردن این تغییر، نیاز است پایگاه داده به روز رسانی شود. به دلایلی، جنگو تلاشی برای تغییرات خودکار در شمای پایگاه داده نمی کند، بنابراین مسئولیت اجرای یک عبارت ALTER TABLE هر زمان که که تغییری در مدل ایجاد شد، به عهده خودتان می باشد. می توان از manage.py dbshell برای این منظور استفاده کرد. در کد زیر نحوه ی حذف NOT NULL در این مورد خاص را مشاهده می کنید: ALTER TABLE books_book ALTER COLUMN publication_date DROP NOT NULL; (توجه داشته باشید که کد فوق برای پایگاه داده ی PostgreSQL می باشد.) توضیح و بحث عمیق تر در مورد این تغییرات در آموزش مدل پیشرفته بحث شده است. به سایت مدیر بر می گردیم، اکنون فرم ویرایش "Add book" اجازه می دهد تا مقدار خالی را برای publication date قرار دهیم. سفارشی کردن نام فیلدها در فرم های ویرایش سایت مدیر، نام هر فیلد از روی نام مدل فیلد تولید می شود. الگوریتم آن بسیار ساده می باشد: جنگو تنها خط های تیره (_) را با فاصله ها جایگزین کرده و حروف اول را تبدیل به حروف بزرگ می کند، بنابراین، برای مثال، فیلد publication_date مدل Book دارای نام "Publication date" خواهد بود. اگر چه نام فیلدها درون مدل به طور زیبایی درون سایت مدیر نیز تغییر می کنند، ولی در برخی موارد ممکن است بخواهید آن نام ها را خودتان تعیین کنید. با استفاده از verbose_name می توان این کار را انجام داد. برای مثال، در زیر نحوه ی تغییر نام فیلد Author.email به "e-mail" نشان داده شده است: class Author(models.Model): first_name = models.CharField(max_length=30) last_name = models.CharField(max_length=40) email = models.EmailField(blank=True, verbose_name='e-mail') تغییر فوق را ایجاد کرده و صفحه را دوباره بارگذاری کنید، شما باید فیلد مورد نظر با نام جدید مشاهده کنید. توجه داشته باشید، در صورتیکه حرف اول نامی که انتخاب می کند حرف بزرگ نباشد جنگو به طور خودکار آن را تبدیل به حروف بزرگ می کند. در پایان، توجه داشته باشید که می توان verbos_name را به صوت یک آرگومان موضعی نیز ارسال کرد، کد زیر برابر با مثال قبلی می باشد: class Author(models.Model): first_name = models.CharField(max_length=30) last_name = models.CharField(max_length=40) email = models.EmailField('e-mail', blank=True) حرکت فوق برای فیلدهای ManyToManyField و ForeignKey کار نخواهد کرد، زیرا در این فیلدها باید اولین آرگومان یک کلاس مدل باشد. در این موارد، می بایست از verbose_name به صورت واضح استفاده کرد. کلاس های ModelAdmin مرسوم نغییراتی که تاکنون اعمال شد – blank=True، null=True و verbose_name – تغییراتی در سطح مدل بوده اند، نه تغییرات در سطح مدیر. خیلی پیش می آید که تغییرات مورد نیاز سایت مدیر در یک بخش از مدل انجام پذیرد و استفاده شوند، هیچ چیز تعیین شده ای برای مدیر وجود ندارد. گذشته از این، سایت مدیر جنگو امکانات و اختیارات قدترمندی برای سفارشی کردن نحوه ی کار سایت مدیر برای مدل خاص ارائه می کند. سفارشی کردن لیست های تغییر اجازه دهید از طریق تعیین کردن فیلدها که درون لیست تغییر برای مدل Author قرار دارند وارد مسائل سفارشی سازی مدیر شویم. به طور پیشفرض، لیست تغییر نتیجه ی __unicode__() برای هر شیء را نمایش می دهد. در آموزش مدل جنگو، متد __uncode__() برای شیء های Author جهت نمایش نام و فامیلی با هم تعریف شد. class Author(models.Model): first_name = models.CharField(max_length=30) last_name = models.CharField(max_length=40) email = models.EmailField(blank=True, verbose_name='e-mail') def __unicode__(self): return u'%s %s' % (self.first_name, self.last_name) در نتیجه لیست تغییر برای شیء های Author نام و نام خانوادگی را با هم نمایش می دهد، همانطور که در شکل 8-6 مشاهده می کنید. می توان این رفتار پیشفرض را با اضافه کردن تعدادی از فیلدها برای تغییر نمایش لیست بهبود بخشید. برای مثال، برای دیدن آدرس الکترونیک هر نویسنده در این لیست، و همچنین اضافه کردن امکان چیدمان بر اساس نام و نام خانوادگی می توان یک کلاس ModelAdmin برای مدل Author تعریف کرد. این کلاس کلید سفارشی سازی مدیر، و یکی از اولیه ترین چیزهایی است که اجازه می دهد لیست فیلدها را جهت نمایش در صفحه ی لیست تغییر تعیین کنید. فایل admin.py را جهت این تغییرات ویرایش کنید: from django.contrib import admin from mysite.books.models import Publisher, Author, Book class AuthorAdmin(admin.ModelAdmin): list_display = ('first_name', 'last_name', 'email') admin.site.register(Publisher) admin.site.register(Author, AuthorAdmin) admin.site.register(Book) در زیر مثال فوق، توضیح داده شده است: ** کلاس AuthorAdmin ساخته شده است. کلاس AuthorAdmin که از کلاس پدر خود یعنی django.admin.ModelAdmin ارث بری کرده است پیکربندی های تعیین شده برای مدل مدیر را نگه می دارد. تنها یک پیکربندی – list_display، انجام شده است که نام فیلدهایی را که قرار است درون لیست تغییر نمایش داده شوند، درون یک تاپل قرار گرفته اند. البته نام فیلدها باید در مدل وجود داشته باشند. ** فراخوانی admin.site.register با اضافه کردن AuthorAdmin بعد از Author تغییر کرده است که می توان آنرا بدین صورت خواند: "مدل Author با امکانات AuthorAdmin عضو شده است." تابع admin.site.register() کلاس فرزند ModelAdmin را به صورت اختیاری به عنوان دومین آرگومان دریافت می کند. در صورتیکه دومین آرگومان را تعیین نکنید (همانطور در مورد Publisher و Book صدق می کند)، جنگو از اختیار پیشفرض مدیر برای آن مدل استفاده می کند. با تغییرات فوق، لیست تغییر نویسنده را دوباره بارگذاری کنید، شما حالا در این صفحه سه ستون را مشاهده خواهید کرد – نام، نام خانوادگی و آدرس الکترونیک. علاوه بر آن، هر کدام از این ستون ها قابلیت چیدمان بر اساس سرتیتر ستون را با کلیک کردن رو آن خواهند داشت. در قدم بعدی اجازه دهید یک نوار جستجوی ساده اضافه کنیم. مانند زیر search_fields را به AuthorAdmin اضافه کنید: class AuthorAdmin(admin.ModelAdmin): list_display = ('first_name', 'last_name', 'email') search_fields = ('first_name', 'last_name') صفحه را درون مرورگر دوباره بارگذاری کنید، شما باید یک نوار جستجو را در قسمت بالای صفحه مشاهده کنید (شکل 10-6). در کد فوق تنها به صفحه ی تغییر گفته شده است که یک نوار جستجو برای جستجو بر حسب فیلدهای نام و نام خانوادگی ایجاد کند. همانطور که ممکن است کاربر انتظار داشته باشد، جستجو به حروف کوچک و بزرگ حساس نمی باشد و درون هر دو فیلد صورت می گیرد، بنابراین برای رشته ی "bar" هم نویسنده ای که نام وی Barney بوده را خواهد یافت و هم نویسنده ای که نام خانوادگی وی Hobarson می باشد را خواهد یافت. در قدم بعدی، اجازه دهید تعدادی فیلتر برای صفحه ی لیست تغییر مدل Book اضافه کنیم: from django.contrib import admin from mysite.books.models import Publisher, Author, Book class AuthorAdmin(admin.ModelAdmin): list_display = ('first_name', 'last_name', 'email') search_fields = ('first_name', 'last_name') class BookAdmin(admin.ModelAdmin): list_display = ('title', 'publisher', 'publication_date') list_filter = ('publication_date',) admin.site.register(Publisher) admin.site.register(Author, AuthorAdmin) admin.site.register(Book, BookAdmin) در کد فوق با آیتم های زیادی سر و کار داریم، در کد فوق یک کلاس BookAdmin از نوع ModelAdmin به طور جداگانه ساخته شده است. ابتدا، یک list_display تنها برای ایجاد لیست زیباتر تعریف شده است. سپس، از list_filter استفاده شده است، که فیلدهایی برای استفاده را درون تاپل قرار می دهد و در سمت راست صفحه ی تغییر لیست نمایش داده می شود. برای فیلدهای تاریخ، جنگو میانبرهایی را برای فیلتر لیست می کند "Today"، "Past 7 days"، "This month"و "This year". list_filter فقط محدود به DateField نمی باشد بلکه با داده های نوع دیگر نیز کار می کند. (سعی کنید با فیلدهای BooleanField و foreignKey هم کار کنید) فیلترها تا زمانیکه حداقل دو مقدار برای انتخاب فرم وجود داشته باشد نمایش داده می شوند. روش دیگربرای ارائه ی فیلترهای تاریخ استفاده از date_hierarcy مانند کد زیر می باشد: class BookAdmin(admin.ModelAdmin): list_display = ('title', 'publisher', 'publication_date') list_filter = ('publication_date',) date_hierarchy = 'publication_date' با اضافه کرد date_hierarchy صفحه ی لیست تغییر یک نوار تاریخ در بالای لیست ایجاد می شود، که در شکل 12-6 مشاهده می کنید، که با یک لیست از سال های در دسترس شروع می کند سپس می توان برای ماه حتی نمایان شدن روز بر روی آن کلیک کرد. توجه داشته باشید که date_hierarchy یک رشته دریافت می کند، نه یک تاپل، زیرا تنها یک فیلد تاریخ می تواند در آن استفاده شود. در پایان، اجازه دهید ترتیب چیدمان پیشفرض لیست را به طوری تغییر دهیم که کتاب ها در صفحه ی لیست تغییر همیشه بر اساس تاریخ به صورت نزولی قرار بگیرند. به طور پیشفرض، لیست تغییر شیء ها را بر اساس کلاس Meta مربوط به مدل مودر نظر چیده می شوند (که در آموزش مدل جنگو به آن اشاره شده است.) – ولی شما این مقدار مرتب کردن را تعیین نکرده اید، پس ترتیب تعریف نشده است. class BookAdmin(admin.ModelAdmin): list_display = ('title', 'publisher', 'publication_date') list_filter = ('publication_date',) date_hierarchy = 'publication_date' ordering = ('-publication_date',) این اختیار چیدمان مدیر دقیقا به صورت چیدمان در کلاس Meta کار می کند، با این تفاوت که آن تنها از اولین فیلد نام در لیست استفاده می کند. تنها یک لیست یا تاپل از نام فیلدها به آن ارسال کنید و یک علامت (-) در ابتدای فیلد برای چیدمان نزولی آن قرار دهید. صفحه ی لیست تغییر را برای مشاهده ی حرکت فوق دوباره بارگذاری کنید. توجه داشته باشید که تیتر "Publication date" حالا شامل یک فلش کوچک می باشد که به نحوه ی چیدمان اشاره می کند. اختیارات اصلی لیست تغییر در اینجا توضیح داده شد. با استفاده از این اختیارات می توانید با قدرت تر کار کنید، با استفاده از تنها چند خط می توانید از یک رابط آماده و پر قدرت استفاده کنید. سفارشی کردن فرم های ویرایش همانطور که لیست تغییر می تواند سفارشی شده باشد، فرم های ویرایش نیز می توانند با روش های مختلف سفارشی شوند. ابتدا اجازه دهید روش چیده شدن فیلدها را سفارشی کنیم. به طور پیشفرض، ترتیب فیلدها در یک فرم ویرایش مطابق با ترتیبی است که آنها در مدل تعریف شده اند. می توان با استفاده از اختیار fields در کلاس فرزند ModelAdmin آن را تغییر داد: class BookAdmin(admin.ModelAdmin): list_display = ('title', 'publisher', 'publication_date') list_filter = ('publication_date',) date_hierarchy = 'publication_date' ordering = ('-publication_date',) fields = ('title', 'authors', 'publisher', 'publication_date') بعد از تغییر فوق، فرم ویرایش برای کتاب ها از ترتیب داده شده برای فیلدها استفاده خواهد کرد. این که نویسنده بعد از عنوان کتاب قرار بگیرد کمی طبیعی تر می باشد. البته، ترتیب فیلد باید بسته به به اطلاعات ورودی جریان کار باشد. هر فرم متفاوت است. نکته ی دیگر مفید در اختیار fields این است که اجازه می دهد بعضی فیلد ها را از قرار داشتن در فرم ویرایش کلا محروم کرد. تنها کافیست، فیلدهایی که نمی خواهید در فرم باشند را درون تاپل قرار ندهید. ممکن است از این امکان هنگامی که کاربران مدیر تنها برای ویرایش بعضی از بخش ها مورد اعتماد هستند استفاده کنید. برای مثال، در پایگاده داده ی کتاب ما، فیلد publication_date از حالت قابل ویرایش بودن خارج و مخفی شده است: class BookAdmin(admin.ModelAdmin): list_display = ('title', 'publisher', 'publication_date') list_filter = ('publication_date',) date_hierarchy = 'publication_date' ordering = ('-publication_date',) fields = ('title', 'authors', 'publisher') نتیجتا، فرم ویرایش برای کتاب ها هیچ روشی برای تعیین publication date ارائه نمی کند. این حرکت می تواند در صورتیکه یک ویرایشگر ترجیح می دهد نویسندگانش تاریخ را عقب نزنند مفید باشد. هنگامی که یک کاربر از این فرم برای اضافه کردن یک کتاب جدید استفاده می کند، جنگو به آسانی مقدار publication_date را None در نظر می گیرد – بنابراین اطمینان حاصل کنید که فیلد مورد نظر دارای null=True می باشد. استفاده ی عمومی دیگر فرم ویرایش سفارشی برای کار با فیلدهای چند به چند می باشد. همانطور که در فرم ویرایش برای کتاب ها مشاهده کردید، سایت مدیر هر ManyToManyField را به صورت یک جعبه ی چند انتخابه نمایش می دهد، که منطقی ترین راه برای ورودی HTML برای استفاده می باشد – ولی استفاده از جعبه های چند انتخابه می تواند کمی سخت باشد. در صورتیکه که می خواهید چند ایتم را انتخاب کنید، باید برای انجام چنین کاری کلید control و یا در Mac کلید command را نگه پایین نگه داشته و آن ها را انتخاب کنید. سایت مدیر برای این مشکل یک توضیحی را در زیر این فیلد قرار داده است، ولی هنوز هم دارای مشکلاتی می باشد مخصوصا زمانی که فیلد شما حاوی صدها انتخاب باشد. راه حل سایت مدیر filter_horizontal می باشد. آنرا به BookAdmin اضافه کرده و نتیجه را مشاهده کنید: class BookAdmin(admin.ModelAdmin): list_display = ('title', 'publisher', 'publication_date') list_filter = ('publication_date',) date_hierarchy = 'publication_date' ordering = ('-publication_date',) filter_horizontal = ('authors',) فرم ویرایش برای کتاب ها را دوباره بارگذاری کنید، بخش "Authors" حالا از یک رابط جاوا اسکریپت کاراتر استفاده می کند که می توان به راحتی درون انتخاب ها جستجو کردن و هر آنچه را که درون "Available authors" انتخاب می کنید را به درون "Chosen authors" و بر عکس ارسال می کند. اکیدا توصیه می شود که برای فیلدهای ManyToManyField که بیشتر از 10 ایتم دارند از filter_horizontal استفاده کنید. روش فوق بسیار آسانتر از استفاده از جعبه ی چند انتخابه می باشد. توجه داشته باشید که همچنین می توان برای چندین فیلد نیز از filter_horizontal استفاده کرد – تنها کافیست نام هر کدام را درون تاپل قرار دهید. کلاس های ModelAdmin همچنین از filter_vertical که تنها در فیلدهای ManyToManyField و نه ForeignKey کار می کند نیز پشتیبانی می کنند، به طور پیشفرض، سایت مدیر برای فیلدهای ForeignKey به سادگی از <select> استفاده می کند، ولی همانطور که برای ManyToManyField نیز از <select> استفاده می شود، ممکن است شما مایل نباشید برای نمایش تمام شیء ها به صورت منوی باز شونده در پایین بار اضافی ای را متحمل شوید. برای مثال در صورتیکه پایگاه داده ی کتاب حاوی صدها ناشر شده باشد، فرم "Add book" مدتی برای بارگذاری زمان خواهد برد، زیرا باید تمام ناشران را برای نمایش در <select> بارگذاری کند. برای حل این مشکل می بایست از raw_id_fields استفاده کرد. نام فیلد ForeignKey را درون این تاپل قرار دهید، فیلدهای مذکور به جای <select> به صورت یک متن ساده نمایش داده می شوند (<input type="text") class BookAdmin(admin.ModelAdmin): list_display = ('title', 'publisher', 'publication_date') list_filter = ('publication_date',) date_hierarchy = 'publication_date' ordering = ('-publication_date',) filter_horizontal = ('authors',) raw_id_fields = ('publisher',) درون جعبه ی ورودی چه چیزی وارد می کنید؟ ID مربوط به پایگاه داده ی ناشر. نمی توان به طور عادی ID هر شخص را به خاطر سپرد، به همین دلیل یک شکل ذره بین نیز در شکل فوق مشاهده می کنید که می توان با کلیک بر روی آن توسط یک پنجره ی pop-up ناشران را که می خواهید اضافه کنید. کاربران، گروه ها و حق دسترسی ها بدلیل اینکه با یک superuser وارد می شویم، می توان برای ساختن، ویرایش و حذف کردن هر شیء اقدام کرد. به طور طبیعی، محیط های مختلف نیازمند حق دسترسی های متفاوتی می باشد – بدین صورت نباید باشد که هر شخصی بتواند superuser باشد. سایت مدیر جنگو یک سیستم حق دسترسی را بکاربرده است که می توان برای دادن دسترسی به کاربران خاص برای بخش هایی ار رابط که مورد نیاز است استفاده کرد. همانطور که در اوایل فصل مشاهده کردیم می توان کاربران و حق دسترسی ها را از طریق رابط مدیر همانند دیگر شیء ها ویرایش کرد. شیء های کاربر دارای فیلد های استاندارد نام کاربری، رمز عبور، آدرس پست الکترونیک و نام واقعی به همراه یک مجموعه از فیلد ها که اختیارات کاربر را در درون رابط مدیر تعیین می کند، می باشد. در ابتدا، سه گزینه ی boolean وجود دارد: ** گزینه ی "active" کنترل می کند که ایا کاربر فعال است یا خیر. در صورتیکه این گزینه تیک نخورده باشد و کاربر سعی کند وارد شود، به وی اجازه ی ورود داده نمی شود حتی اگر رمز عبور وی معتبر باشد. ** گزینه ی "staff" کنترل می کند که ایا کاربر اجازه ی ورود به رابط مدیر را دارد یا خیر (مانند اینکه ایا کاربر مورد نظر به عنوان یکی از کارمندان شرکت در نظر گرفته شده است یا خیر). ** گزینه ی "superuser" به کاربر دسترسی کامل را برای اضافه، ساختن و حذف کردن هر ایتم در رابط مدیر را می دهد. در صورتیکه یک کاربر این گزینه را داشته باشد، در آن صورت تمام قوانین دسترسی برای آن کاربر نقض خواهد شد. کاربران مدیر "Normal"، کاربر superuser نیستند بلکه دارای دسترسی مدیر از طریق دسترسی های اختصاص داده شده به آنها می باشند که می تواند شامل محدودیت های دسترسی باشد. هر شیء قابل ویرایش از طریق رابط مدیر (مانند کتاب ها، نویسندگان، ناشران) دارای سه حق دسترسی می باشد: حق دسترسی ساخت، حق دسترسی ویرایش و حق دسترسی حذف. اختصاص دادن حق دسترسی ها به یک کاربر، محدوده اختیارات آن کاربر را برای ایجاد، حذف و یا اعمال تغییرات تعیین می کند. زمانیکه یک کاربر می سازید، کاربر ساخته شده هیچ حق دسترسی ای ندارد، و برای دادن حق دسترسی های خاص حاضر می باشد. برای مثال، شما می توانید حق دسترسی ای برای تغیییر ناشران به آن بدهید، ولی حق حذف کردن ناشران را به کاربر ندهید. توجه داشته باشید که این حق دسترسی ها برای هر مدل تعریف شده می باشند و نه برای هر شیء، بنابراین شما می توانید اینطور بگویید که "john می تواند روی هر کتاب تغییر ایجاد کند"، ولی نمی توان گفت "john می تواند بر روی هر کتابی که با Apress منتشر شده است تغییرات ایجاد کند." قابلیت دوم، حق دسترسی های هر شیء می باشد که کمی پیچیده تر بوده و خارج از حوصله ی این کتاب می باشد ولی در مستندات جنگو درباره ی آن صحبت شده است. نکته : دسترسی به ویرایش کاربران و حق دسترسی ها نیز از طریق سیستم حق دسترسی کنترل شده است. در صورتیکه به شخصی حق دسترسی برای ویرایش کاربران را بدهید، آن شخص قادر به ویرایش حق دسترسی های خود می باشد که این ممکن است آن چیزی نباشد که شما می خواهید! دادن حق دسترسی کاربر برای ویرایش کاربران اساسا تغییر کاربر به superuser می باشد. همچنین می توان کاربران را به گروه ها اختصاص داد. گروه مجموع ای از حق دسترسی هایی می باشد که برای تمام اعضای آن گروه بکار برده می شود. گروه ها برای دادن حق دسترسی های یکسان به زیرمجموعه ای از کاربران مفید می باشد. چه زمانی و به چه دلیل از رابط مدیر استفاده می شود و چه زمانی استفاده نمی شود بعد از آشنایی و کار در این فصل، شما باید یک ایده ی خوب در مورد نحوه ی استفاده از سایت مدیر جنگو داشته باشید. ولی می خواهیم در اینجا چند موضوع را باز کنید و آن هم این است که چرا و کی باید از سایت مدیر جنگو استفاده کرد و چه زمانی نباید از آن استفاده کرد. سایت مدیر جنگو زمانی بسیار پر ارزش می شود که کاربران غیر فنی به وارد کردن داده نیاز داشته باشند، در روزنامه جایی که جنگو اولین توسعه را در آنجا پیدا کرد یک گزارش ویژه در مورد کیفیت آب شهری که چیزی شبیه به مراحل زیر بود، ارائه شده بود: ** گزارشگر مسئولیت داشت برای پروژه با یکی از توسعه دهندگان ملاقات کند و داده ی در دسترس را توضیح دهد. ** توسعه دهنده مدل های جنگو را برای متناسب بودن با آن داده ها طراحی کرده سپس سایت مدیر را برای گزارشگر باز می کرد. ** گزارشگر سایت مدیر را بررسی کرده و کمبود ها و فیلدهای غیر اصلی را به آن اشاره می کرد، توسعه دهنده مکررا مدل ها را تغییر می داد. ** هنگامی که مدل ها مورد توافق قرار گرفت، گزارشگر شروع به وارد کردن داده با استفاده از سایت مدیر می کرد. هم زمان، برنامه نویس می تواند روی توسعه ی عمومی قسمت های views و template ها کار کند (قسمت جالب کار). ورای وظایف واضح برای وارد کردن داده، سایت مدیر در موارد دیگر که در زیر آمده است نیز مفید می باشد: ** بررسی کردن داده ی مدل ها: هنگامی که تعدادی مدل تعریف می کنید، فراخوانی آن ها در رابط مدیر و وارد کردن برخی داده های ساختگی می تواند کاملا مفید باشد. در برخی موارد، می تواند باعث آشکار شدن اشتباهات data-modeling و یا مشکلات دیگر با مدل های شما شود. ** مدیریت داده ی بدست آمده: برای برنامه هایی که بر روی آمدن داده از منابع بیرونی تکیه دارند، سایت مدیر روشی ساده برای بازرسی یا ویرایش این داده ها به شما می دهد. ممکن است آن را کم قدرت تصور کنید، ولی بسیار مناسب تر از امکان خط فرمان پایگاه داده ی شما می باشد. ** مدیریت داده ی app ها به صورت سریع: می توان برای ساخت مدیریت داده ی بسیار سبک app از سایت مدیر استفاده کرد. در صورتیکه که تنها می خواهید برای نیازهای خود چیزی بسازید، نه برای مصارف عمومی، سایت مدیر می تواند راه مناسبی باشد. یک نکته ی پایانی اینکه می خواهیم واضح باشد: سایت مدیر برای همه وقت و همه چیز نیست. سایت مدیر برای یک رابط عمومی بودن در نظر گرفته نشده است، همچنین برای چیدمان و جستجوی پیچیده ی داده ها نیز در نظر گرفته نشده است. همانطور پیش تر در این فصل گفته شد، سایت مدیر برای مدیران مورد اعتماد سایت می باشد. خسته نباشید دوستان عزیز . جلسه ششم بخش دوم کتاب جنگو به پایان رسید . امیدوارم که موفق باشید . ترجمه از سایت www.djangobook.com
  5. آموزش سایت مدیرت پیشفرض در جنگو ( بخش اول ) برای طبقه ی خاصی از وب سایت ها، یک رابط مدیر (admin interface) بخشی ضروری زیر ساخت وب سایت می باشد. رابط مدیر یک رابط تحت وب می باشد، که مختص مدیران مورد اعتماد سایت می باشد و اضافه کردن، ویرایش و حذف محتویات سایت را مقدور می سازد. رابطی که شما برای پست کردن به بلاگ خود از آن استفاده می کنید، ابزاری که کاربران برای به روز رسانی مطالبی که برای آن ها ساخته اید به کار می برند و محیطی که مدیران سایت برای اداره ی نقطه نظرات کاربران از آن استفاده می کنند مثال هایی برای استفاده از رابط مدیر می باشند. توسعه ی وب هنگامی که با عملکرد برنامه رو به رو هستید کاری جالب می باشد در صورتیکه ساختن رابط مدیر همواره به یک شکل است. باید به کاربران اجازه دسترسی بدهید، فرم ها را نمایش داده و کنترل کنید، ورودی را معتبر سازید و غیره. این ها کارهایی خسته کننده و تکراری می باشند. بنابراین روش جنگو برای این مسائل خسته کننده و تکراری چه می باشد؟ جنگو تنها با چند خط نه بیشتر تمام این کارها را برای شما انجام می دهد. با ساختن رابط مدیر جنگو تمام این مشکلات حل خواهد شد. این فصل درباره ی رابط خودکار مدیر می باشد. ویژگی ای که از طریق خواندن داده های موجود در مدل یک رابط پر قدرت که مدیران سایت می توانند به سرعت از آن استفاده کنند را تهیه می کند. در اینجا نحوه ی فعال کردن و سفارشی کردن این ویژگی را مورد بررسی قرار خواهیم داد. توجه داشته باشید که توصیه می کنیم حتی اگر قصد استفاده از رابط مدیر را ندارید این فصل را مطالعه کنید، زیرا در این فصل صرفنظر از کاربرد سایت مدیر، مفاهیمی معرفی خواهند شد که در تمام جنگو بکار می روند. پکیج های django.contrib مدیر خودکار جنگو بخشی از یک سلسله از عملکرد جنگو می باشد که django.contrib نامیده می شود (بخشی از کد جنگو که حاوی افزودنی های مفید برای هسته فریم ورک می باشد). می توانید django.contrib در جنگو را معادل کتابخانه ی استاندار پایتون فرض کنید. این پکیج ها به وسیله ی جنگو جمع آوری و تدوین شده اند، به طوری که نیازی به دوباره نویسی برخی از اصول در برنامه ها نمی باشد. سایت مدیر اولین بخش از django.contrib می باشد که در این کتاب پوشش داده شده است که از نظر فنی، django.contrib.admin نامیده می شود. از خصوصیات دیگر قابل استفاده درون django.contrib می توان سیستم حق دسترسی (django.contrib.auth)، سیستم پشتیبانی از session ها (django.contrib.sessions) و حتی یک سیستم برای نقطه نظرات کاربر (django.contrib.comments)را نام برد. شما خصوصیات مختلف django.contrib را به صورت فردی حرفه ای در جنگو فرا خواهید گرفت، زمان زیادی را در پکیج django.contrib برای بحث در مورد این خصوصیات خواهیم گذاشت. فعال کردن دسترسی مدیر سایت مدیر جنگو به صورت کلی اختیاری می باشد، زیرا بعضی از سایت ها نیاز به این عملکرد دارند. این بدان معناست که نیاز خواهید داشت جند قدمی را برای فعال کردن آن در پروژه ی خود بردارید. ابتدا، چند تغییر در فایل تنظیمات انجام دهید: ** django.contrib.admin را به تنظیم INSTALLED_APPS اضافه کنید. (ترتیب قرارگیری محتویات INSTALLED_APPS اهمیت ندارد، ولی در این کتاب برای خوانایی بیشتر آن ها را بر اساس حروف الفبا مرتب کرده ایم.) ** اطمینان حاصل کنید که INSTALLED_APPS حاوی 'django.contrib.auth'، 'django.contrib.contenttypes' و 'django.contrib.sessions' می باشد. سایت مدیر جنگو به این سه پکیج نیاز دارد. (در صورتیکه همزمان با تمرینات کتاب یعنی پروژه ی mysite پیش می روید، توجه داشته باشید که در آموزش مدل جنگو این سه پکیج را کامنت کردیم. همین حالا آن ها را از حالت کامنت خارج کنید.) ** اطمینان حاصل کنید که MIDDLEWARE_CLASSES حاوی 'django.middleware.common.CommonMiddleware'، 'django.contrib.sessions.middleware.SessionMiddleware' و 'django.contrib.auth.middleware.AuthenticationMiddleware' می باشد (دوباره، در صورتیکه همزمان با تمرینات کتاب پیش می روید، توجه داشته باشید که در آموزش مدل جنگو ایتم های فوق کامنت شده اند، پس آن ها را از حالت کامنت خارج کنید.) --- در قدم دوم، دستور python manage.py syncdb را اجرا کنید. دستور فوق جداول پایگاه داده اضافه که رابط مدیر از آنها استفاده می کند را نصب می کند. در اولین باری که دستور sycdb را به 'django.contrib.auth' درون INSTALLED_APPS اجرا می کنید، سوالی مبنی درباره ی ساختن یک superuser از شما پرسیده می شود. در صورتیکه آن را انجام ندهید، نیاز است که دستور python manage.py createsuperuser را به طور جداگانه برای ساختن یک حساب کاربری مدیر اجرا کنید، در غیر اینصورت قادر نخواهید بود به سایت مدیر وارد شوید. (نکته ی مهم: دستور python manage.py createsuperuser تنها زمانی در دسترس خواهد بود که 'django.contrib.auth' درون تنظیم INSTALLED_APPS موجود باشد.) --- قدم سوم، اضافه کردن سایت مدیر به URLconf (درون فایل urls.py) می باشد. به صورت پیشفرض، urls.py تولید شده توسط django-admin.py startproject حاوی کدهای کامنت شده ای برای مدیر جنگو می باشد و تمام کاری که شما باید انجام دهید خارج کردن آن کدها از حالت کامنت می باشد. چیزی شبیه به کد زیر لازم است: # Include these import statements... from django.contrib import admin admin.autodiscover() # And include this URLpattern... urlpatterns = patterns('', # ... (r'^admin/', include(admin.site.urls)), # ... ) با اضافه کردن سایت مدیر به URLconf، حالا می توان سایت مدیر جنگو را در عمل مشاهده کرد. تنها کافیست سرور جنگو را اجرا کرده (python manage.py runserver) و نشانی http://127.0.0.1:8000/admin/ را درون مرورگر جستجو کنید. استفاده از سایت مدیر سایت مدیر برای استفاده ی کاربران غیر فنی طراحی شده است، و به همین دلیل می بایست بسیار واضح باشد. با این وجود، ویژگی های اولیه آن را به صورت سریع به شما نشان خواهیم کرد. اولین چیزی که شما مشاهده خواهید کرد صفحه ی ورود مانند شکل 1-6 می باشد : با نام کاربری و رمز عبوری که در زمان اضافه کردن superuser ساخته اید وارد شوید. در صورتیکه قادر به وارد شدن نیستید، اطمینان حاصل کنید که واقعا یک superuser ساخته اید (سعی کنید دستور python manage.py createsuperuser را اجرا کنید.) هنگامی که وارد شدید، اولین چیزی که مشاهده خواهید کرد صفحه ی خانگی مدیر می باشد. این صفحه تمامی نوع داده هایی که می توان ویرایش کرد را درون سایت مدیر لیست می کند. در حال حاضر، به دلیل آنکه هنوز هیچ مدل فعالی وجود ندارد، لیست کمی خالی می باشد: تنها Groups و Users وجود دارند که مدل های پیشفرض قابل ویرایش مدیر می باشند. هر نوعی از داده در سایت مدیر جنگو دارای یک change list و یک edit form می باشد. change list ها تمام شیء های در دسترس درون پایگاه داده را نشان می دهند، و edit form ها، اجازه ی اضافه کردن تغییر دادن و یا حذف رکورد های مشخص در پایگاه داده را به شما می دهند. زبان های دیگر در صورتیکه زبان اصلی شما زبان انگلیسی نمی باشد و مرورگر شما برای یک زبان دیگری به جز زبان انگلیسی تنظیم شده است، می توانید با یک تغییر سریع همه چیز را درون سایت مدیر جنگو به صورت ترجمه شده به زبان مورد دلخواه مشاهده کنید. تنها کافیست 'django.middleware.locale.localeMiddleware' را به تنظیم MIDDLEWARE_CLASSES اضافه کنید، اطمینان حاصل کنید که آن را بعد از 'django.contrib.sessions.middleware.SessionMiddleware' قرار دهید. هنگامی که تنظیم فوق انجام داده شد، صفحه ی اصلی مدیر را دوباره بارگذاری کنید. در صورتیکه یک ترجمه برای زبان شما در دسترس باشد، بخش های مختلف از رابط مانند لینک های "Change password" و "Log out" در بالای صفحه و لینک های "Groups" و "Users" در وسط صفحه به زبان مورد نظر ترجمه خواهند شد. جنگو با ترجمه ی ده ها زبان ارائه شده است. برای خصوصیات بیشتر بین المللی جنگو، به آموزش بین المللی سازی جنگو مراجعه کنید. برای بار گذاری صفحه ی change list برای کاربران بر روی لینک "Change" در ردیف "Users" کلیک کنید. خسته نباشید دوستان عزیز . جلسه ششم بخش اول کتاب جنگو به پایان رسید . امیدوارم که موفق باشید . ترجمه از سایت www.djangobook.com
  6. این تاپیک پشتیبانی برای آموزش است آموزش ایجاد پنل مدیریت در جنگو ( جلسه ششم ) - بخش اول 12/04/96 10:29 12/04/96 10:43 لطفا اگرهر سوال یا بازخوردی دارید اینجا ارسال کنید.
  7. در view و urlconf دیدیم که کد HTML را می توانیم به صورت یک متن به طور مستقیم درون view بگنجانیم: def current_datetime(request): now = datetime.datetime.now() html = "<html><body>It is now %s.</body></html>" % now return HttpResponse(html) یکی از معایب روش بالا این است که برای هرگونه اعمال تغییر در طراحی صفحه نیازمند تغییر در کد پایتون می باشیم. می دانیم که طراحی سایت نیازمند تغییرات متعددی است در نتیجه استفاده از این روش موجب تغییر به مراتب بیشتر کد پایتون می باشد. بنابراین مناسب تر آن است که طراحی صفحه و ایجاد تغییرات در آن، نیازی به اصلاح و تغییر کد پایتون نداشته باشد. نوشتن کد پایتون و طراحی HTML دو موضوع متفاوت از یکدیگر بوده و نظم و قانون مربوط به خود را دارند، و بیشتر محیط های توسعه ی وب حرفه ای این مسئولیت ها را جدا کرده و به افراد جدا (حتی به بخش و حوزه ی جدا) واگذار می کنند. طراحان و کد نویسان HTML/CSS نباید نیاز به ویرایش کد پایتون برای کار خود داشته باشند. اگر طراحان بتوانند بر روی کدهای html در همان زمان که برنامه نویسان در حال کار با کدهای پایتون هستند، کار کنند. بهترین بهره وری از کار را خواهیم داشت زیرا دیگر نیازی نیست که یک فرد منتظر تمام کردن کد توسط فردی دیگر باشد چرا که در یک فایل کد HTML و کد پایتون هر دو به صورت جداگانه وجود دارد. این حالت را (که کد HTML به طور مستقیم درون view قرار بگیرد) به اصطلاح hard-code می نامند، بدین معنا که کد HTML به صورت غیر مستقل داخل کد پایتون قرار دارد و تغییر آن کار ساده ای نخواهد بود. اگرچه تکنیک فوق برای توضیح و یا شرح نحوه ی کارکرد view در فصل قبلی مناسب به نظر می آید، اما به دلایل ذکر شده در بالا این ایده ی خوبی نیست که کد HTML به صورت hard-code به طور مستقیم درون view قرار گیرد. همانطور که ذکر کردیم جدا کردن طراحی صفحه از کد پایتون مربوط به آن بسیار واضح و منطقی است. با استفاده از سیستم template جنگو می توانیم کدهای مربوط به HTML را از کد پایتون جداسازی کنیم، که در این فصل به این موضوع خواهیم پرداخت. قواعد Template System template جنگو یک رشته ای از متن می باشد که برای جدا کردن نمایش یک سند از داده ی خود در نظر گرفته شده است. قالب حفره ها و تکه کدهای (تگ های template) مختلفی را تعریف می کند که نحوه ای که سند باید نمایش داده شود را تنظیم می کند. به طور معمول template ها برای تولید HTML استفاده می شوند، اما template های جنگو به همان اندازه در تولید هر فرمت متنی توانا هستند. بیایید با یک مثال ساده شروع کرده و آن را مورد بررسی قرار دهیم: <html> <head><title>Ordering notice</title></head> <body> <h1>Ordering notice</h1> <p>Dear {{ person_name }},</p> <p>Thanks for placing an order from {{ company }}. It's scheduled to ship on {{ ship_date|date:"F j, Y" }}.</p> <p>Here are the items you've ordered:</p> <ul> {% for item in item_list %} <li>{{ item }}</li> {% endfor %} </ul> {% if ordered_warranty %} <p>Your warranty information will be included in the packaging.</p> {% else %} <p>You didn't order a warranty, so you're on your own when the products inevitably stop working.</p> {% endif %} <p>Sincerely,<br />{{ company }}</p> </body> </html> template فوق یک HTML بنیادی با برخی متغیرها و تگ های template استفاده شده در آن می باشد. بیایید template فوق را مورد بررسی قرار دهیم. هر متنی که داخل دو آکولاد قرار گرفته باشد (مانند {{ person_name }}) یک متغیر است. این بدین معنی می باشد که "مقدار ارزش متغیر با نام داده شده را درج کند" به عبارت دیگر اگر (person_name) داخل آکولاد قرار نگیرد خروجی Dear person_name را درج خواهد کرد و نام شخص را به ما نشان نمی دهد. (چطور ارزش متغیرها را می توان تعیین کرد؟ در این فصل خواهید فهمید.) هر متنی که داخل یک آکولاد و علامت درصد قرار بگیرد (مانند {% if ordered_warranty %}) یک تگ template می باشد. تعریف یک تگ بسیار وسیع می باشد: تگ به template می گوید که "کاری را انجام بده". مثال template فوق حاوی یک تگ for ({% for item in item_list %}) و یک تگ if ({% if ordered_warranty %}) می باشد. تگ for بسیار شبیه به عبارت for در پایتون می باشد، که به ما اجازه می دهد درون سرتاسر آیتم های یک لیست به ترتیب بگردید و یا تغییراتی را بر روی همه یا یک سری از آیتم ها اعمال کنیم. تگ if همانطور که انتظار آن می رود، به صورت یک عبارت if منطقی عمل می کند. در این مورد خاص، تگ مورد نظر بررسی می کند که آیا ارزش متغیر ordered_warranty ،True می باشد یا خیر. اگر بدین صورت بود یعنی اگر مقدار آن True بود، سیستم template جنگو هر آنچه که بین {% if ordered_warranty %} و {% else %} باشد را نمایش خواهد داد، در غیر اینصورت سیستم template جنگو هر آنچه را که بین {% else %} و {% endif %} باشد را نمایش خواهد داد. توجه داشته باشید که تک {% else %} کاملا اختیاری می باشد. نهایتا، پاراگراف دوم template فوق حاوی یک مثال از filter می باشد، که مناسب ترین روش برای تغییر قالب بندی (formatting) یک متغیر می باشد. در این مثال، {{ ship_date|date:"F j, Y" }}، متغیر ship_date به فیلتر date ارسال شده، و آرگومان "F j, Y" نیز به فیلتر date داده شده است. فیلتر date تاریخ را بر اساس آرگومان تغیین شده قالب بندی می کند. فیلترها با استفاده از علامت (|) مربوط می شوند، همانند کاربرد آن در یونیکس. هر قالب جنگو به چندین تگ و فیلتر داخلی (built-in) دسترسی دارد، تعدادی از آن ها در ادامه فصل های کتاب مورد بحث قرار خواهند گرفت. همچنین این امکان وجود دارد که فیلتر و تگ برای خودتان ایجاد کنید؛ که در آموزش template پیشرفته این کتاب بیان خواهد شد. استفاده از template جنگو بیایید وارد بحث template جنگو شویم، تا شما نحوه ی کارکرد آن را مشاهده کنید، ولی هنوز نمی خواهیم قالب جنگو را با view هایی که در فصل گذشته ساخته شد به هم مرتبط کنیم. هدف در اینجا این است که با نحوه ی کار template جنگو، مستقل از دیگر بخش ها آشنا شوید. (به عبارت دیگر: به طور معمول شما template جنگو را همراه با یک view استفاده خواهید کرد، ولی می خواهیم این موضوع را روشن کنیم که template جنگو تنها کتابخانه ی پایتون می باشد که شما می توانید آن را در هرجایی استفاده کنید، نه فقط در view های جنگو.) در اینجا ابتدایی ترین راه که می تونید قالب جنگو را در کد پایتون استفاده کنید آمده است: ساختن شیء Template از طریق ایجاد کد قالب به صورت رشته. فراخوانی متد render() از شیء Template با دادن یک مجموعه ای از متغیرها (the context). این متد قالب را به صورت رشته ی کامل با تمام متغیرها و تگ های قالب بر می گرداند. به کد زیر توجه کنید: >>> from django import template >>> t = template.Template('My name is {{ name }}.') >>> c = template.Context({'name': 'Adrian'}) >>> print t.render(c) My name is Adrian. >>> c = template.Context({'name': 'Fred'}) >>> print t.render(c) My name is Fred. در بخش بعدی جزئیات هر خط از کد بالا شرح داده خواهد شد. ساختن شیء های template ساده ترین راه برای ساختن شیء Template به طور مستقیم به عنوان نمونه ذکر کردن آن می باشد. کلاس Template درون ماژول django.template می باشد و سازنده ی (cunstructor) آن یک آرگومان دریافت می کند که کد خام template می باشد. بیایید نمونه آن را درون interactive interpreter پایتون مشاهده کنیم. درون دایرکتوری mysite ساخته شده توسط دستور django-admin.py startproject (بیان شده در شروع کار جنگو)، دستور python manage.py shell را تایپ کرده و interactive interpreter را باز کنید. خط فرمان ویژه ی پایتون در صورتیکه در گذشته از پایتون استفاده کرده باشید، ممکن است متعجب شوید که چرا بجای فرمان python، از فرمان python manage.py shell استفاده شده است. هر دو فرمان باعث باز شدن interactive interpreter خواهد شد، با این تفاوت که دستور manage.py shell قبل از آغاز شدن interpreter، به جنگو اعلام می کند که از کدام فایل تنظیمات استفاده کند. بسیاری از قسمت ها در جنگو، حاوی سیستم template می باشد، که شما قادر به استفاده از آن ها نخواهید بود مگر آنکه فریم ورک بداند از کدام تنظیمات استفاده کند. اگر در مورد نحوه ی انجام کار فوق کنجکاو هستید، در اینجا توضیح نحوه ی عملکرد آن در پشت صحنه، وجود دارد. جنگو به دنبال یک متغیر محیطی با نام DJANGO_SETTINGS_MODULE می گردد که باید در مسیر import فایل settings.py شما قرار گرفته باشد. به عنوان مثال، با فرض اینکه mysite مسیر پایتون شما می باشد، DJANGO_SETTINGS_MODULE ممکن است در 'mysite.settings'، قرار گرفته باشد. هنگامی که شما فرمان python manage.py shell را اجرا می کنید، فرمان مذکور به DJANGO_SETTINGS_MODULE توجه می کند. شما را تشویق می کنیم برای به حداقل رساندن پیچیدگی و تنظیماتی که باید انجام دهید از python manage.py shell در این مثال ها استفاده کنید هنگامی که با جنگو بیشتر آشنا شوید، احتمالا استفاده از manage.py shell را کنار گذاشته و خودتان به صورت دستی DJANGO_SETTINGS_MODULE را در .bash_profile یا محیط های دیگر تنظیم خواهید داد. اجازه دهید با اصول اولیه سیستم template جنگو آشنا شویم: >>> from django.template import Template >>> t = Template('My name is {{ name }}.') >>> print t با وارد کردن کد فوق، چیزی شبیه به این مشاهده خواهید کرد: <django.template.Template object at 0xb7d5f24c> عبارت 0xb7d5f24c هویت شیء پایتون می باشد که در هر زمان متفاوت می باشد واز حیطه بحث ما خارج می باشد. هنگامی که یک شیء Template ایجاد می کنید، سیستم template جنگو کد template را به صورت داخلی کامپایل می کند، و شکل بهینه آن برای ارائه دادن (rendering) آماده می شود، اما در صورتیکه کد template شما دارای اشکال باشد، فراخوانی Template() موجب بروز خطا خواهد شد: >>> from django.template import Template >>> t = Template('{% notatag %}') Traceback (most recent call last): File "<stdin>", line 1, in ? ... django.template.TemplateSyntaxError: Invalid block tag: 'notatag' در موارد زیر خطای TemplateSyntaxError رخ خواهد داد: تگ های نا معتبر آرگومان های نا معتبر درون تگ های معتبر فیلترهای نا معتبر آرگومان های نا معتبر درون فیلترهای معتبر کد template نا معتبر تگ های بسته نشده (تگ های for باید بسته شوند) ارائه دادن (rendering) یک Template هنگامی که شما یک شیء Template دارید، می توانید از طریق یک context به آن داده ارسال کنید. context مجموعه ای از نام متغیرهای template و ارزش های آن ها می باشد. Template با استفاده از context متغیرهای خودش را با ارزش مورد نظر جایگزین کرده و تگ ها را نیز اجرا می کند. context با کلاس Context در جنگو نشان داده می شود، که درون ماژول django.template قرار دارد. سازنده ی آن یک آرگومان اختیاری دریافت می کند: یک دیکشنری نام های متغیر و ارزش های آن. برای پر کردن template متد render() شیء Template را با context فراخوانی می کنیم: >>> from django.template import Context, Template >>> t = Template('My name is {{ name }}.') >>> c = Context({'name': 'Stephane'}) >>> t.render(c) u'My name is Stephane.' نکته ای که باید در اینجا اشاره کنیم این است که مقدار برگشتی (t.render(c یک رشته ی معمولی پایتون نمی باشد، بلکه یک شیء یونیکد است. که با نمایش حرف u در ابتدای آن نشان داده می شود. جنگو در سراسر فریم ورک به جای رشته ی معمولی پایتون از شیء های یونیکد استفاده می کند. پشتیبانی یونیکد جنگو نسبتااز طیف گسترده ای از حروف برای برنامه های شما بدون زحمت و دردسر پشتیبانی می کند. دیکشنری ها و context ها دیکشنری پایتون یک رابطه ی بین کلید ها و ارزش های متغیر می باشد. یک context همانند یک دیکشنری می باشد، با این تفاوت که حالت تابعی به خود گرفته است و در آموزش template پیشرفته مورد بحث قرار خواهد گرفت. نام متغیرها باید با حروف الفبای انگلیسی شروع شوند (A-Z or a-z) و می توانند حاوی حروف الفبا، عدد، خط تیره (_) و نقطه باشند (نقطه ها مورد ویژه ای هستند که بعدا راجع به آن صحبت خواهیم کرد.)، همچنین نام متغیرها به حروف کوچک و بزرگ حساس می باشند. در اینجا یک مثال از کامپایل template و rendering آن شبیه به مثالی که در ابتدای فصل مشاهده کردید وجود دارد : >>> from django.template import Template, Context >>> raw_template = """<p>Dear {{ person_name }},</p> ... ... <p>Thanks for placing an order from {{ company }}. It's scheduled to ... ship on {{ ship_date|date:"F j, Y" }}.</p> ... ... {% if ordered_warranty %} ... <p>Your warranty information will be included in the packaging.</p> ... {% else %} ... <p>You didn't order a warranty, so you're on your own when ... the products inevitably stop working.</p> ... {% endif %} ... ... <p>Sincerely,<br />{{ company }}</p>""" >>> t = Template(raw_template) >>> import datetime >>> c = Context({'person_name': 'John Smith', ... 'company': 'Outdoor Equipment', ... 'ship_date': datetime.date(2009, 4, 2), ... 'ordered_warranty': False}) >>> t.render(c) u"<p>Dear John Smith,</p>\n\n<p>Thanks for placing an order from Outdoor Equipment. It's scheduled to\nship on April 2, 2009.</p>\n\n\n<p>You didn't order a warranty, so you're on your own when\nthe products inevitably stop working.</p>\n\n\n<p>Sincerely,<br />Outdoor Equipment </p>" اجازه دهید کد فوق را مورد بررسی قرار دهیم: در ابتدا کلاس های Template و Context از ماژول django.template به درون برنامه import شده اند. متن خام template درون متغیر raw_template ذخیره شده است. باید توجه داشته باشیم که در رشته های معمولی تنها می توان از یک خط استفاده کرد. واگر بخواهیم از رشته های چند خطی استفاده کنیم بایستی از علامت (" " ") برای رشته ی مورد نظر استفاده کنیم. در قدم بعدی، یک شیء template به نام t ساخته شده و رشته ی raw_template به سازنده ی آن ارسال شده است. ماژول datetime از کتابخانه ی استاندارد پایتون درون برنامه import شده است، چرا که در ادامه ی کار مورد استفاده قرار خواهد گرفت. یک شیء context به نام c ساخته شده است، سازنده ی context یک دیکشنری پایتون دریافت می کند که نام های متغیرها را با ارزش ها مرتبط می سازد. برای مثال در اینجا person_name به 'John Smith' و company به 'Outdoor Equipment'، و غیره مرتبط شده است. در نهایت، متد render() از شیء template فراخوانی شده، و context به آن ارسال شده است. این متد یک template قابل ارائه را بر می گرداند، بدین معنی که تمام متغیرها با ارزش و مقدار واقعی جایگزین شده و تمام تگ های template اجرا شده اند. توجه داشته باشید که پاراگراف "You didn't order a warranty" نمایش داده می شود چرا که متغیر ordered_warranty به صورت False ارزیابی شده است. همچنین توجه کنید تاریخ April 2, 2009 به حالت آن قالب بندی که برای آن مشخص شده است نمایش داده شده است (F j, Y). در صورتیکه تازه با زبان برنامه نویسی پایتون آشنا شده باشید، ممکن است تعجب کنید که رشته ی خروجی به رفتن به خط بعد حرف (\n) را نمایش می دهد. دلیل زیرکی interactive interpreter پایتون می باشد: فراخوانی (t.render(c یک رشته بر می گرداند، و interactive interpreter به صورت پیشفرض به جای شکل چاپی رشته شکل نمایشی آن را نشان می دهد. در صورتیکه می خواهید رشته با حالت چاپی نمایش داده شود، یعنی بجای حرف (\n) رشته به خط بعد برود، می توانید از عبارت print استفاده کنید: (print t.render(c. مسائل فوق اصول استفاده از template system جنگو می باشد: نوشتن یک رشته ی template، ساختن شیء Template، ساختن Context و فراخوانی متد render(). Context های چندگانه در یک Template با یک شیء Template می توانید چندین context را ارائه دهید. برای مثال: >>> from django.template import Template, Context >>> t = Template('Hello, {{ name }}') >>> print t.render(Context({'name': 'John'})) Hello, John >>> print t.render(Context({'name': 'Julie'})) Hello, Julie >>> print t.render(Context({'name': 'Pat'})) Hello, Pat هر گاه مانند مثال فوق از template همسان برای چندین context استفاده می کنید ، بسیار بهینه تر می باشد اگر یک مرتبه یک شیء Template ساخته و سپس متد render() را برای چند بار فراخوانی کنید: # Bad for name in ('John', 'Julie', 'Pat'): t = Template('Hello, {{ name }}') print t.render(Context({'name': name})) # Good t = Template('Hello, {{ name }}') for name in ('John', 'Julie', 'Pat'): print t.render(Context({'name': name})) تجزیه ی template جنگو کاملا سریع می باشد. در پشت صحنه بیشترین تجزیه در جنگو از طریق فراخوانی یک regular expression می باشد. این متضاد با موتور های template ای می باشد که پایه اساس آنها XML باشد، چرا که بسیار کند تر از موتور template جنگو می باشند. متغیرهای دیگر قابل ارسال به Context مثال های آورده شده تاکنون، یک مقدار ساده را به context ها ارسال کرده اند که به غیر مثال datetime.date غالبا رشته بوده اند. در صورتی که template system جنگو با ظرافت خاصی تعداد بیشتری از داده های با ساختار پیچیده را مانند لیست ها، دیکشنری ها و شیء های ساخته شده را نیز کنترل می کند. کلید گذشتن از داده های با ساختار پیچیده در template های جنگو حرف نقطه ( . ) می باشد، با استفاده از نقطه می توان به کلیدهای دیکشنری، attribute ها، متد ها و اندیس های یک شیء نیز دسترسی داشت. بهترین توضیح استفاده از چند مثال می باشد. برای نمونه، فرض کنید شما یک دیکشنری پایتون را به یک template ارسال کرده اید. برای دسترسی به مقادیر دیکشنری مورد نظر با کلید دیکشنری از یک نقطه استفاده کنید: >>> from django.template import Template, Context >>> person = {'name': 'Sally', 'age': '43'} >>> t = Template('{{ person.name }} is {{ person.age }} years old.') >>> c = Context({'person': person}) >>> t.render(c) u'Sally is 43 years old.' به طور مشابه، نقطه ها همچنین اجازه می دهند به attribute های شیء نیز دسترسی پیدا کنید. برای مثال، شیء datetime.date پایتون دارای attribute های year، month و day می باشد، می توان با استفاده از یک نقطه به attribute های آن در template جنگو دسترسی پیدا کرد: >>> from django.template import Template, Context >>> import datetime >>> d = datetime.date(1993, 5, 2) >>> d.year 1993 >>> d.month 5 >>> d.day 2 >>> t = Template('The month is {{ date.month }} and the year is {{ date.year }}.') >>> c = Context({'date': d}) >>> t.render(c) u'The month is 5 and the year is 1993.' در مثال زیر از یک کلاس ساخته شده استفاده شده است که نشان می دهد از نقطه ها می توان جهت دسترسی به شیء های دلخواه نیز استفاده کرد: >>> from django.template import Template, Context >>> class Person(object): ... def __init__(self, first_name, last_name): ... self.first_name, self.last_name = first_name, last_name >>> t = Template('Hello, {{ person.first_name }} {{ person.last_name }}.') >>> c = Context({'person': Person('John', 'Smith')}) >>> t.render(c) u'Hello, John Smith.' از طریق نقطه ها همچنین می توانند به متدهای درون یک شیء نیز دسترسی پیدا کرد. برای مثال هر رشته ی پایتون، دارای متدهای upper() و isdigit() می باشد، و می توان آن ها را در template جنگو فراخوانی و استفاده کرد: >>> from django.template import Template, Context >>> t = Template('{{ var }} -- {{ var.upper }} -- {{ var.isdigit }}') >>> t.render(Context({'var': 'hello'})) u'hello -- HELLO -- False' >>> t.render(Context({'var': '123'})) u'123 -- 123 -- True' توجه داشته باشید که پرانتزهای مربوط به متدها را در template نباید به کار برد. همچنین نمی توان به متدها آرگومان ارسال کرد؛ شما می توانید تنها متدهایی را فراخوانی کنید که هیچ آرگومانی دریافت نمی کنند. (کمی بعد در این فصل این فلسفه توضیح داده خواهد شد.) همچنین نقطه ها برای دسترسی به اندیس های لیست نیز استفاده می شوند، برای مثال: >>> from django.template import Template, Context >>> t = Template('Item 2 is {{ items.2 }}.') >>> c = Context({'items': ['apples', 'bananas', 'carrots']}) >>> t.render(c) u'Item 2 is carrots.' اندیس های منفی لیست را در template نمی توان استفاده کرد، برای مثال، متغیر {{ items.-1 }} موجب بروز خطای TemplateSyntaxError خواهد شد. لیست های پایتون یادآوری: لیست های پایتون با اندیس صفر شروع می شوند، بدین معنی که اولین اندیس صفر، دومین اندیس یک و به همین ترتیب ادامه خواهد داشت. کاربرد نقطه ها در template را می توان بدین شکل خلاصه کرد: هنگامی که template system با یک نقطه در مقابل نام یک متغیر برخورد می کند، به دنبال مسائل زیر جستجو خواهد کرد: دیکشنری (مانند foo["bar"]) attribute (مانند foo.bar) فراخوانی متد (مانند foo.bar()) اندیس لیست (مانند foo[2]) نقطه ها می توانند به صورت تودرتو نیز استفاده شوند. به عنوان نمونه،مثال زیر از عبارت {{ person.name.upper }} استفاده کرده است که ابتدا درون یک دیکشنری به جستجو می پردازد (person['name']) سپس یک متد را فراخوانی می کند (upper()): >>> from django.template import Template, Context >>> person = {'name': 'Sally', 'age': '43'} >>> t = Template('{{ person.name.upper }} is {{ person.age }} years old.') >>> c = Context({'person': person}) >>> t.render(c) u'SALLY is 43 years old.' فراخوانی متد و رفتار آن فراخوانی متد کمی پیچیده تر از دیگر انواع جستجو می باشد. در زیر مواردی که باید به خاطر داشته باشیم بیان شده است: اگر در طی فراخوانی متد، یک متد خطایی تولید کرد، آن خطا اعمال خواهد شد مگر آنکه کلاس آن خطا دارای attribute ای به نام silent‑variable‑failure با مقدار True باشد. در صورتیکه کلاس خطا دارای attribute مورد نظر باشد، متغیر درون template مقدار خالی را نشان خواهد داد، به عنوان مثال: >>> t = Template("My name is {{ person.first_name }}.") >>> class PersonClass3: ... def first_name(self): ... raise AssertionError, "foo" >>> p = PersonClass3() >>> t.render(Context({"person": p})) Traceback (most recent call last): ... AssertionError: foo >>> class SilentAssertionError(AssertionError): ... silent_variable_failure = True >>> class PersonClass4: ... def first_name(self): ... raise SilentAssertionError >>> p = PersonClass4() >>> t.render(Context({"person": p})) u'My name is .' -- فراخوانی متد تنها زمانی کار خواهد کرد که متد مورد نظر هیچ آرگومان ضروری نداشته باشد. در غیر اینصورت system در پی نوع دیگر بعدی (اندیس لیست) خواهد رفت. -- بدیهی است که برخی از متدها دارای اثرات زیان آور، و حتی می توانند یک حفره ی امنیتی باشند، و اجازه ی دسترسی template system به آن متدها کاری ناشیانه می باشد. به عنوان نمونه، فرض کنید شما یک شیء BankAccount دارید که دارای یک متد delete() می باشد. اگر یک template حاوی چیزی شبیه به این باشد {{ account.delete }}، در صورتیکه account شیء BankAccount باشد، هنگام ارائه template شیء مورد نظر حذف خواهد شد! برای جلوگیری از این موضوع، باید بدین شکل عمل کرد: def delete(self): # Delete the account delete.alters_data = True template system هر متدی که با روش فوق مشخص شده باشد را اجرا نخواهد کرد. در مثال فوق، اگر یک template حاوی {{ account.delete }} باشد و متد delete() دارای alter_data=True باشد، در این صورت متد delete() هنگام ارائه ی template اجرا نخواهد شد و بجای آن، بی صدا رد خواهد شد. نحوه ی کنترل متغیرهای نا معتبر به صورت پیشفرض، اگر یک متغیر وجود نداشته باشد، template system آن را به صورت یک رشته ی خالی ارائه می دهد. به عنوان مثال: >>> from django.template import Template, Context >>> t = Template('Your name is {{ name }}.') >>> t.render(Context()) u'Your name is .' >>> t.render(Context({'var': 'hello'})) u'Your name is .' >>> t.render(Context({'NAME': 'hello'})) u'Your name is .' >>> t.render(Context({'Name': 'hello'})) u'Your name is .' سیستم template بجای بروز خطا، آرام از کنار آن می گذرد. در صورت بروز خطا در این مورد برنامه به دلیل مچ نبودن حروف بزرگ و کوچک از روال عادی خارج می شود، در دنیای واقعی، برای یک وب سایت غیر قابل قبول است که به دلیل یک خطای نوشتاری در یک template کوچک همه چیز غیر قابل دسترس شده و برنامه متوقف شود. بازی با شیء های Context در اغلب مواقع، شیء های Context را با ارسال داده ی دیکشنری به آن تعریف می کنند. می توان ایتم های شیء Context را بعد از تعریف نیز مانند دیکشنری استاندارد پایتون حذف یا اضافه کرد: >>> from django.template import Context >>> c = Context({"foo": "bar"}) >>> c['foo'] 'bar' >>> del c['foo'] >>> c['foo'] Traceback (most recent call last): ... KeyError: 'foo' >>> c['newvariable'] = 'hello' >>> c['newvariable'] 'hello' تگ ها و فیلترهای اولیه ی Template همانطور که گفته شد، سیستم template جنگو تعدادی تگ ها و فیلترهای داخلی را با خود حمل می کند. در این بخش خلاصه ای از متداول ترین تگ ها و فیلترها را مورد بررسی قرار خواهیم داد. تگ if/else تگ {% if %} یک متغیر را مورد ارزیابی قرار می دهد، و در صورتی که مقدار متغیر True (مانند وجود داشتن، خالی نبودن، و مقدار False نبودن) بود، سیستم template جنگو هر آنچه را که بین تگ {% if %} و {% endif %} باشد را نمایش خواهد داد، مانند: {% if today_is_weekend %} <p>Welcome to the weekend!</p> {% endif %} استفاده از یک تگ {% else %} اختیاری می باشد: {% if today_is_weekend %} <p>Welcome to the weekend!</p> {% else %} <p>Get back to work.</p> {% endif %} مقدار True و False در پایتون در پایتون و template system جنگو شیء های زیر به منزله ی False تلقی می شوند: یک لیست خالی ([]) یک تاپل خالی (()) یک دیکشنری خالی ({}) یک رشته ی خالی ('') عدد صفر (0) شیء ویژه ی None شیء False شیء های ساخته شده که رفتار داده ی Boolean خود را تعریف می کنند. به غیر از موارد فوق همه چیز True ارزیابی می شود. تگ {% if %} عبارات and، or و not را برای آزمودن چندین متغیر، یا منفی کردن متغیر داده شده قبول می کند. به عنوان مثال: {% if athlete_list and coach_list %} Both athletes and coaches are available. {% endif %} {% if not athlete_list %} There are no athletes. {% endif %} {% if athlete_list or coach_list %} There are some athletes or some coaches. {% endif %} {% if not athlete_list or coach_list %} There are no athletes or there are some coaches. {% endif %} {% if athlete_list and not coach_list %} There are some athletes and absolutely no coaches. {% endif %} تگ های {% if %} اجازه ی نمی دهند عبارات and و or در یک تگ همسان استفاده شوند، دلیل آن است که ترتیب محاسبه ی آن ها مبهم خواهد بود. برای عنوان مثال کد زیر نا معتبر است: {% if athlete_list and coach_list or cheerleader_list %} استفاده از پرانتز برای کنترل کردن ترتیب عملکردها در سیستم template پشتیبانی نمی شود. در صورتیکه نیاز به استفاده از پرانتز بود، می توان اعمال منطقی را بیرون از template انجام داده و نتیجه را به عنوان متغیر template ارسال کرد، و یا آنکه از تگهای {% if %} به صورت تودرتو استفاده کرد. مانند: {% if athlete_list %} {% if coach_list or cheerleader_list %} We have athletes, and either coaches or cheerleaders! {% endif %} {% endif %} استفاده از چند عملگر یکسان در یک تگ مجاز می باشد، ولی نمی توان عملگرهای متفاوت را بدین شکل استفاده کرد، برای مثال کد زیر معتبر می باشد: {% if athlete_list or coach_list or parent_list or teacher_list %} تگی با نام {% elif %} وجود ندارد. می توان از تگ های {% if %} تودرتو برای این کار استفاده کرد: {% if athlete_list %} <p>Here are the athletes: {{ athlete_list }}.</p> {% else %} <p>No athletes are available.</p> {% if coach_list %} <p>Here are the coaches: {{ coach_list }}.</p> {% endif %} {% endif %} اطمینان حاصل کنید که هر تگ {% if %} با یک تگ {% endif %} بسته شده است. در غیر اینصورت خطای TemplateSyntaxError ایجاد خواهد شد. تگ for تگ {% for %} اجازه می دهد تا به ترتیب در سراسر ایتم های یک لیست یا ... چرخ بزنید. همانند عبارت for در پایتون؛ for X in Y، Y لیست مورد نظر می باشد و X در هر نوبت از حلقه یکی از ایتم های Y می باشد. سیستم template در هر بار، هر چیزی که بین {% for %} و {% endfor %} باشد را اجرا می کند. برای مثال، می توانید از کد زیر یک لیست از ورزشکاران را که به صورت متغیر athlete_list داده شده است را نمایش دهید: <ul> {% for athlete in athlete_list %} <li>{{ athlete.name }}</li> {% endfor %} </ul> اضافه کردن کلمه ی reversed موجب می شود که حلقه به صورت بر عکس جریان پیدا کند: {% for athlete in athlete_list reversed %} ... {% endfor %} می توان از تگ های {% for %} به صورت تودرتو نیز استفاده کرد: {% for athlete in athlete_list %} <h1>{{ athlete.name }}</h1> <ul> {% for sport in athlete.sports_played %} <li>{{ sport }}</li> {% endfor %} </ul> {% endfor %} می توان از الگوی کد زیر برای بررسی کردن اندازه ی لیست استفاده کرد، همچنین در صورت خالی بودن لیست، می توان یک پیام را نمایش داد: {% if athlete_list %} {% for athlete in athlete_list %} <p>{{ athlete.name }}</p> {% endfor %} {% else %} <p>There are no athletes. Only computer programmers.</p> {% endif %} به دلیل آنکه الگوی فوق بسیار رایج می باشد، تگ for از یک تگ {% empty %} پشتیبانی می کند که به شما اجازه می دهد در صورت خالی بود لیست آنچرا که می خواهید تعریف کنید. مثال زیر معادل کد قبلی می باشد: {% for athlete in athlete_list %} <p>{{ athlete.name }}</p> {% empty %} <p>There are no athletes. Only computer programmers.</p> {% endfor %} در سیستم template از عبارت break پشتیبانی نمی شود، بدین معنی که عبارتی برای شکستن روال عادی حلقه وجود ندارد. برای انجام چنین کاری می توان متغیر لیست را طوری تغییر داد که تنها حاوی مقادیری باشد که می خواهیم حلقه در آن بچرخد. به طور مشابه از عبارت continue نیز پشتیبانی نمی شود (از عبارت continue در پایتون برای انتقال حرکت حلقه به طور ناگهانی به ابتدای حلقه استفاده می شود.) (در همین فصل، در بخش فلسفه ی محدودیت ها دلیل محدودیت های فوق را درخواهید یافت.) داخل هر حلقه ی {% for %}، می توانید به یک متغیر template با نام forloop دسترسی پیدا کنید. این متغیر دارای attribute هایی می باشد که دارای اطلاعاتی در مورد حرکت حلقه می باشند. forloop.counter همواره عددی را نمایش می دهد که حاکی از تعداد حرکت حلقه می باشد، همچنین مقدار آن در بار اول حرکت حلقه عدد یک (1) می باشد: {% for item in todo_list %} <p>{{ forloop.counter }}: {{ item }}</p> {% endfor %} forloop.counter0 شبیه به forloop.counter می باشد، تنها فرق آن در این است که مقدار آن در اولین بار حرکت حلقه عدد صفر (0) می باشد. forloop.revcounter همواره عددی را نمایش می دهد که حاکی از تعداد ایتم های باقی مانده ی حلقه می باشد. در اولین حرکت حلقه مقدار آن مجموع ایتم های موجود در لیست می باشد. در آخرین حرکت حلقه مقدار آن برابر با عدد یک (1) خواهد بود. forloop.revcounter0 شبیه به forloop.revcounter می باشد، فرق آن در این است که در اولین حرکت حلقه مقدار آن به اندازه ی مجموع ایتم های لیست منهای یک می باشد و در آخرین حرکت حلقه مقدار آن برابر با عدد صفر (0) می باشد. forloop.first یک مقدار Boolean می باشد. در صورتی که حلقه در حرکت اول خود باشد مقدار True بر می گرداند که برای موارد خاص مناسب می باشد: {% for object in objects %} {% if forloop.first %}<li class="first">{% else %}<li>{% endif %} {{ object }} </li> {% endfor %} forloop.last یک مقدار Boolean می باشد. در صورتی که حلقه در حرکت آخر خود باشد مقدار True بر می گرداند، بیشترین استفاده از این attribute برای گذاشتن علامت (|) مابین لیستی از لینک ها می باشد: {% for link in links %} {{ link }} {% if not forloop.last %} | {% endif %} {% endfor %} خروجی کد فوق چیزی شبیه به این خواهد بود: Link1 | Link2 | Link3 | Link4 کاربرد رایج دیگر آن در قرار دادن ویرگول بین لغات می باشد: Favorite places: {% for p in places %}{{ p }}{% if not forloop.last %}, {% endif %}{% endfor %} forloop.parentloop در حلقه های تودرتو استفاده می شود، بدین صورت که از طریق آن می توان درون حلقه ی داخلی به attribute های حلقه ی خارجی دسترسی پیدا کرد: {% for country in countries %} <table> {% for city in country.city_list %} <tr> <td>Country #{{ forloop.parentloop.counter }}</td> <td>City #{{ forloop.counter }}</td> <td>{{ city }}</td> </tr> {% endfor %} </table> {% endfor %} متغیر forloop تنها در داخل حلقه ها در دسترس می باشد. بعد از آنکه template به تگ {% endfor %} می رسد، forloop از بین می رود. context و متغیر forloop هنگامی درون تگ {% for %} متغیری همنام با forloop داشته باشید، برای جلوگیری از overwrite شدن متغیر forloop جنگو فرض می کند که متغیر forloop شما forloop.parentloop می باشد. نیازی به نگرانی درباره ی این موضوع نمی باشد ولی توصیه می شود متغیری با نام forloop درون template استفاده نشود. تگ ifequal/ifnotequal سیستم template جنگو به طور عمد یک زبان برنامه نویسی کامل نمی باشد، در نتیجه اجازه ی اجرای عبارت های دلخواه پایتون را نمی دهد. (برای اطلاعات بیشتر نسبت به این محدودیت به بخش فلسفه ی محدودیت ها در همین بخش مراجعه کنید.) با این وجود، سیستم template جنگو برای مقایسه ی دو مقدار و نمایش چیزی در صورت مساوی بودن آن ها امکانات کاملی را پشتیبانی می کند (برای این منظور تگ {% ifequal %} در جنگو پیش بینی شده است.) تگ {% ifequal %} دو مقدار را با هم مقایسه می کند و در صورت مساوی بودن، هر آنچه که مابین {% ifequal %} و {% endifequal %} می باشد را نمایش می دهد. مثال زیر دو متغیر user و currentuser را مقایسه می کند: {% ifequal user currentuser %} <h1>Welcome!</h1> {% endifequal %} همچنین می توان برای مقایسه ی دو مقدار از رشته ی خام درون تک کوتیشن و یا دابل کوتیشن استفاده کرد: {% ifequal section 'sitenews' %} <h1>Site News</h1> {% endifequal %} {% ifequal section "community" %} <h1>Community</h1> {% endifequal %} درست مثل {% if %}، تگ {% ifequal %} نیز به طور اختیاری از تگ {% else %} پشتیبانی می کند: {% ifequal section 'sitenews' %} <h1>Site News</h1> {% else %} <h1>No News Here</h1> {% endifequal %} تنها متغیرهای template مانند؛ رشته ها، اعداد صحیح، و اعداد اعشاری می توانند به عنوان آرگومان {% ifequal %} قرار بگیرند. مثال های زیر معتبر می باشند: {% ifequal variable 1 %} {% ifequal variable 1.23 %} {% ifequal variable 'foo' %} {% ifequal variable "foo" %} نوع داده های دیگر از قبیل دیکشنری ها، لیست ها، و Boolean، برای {% ifequal %} مجاز نمی باشند. مثال های زیر نامعتبر می باشند: {% ifequal variable True %} {% ifequal variable [1, 2, 3] %} {% ifequal variable {'key': 'value'} %} کامنت ها تنها در HTML و پایتون، زبان template جنگو اجازه می دهد از کامنت ها استفاده شود. برای طراحی یک کامنت از {# #} استفاده می شود: {# This is a comment #} هنگامی که template اجرا می شود، کامنت ها هیچ خروجی ای نخواهند داشت. از تگ فوق نمی توان برای کامنت های چند خطی استفاده کرد. مثال زیر به عنوان کامنت در نظر گرفته نمی شود و مانند دیگر عبارت template به حساب می اید: This is a {# this is not a comment #} test. در صورتیکه می خواهید از کامنت های چند خطی استفاده کنید؛ بایستی از تگ {% template comment %} مانند زیر استفاده کرد: این یک کامنت چند خطی است.{% comment %} {% endcomment %} فیلتر ها همانطور پیش تر در این فصل توضیح داده شد، فیلترها روش های ساده ای برای تغییر مقدار متغیرها قبل از نمایش آن ها می باشند. فیلتر ها مانند زیر از علامت پایپ (|) استفاده می کنند: {{ name|lower }} کد فوق مقدار متغیر {{ name }} را بعد از عبور از فیلتر lower به حروف کوچک انگلیسی تبدیل می کند. فیلترها می توانند به صورت زنجیروار نیز استفاده شوند؛ بدین صورت که آن ها می توانند پشت سر هم قرار بگیرند. در این حالت خروجی فیلتر قبلی وارد فیلتر بعدی شود. در مثال زیر اولین المان (element) لیست دریافت شده و به حروف بزرگ انگلیسی تبدیل می شود: {{ my_list|first|upper }} مثال فوق 30 لغت اول متغیر bio را نمایش می دهد. در زیر تعداد از مهمترین فیلتر ها توضیح داده شده اند: addslashes: فیلتر مذکور یک علامت (\) قبل از علامت های (\)، تک کتیشن، و دابل کوتیشن قرار می دهد. این فیلتر برای متن های تولید شده درون رشته های جاوا اسکریپت مفید می باشند. date: تاریخ و یا زمان را بر طبق قالبی که به آن به عنوان پارامتر داده می شود، مانند مثال زیر قالب بندی می کند: {{ pub_date|date:"F j, Y" }} length: طول یک مقدار را بر می گرداند. برای یک لیست، تعداد المان های آن و برای یک رشته تعداد حروف آن را بر می گرداند. (توسعه دهندگان پایتون توجه داشته باشند که این فیلتر برای هر شیء پایتونی که تحوه تعیین طول آن مشخص شده باشد کار می کند؛ مانند هر شیءی که دارای متد __len__() باشد.) فلسفه ی محدودیت ها اکنون که تا حد زیادی با زبان template جنگو آشنا شده اید، وقت آن رسیده است که به برخی از محدودیت های عمدی موجود در این زبان، به همراه فلسفه ی این که چرا این زبان به این شکل کار می کند اشاره کنیم. قواعد زبان template جنگو ،بیشتر از هر جزء دیگری از برنامه های وب، بسیار خصوصی بوده و انتخاب های برنامه نویس بسیار گسترده می باشد. حقیقتی است که پایتون دارای پشتیبانی از ده ها زبان template سورس باز می باشد. که احتمالا هر کدام به این دلیل ساخته شده اند که توسعه دهنده معتقد بر این بوده است که زبان های template موجود، کافی نمی باشند. (در حقیقت، این فرمان عبور، برای یک توسعه دهنده پایتون، برای نوشتن زبان template خودش می باشد، اگر تاکنون همچین کاری نکرده اید، می توانید آن را امتحان، زیرا یک تمرین جالب می باشد.) با در نظر گرفتن این موضوع، جالب است این را بدانید که جنگو نیازی به استفاده از زبان template آن ندارد؛ یعنی می توان از هر زبان template دیگر نیز استفاده کرد. زیرا جنگو برای این در نظر گرفته شده است که یک فریم ورک وب full-stack برای تهیه ی تمام قسمت های ضروری برای توسعه دهندگان باشد تا یک تولید کننده باشند، خیلی وقت ها استفاده از سیستم template جنگو مناسب تر از کتابخانه های templte دیگر پایتون می باشد، ولی این یک نیازمندی موکد نمی باشد. همانطور که در بخش اینده ی این فصل "استفاده از template ها در view" مشاهده خواهید کرد، استفاده از زبان های template دیگر بسیار آسان می باشد. واضح است که ترجیح می دهیم از خود زبان template جنگو استفاده کنیم. template system دارای اصولی نسبت به نحوه ی توسعه ی وب انجام شده در World Online و تجربیات متعدد سازندگان جنگو می باشد. در زیر به تعدادی از این فلسفه ها اشاره خواهیم کرد: ** منطق برنامه (Business logic) باید از ارائه منطق (Presentation logic) جدا باشد. توسعه دهندگان جنگو، سیستم template جنگو را تنها به چشم ابزاری برای کنترل نمایش و نمایش منطق نگاه می کنند و نه بیشتر. سیستم template جنگو نباید از حالت تابع گرایی پشیتبانی کند که از این هدف اصلی خارج شود. به همین دلیل، فراخوانی کد پایتون به طور مستقیم درون template های جنگو امکان پذیر نیست. تمام برنامه نویسی، اساسا محدود به محدوده ی تگ های template ها و آن چه که می توان در این محدوده انجام داد می باشد. می توان از تگ های سفارشی template برای انجام وظایف دلخواه استفاده کرد، ولی در صورتی که خارج از تگ های template جنگو باشد به طور عمدی اجازه داده نخواهد شد کد پایتون دلخواه اجرا شود. ** کد template باید از HTML/XML جدا باشد. اگرچه سیستم template برای تولید HTML استفاده می شود، ولی سیستم template تنها باری قالب های غیر HTML ای، مانند متن ساده در نظر گرفته شده است. برخی از زبان های دیگر template ای که بر اساس XML می باشند، در آن ها تمام منطق template داخل تگ ها یا attribute ها XML قرار می گیرند، در صورتیکه جنگو به صورت عمدی از این محدودیت اجتناب کرده است. استفاده از XML می تواند موجب بوجود آمدن اشتباهات غیر قابل اجتناب شود که پیام های خطای آن نیز کمی غیر قابل فهم می باشند، همچنین استفاده از موتور XML برای parse کردن template ها باعث ایجاد یک سری وظایف اضافه ی غیر قابل قبول در پردازش template می شود. ** راحتی طراحان برای کار با کد HTML در نظر گرفته شده است. سیستم template طوری طراحی نشده است که به زیبایی قابل نمایش درون editor هایی مانند Dreamweaver نمایش داده شود. جنگو از نویسندگان template انتظار دارد به طور مستقیم و راحت HTML را ویرایش کنند. ** فرض بر این است که طراحات HTML برنامه نویسان پایتون نیستند. نسبت به این که اغلب template های صفحات وب به وسیله ی طراحان نوشته شده است نه برنامه نویسان، بنابراین در template system دانش پایتون فرض نشده است. ** هدف اختراع یک زبان برنامه نویسی نیست. هدف تنها ارائه ی یک سبک برنامه نویسی مانند استفاده از حلقه و غیره می باشد، که برای ایجاد یک نمایش از تصمیمات ضروری می باشد. استفاده از template ها در view اصول اولیه ی استفاده از template system را آموختیم؛ اجازه دهید از این دانش برای ساخت view استفاده کنیم. تابع current_datetime را در ماژول mysite.views که در فصل گذشته ساخته شد را دوباره فراخوانی کنید: from django.http import HttpResponse import datetime def current_datetime(request): now = datetime.datetime.now() html = "<html><body>It is now %s.</body></html>" % now return HttpResponse(html) اجازه دهید view فوق را با استفاده از سیستم template جنگو تغییر دهیم. در ابتدا ممکن است فکر کنید، باید کاری شبیه به کد فوق را انجام دهید: from django.template import Template, Context from django.http import HttpResponse import datetime def current_datetime(request): now = datetime.datetime.now() t = Template("<html><body>It is now {{ current_date }}.</body></html>") html = t.render(Context({'current_date': now})) return HttpResponse(html) مطمئنا از template system استفاده خواهیم کرد، ولی روش فوق مشکلات که در ابتدای فصل به آن اشاره کردیم را حل نمی کند. به عنوان مثال، template همچنان درون کد پایتون می باشد. می توان مشکل فوق را با جدا کردن template درون فایلی دیگر حل کرد، به طوری که فایل مذکور درون view بار گذاری شود. ممکن است ابتدا اینطور به نظر برسد که template را درون جایی روی سیستم ذخیره کردن و با استفاده از توابع داخلی پایتون محتویات فایل مورد نظر را بخوانید. در مثال زیر فرض شده است که template درون فایل /home/djangouser/templates/mytemplate.html ذخیره شده است: from django.template import Template, Context from django.http import HttpResponse import datetime def current_datetime(request): now = datetime.datetime.now() # Simple way of using templates from the filesystem. # This is BAD because it doesn't account for missing files! fp = open('/home/djangouser/templates/mytemplate.html') t = Template(fp.read()) fp.close() html = t.render(Context({'current_date': now})) return HttpResponse(html) روش فوق نیز با توجه به معایبی که در ادامه بیان می کنیم، روش مناسبی نمی باشد: ** روش فوق در زمان نبود فایل به هیچ وجه کار نخواهد کرد. فراخوانی open()، در صورتیکه فایل mytemplate.html وجود نداشته باشد و یا اینکه قابل خواندن نباشد باعث ایجاد خطای IOError خواهد شد. ** مکان template در این روش داخل کد پایتون قرار خواهد گرفت. در صورت استفاده از این تکنیک برای هر تابع view، باید درون هر فایل به صورت تکراری آدرس فایل را قرار بدهیم. ** روش فوق حاوی تعداد زیادی کدهای تکراری خسته کننده می باشد. در هر فایل شما باید fp.open() ،fp.read() و fp.close() را قرار دهید و بدیهی است که در صورت فراموش کردن این کدها برنامه شما با مشکل روبرو می شود. برای حل کردن موارد فوق، از بار گذاری template و دایرکتوری های آن استفاده می شود. بار گذاری Template جنگو با هدف حذف کردن کدهای اضافه در برنامه هنگام فراخوانی و همچنین درون template، برای بارگذاری template ها یک API بسیار مناسب و قدرتمند تهیه کرده است. به منظور استفاده از API بار گذاری template، ابتدا می بایست به فریم بگویید که template ها را در کجا ذخیره خواهید کرد. برای انجام چنین کاری نیازمند فایل settings می باشید. (در فصل گذشته هنگام معرفی تنظیم ROOT_URLCONF، در مورد فایل settings.py صحبت شد.) اگر از ابتدا کتاب را دنبال کرده اید، فایل settings.py را باز کرده و تنظیم TEMPLATE_DIRS را پیدا کنید. تنظیم فوق، یک تاپل خالی که احتمالا حاوی برخی کامنت های پیشفرض که به صورت خودکار تولید شده است، می باشد: TEMPLATE_DIRS = ( # Put strings here, like "/home/html/django_templates" or "C:/www/django/templates". # Always use forward slashes, even on Windows. # Don't forget to use absolute paths, not relative paths. ) تنظیم فوق به مکانیسم بار گذاری template جنگو می گوید که باید در کجا به دنبال template ها بگردد. مسیر و دایرکتوری را که می خواهید template های خود را ذخیره کنید مانند مثال زیر درون TEMPLATE_DIRS اضافه کنید: TEMPLATE_DIRS = ( '/home/django/mysite/templates', ) توجه به چند نکته ضروری است: ** می توانید هر مسیری را که می خواهید تعیین کنید، البته تا زمانیکه مسیر و template ها برای کاربر قابل خواندن باشد. در صورتیکه جای مناسبی را برای template های خود به یاد نمی آورید، پیشنهاد می کنیم یک دایرکتوری داخل پروژه ی خود بسازید (داخل دایرکتوری mysite که در شروع کار جنگو ساخته شد). ** در صورتیکه حاوی تنها یک مسیر می باشد، فراموش نکنید که در پایان رشته ی آدرس یک علامت کاما (,) قرار دهید! غلط: # Missing comma! TEMPLATE_DIRS = ( '/home/django/mysite/templates' ) صحیح: # Comma correctly in place. TEMPLATE_DIRS = ( '/home/django/mysite/templates', ) ** دلیل حرکت فوق این است که پایتون از طریق علامت کاما بتواند تشخیص دهد که عبارت فوق یک تاپل می باشد، نه یک عبارت ساده ی داخل پرانتز. ** اگر شما با سیستم عامل ویندوز کار می کنید، درون آدرس مورد نظر می بایست نام حرف دیسک درایو را اضافه کرده و همچنین مانند مثال زیر بجای علامت (\) از علامت (/) استفاده کنید: TEMPLATE_DIRS = ( 'C:/www/django/templates', ) ساده ترین راه این است که از آدرس های کامل (بدین معنی که مسیر دایرکتوری ها از ریشه ی سیستم آدرس دهی شود) استفاده کنید. همانطور که می دانید فایل settings تنها کد پایتون می باشد و با استفاده از این خصوصیت می توان کمی منعطف تر از قبل کار کرد، بدین صورت که می توان آدرس دهی درون تنظیم TEMPLATE_DIRS را به صورت پویا مانند زیر طراحی کرد: import os.path TEMPLATE_DIRS = ( os.path.join(os.path.dirname(__file__), 'templates').replace('\\','/'), ) مثال فوق از متغیر مجیک (magic) پایتون یعنی __file__ استفاده کرده است، بدین صورت که این متغیر به صورت خودکار حاوی نام فایل ای می باشد که در آن است. همچنین با استفاده از os.path.dirname نام دایرکتوری ای که حاوی فایل settings.py می باشد بدست می اید، سپس رشته ی template که در دومین پارامتر داده است به انتهای آن اضافه می شود و در پایان جای علامت های (\\) با علامت (/) جایگزین می باشد (اگر در سیستم عامل ویندوز باشید.) هنگامی که درون فایل settings.py از کد پویای پایتون استفاده کنید، باید اشاره کنیم که درون فایل settings.py از هرگونه خطا و اشتباه کد پایتون جلوگیری کنید. در صورتیکه درون این فایل یک خطای نوشتاری و یا خطای runtime وجود داشته باشد، سایت ایجاد شده توسط جنگو معیوب خواهد شد. بعد از تنظیم TEMPLATE_DIRS، گام بعدی تغییر کد view می باشد که باید از بار گذاری template به جای استفاده مستقیم template، استفاده کرد. باز می گردیم به تابع current_datetime، و آن را مانند زیر تغییر می دهیم: from django.template.loader import get_template from django.template import Context from django.http import HttpResponse import datetime def current_datetime(request): now = datetime.datetime.now() t = get_template('current_datetime.html') html = t.render(Context({'current_date': now})) return HttpResponse(html) در مثال فوق، از تابع django.template.loader.get_template() بجای بارگذاری template از سیستم به صورت دستی استفاده شده است. تابع get_template() نام template را به عنوان آرگومان دریافت کرده، و محلی را در سیستم template در آن وجود دارد را پیدا کرده، آن را باز کرده و و یک شیء template کامپایل شده را بر می گرداند. template مورد نظر در مثال فوق current_datetime.html می باشد، ولی هیچ چیز خاصی درباره ی پسوند .html وجود ندارد. شما می توانید هر پسوندی که می خواهید برای آن قرار دهید، و یا حتی می توانید پسوند فایل را کلا حذف کنید. برای تعیین مکان template در روی سیستم، تابع get_template() مسیر فایل را که در TEMPLATE_DIRS وجود دارد را با نام template که به آن ارسال می کنید ترکیب می کند. به عنوان مثال اگر TEMPLATE_DIRS حاوی آدرس /home/django/mysite/templates باشد، تابع get_template() مثال فوق فایل زیر را جستجو خواهد کرد. /home/django/mysite/templates/current_datetime.html در صورتیکه تابع get_template() موفق به یافتن template با نام داده شده نشود، خطای TemplateDoesNotExist ایجاد خواهد شد. برای دیدن خطای فوق سرور جنگو را با دستور python manage.py runserver درون دایرکتوری پروژه جنگو اجرا کنید. سپس مرورگر خود را باز کرده و به آدرس مورد نظر برای مثال http://127.0.0.1:8000/time/ بروید. با فرض اینکه تنظیم DEBUG به صورت True می باشد و هنوز template مورد نظر یعنی current_datetime.html ساخته نشده است، شما باید یک صفحه خطای جنگو را با نام TemplateDoesNotExist مشاهده کنید. صفحه ی خطای فوق همانند صفحه ای است که در آموزش view و urlconf جنگو توضیح داده شد، تنها با یک قسمت اطلاعات اضافه تر: بخش Template-loader postmortem. این بخش به شما می گوید که جنگو کدام template ها را بار گذاری کرده است، و همچنین دلیل رد کردن template ها را نیز در بر می گیرد (مانند File does not exist). این اطلاعات هنگامی که شما می خواهید خطاهای بارگذاری template را بر طرف کنید بسیار با ارزش می باشند. در پایان می بایست current_datetime.html را درون دایرکتوری template خود ساخته و کد زیر را درون آن قرار دهید: <html><body>It is now {{ current_date }}.</body></html> صفحه را ذخیره کرده و صفحه ی مرورگر خود را به اصطلاح refresh کنید، شما می بایست صفحه تولید شده حاوی زمان و تاریخ فعلی خود را مشاهده کنید. تابع render_to_response() همانطور که قبلا اشاره کردیم، بارگذاری یک template شامل پر کردن یک Context و بر گرداندن نتیجه ی یک template توسط یک شیء HttpResponse، می باشد. همانطور که گفته شد در روش فوق با استفاده از get_template() به جای template های مستقیم و یا آدرس درون کد، توانستیم کد خود را بهینه تر کنیم. ولی همچنان نیاز به یک حرکت زیبا برای بهینه تر کردن کد وجود دارد. جنگو یک میانبر (shortcut) ارائه می دهد که از طریق آن تنها می توان با یک خط کد template را بار گذاری کرده، آن را ارائه داده و یک HttpResponse را بر گردانید. این میانبر یک تابع است که render_to_response() نام دارد، که در ماژول django.shortcuts قرار دارد. اغلب اوقات شما بجای بارگذاری template ها و ساختن Context و شیء ها HttpResponse به صورت دستی از render_to_response() استفاده خواهید کرد، مگر آنکه کارفرای شما بر اساس مجموع خط های موجود در کدی که نوشته اید نسبت به کار شما تصمیم گیری کند. در زیر تابع بهینه شده ی current_datetime که با استفاده از render_to_response() دوباره نویسی شده است را مشاهده می کنید: from django.shortcuts import render_to_response import datetime def current_datetime(request): now = datetime.datetime.now() return render_to_response('current_datetime.html', {'current_date': now}) آن چه که تغییر پیدا کرده است: ** در مثال فوق get_template، Template، Context و HttpResponse دیگر import نشده اند، و به جای آن ها تنها django.shortcuts.render_to_response، import شده است. ** داخل تابع current_datetime، همچنان متغیر now محاسبه شده است، ولی بارگذاری template، ساختن Context، ارائه ی template و ساختن HttpResponse تماما تنها با فراخوانی render_to_response() انجام شده است. زیرا render_to_response() یک شیء HttpResponse بر می گرداند، و تنها کافی است آن مقدار را در view بر گردانده شود. اولین آرگومان تابع render_to_response() نام template مورد استفاده می باشد. دومین آرگومان در صورت ارسال، باید یک دیکشنری باشد که جهت ساختن Context برای template استفاده می شود. در صورتیکه دومین آرگومان را ارسال نکنید، render_to_response() از یک دیکشنری خالی استفاده می کند. تکنیک locals() آخرین تابع current_datetime نوشته شده ملاحظه کنید: def current_datetime(request): now = datetime.datetime.now() return render_to_response('current_datetime.html', {'current_date': now}) درون یک برنامه شما چندین بار مانند مثال فوق، مقادیری را حساب کرده و درون متغیرهایی ذخیره می کنید (مانند متغیر now در کد قبلی)، و متغیرها را به template مورد نظر ارسال می کنید. برنامه نویسان راحت طلب باید توجه داشته باشند که این کمی اضافه کاری است که باید متغیرها موقت ساخته و نام گذاری کنند و نام آن ها را برای template ارسال کنند. نه تنها این کار زائدی می باشد، بلکه تایپ اضافی درون برنامه نیز می باشد. پس اگر شما جزء آن دسته از برنامه نویسان راحت طلب می باشید که مایلند کد خود را کوتاه و مختصر نگه دارند، می توانید از یک تابع داخلی پایتون به نام locals() استفاده کنید. این تابع یک دیکشنری بر می گرداند که حاوی نام تمام متغیرهای محلی و ارزش هایشان می باشد، متغیرهای محلی به متغیرهایی گفته می شود که داخلی محدوده ی فعلی تعریف شده باشند. در نتیجه، view قبلی را می تواند به صورت زیر بازنویسی کرد: def current_datetime(request): current_date = datetime.datetime.now() return render_to_response('current_datetime.html', locals()) در مثال فوق، بجای تعیین کردن دیکشنری context به صورت دستی همانند قبل، مقدار locals() ارسال شده است، که شامل تمام متغیرهای تعریف شده در آن نقطه از اجرای تابع می باشد. در نتیجه، متغیر now به current_date تغییر نام پیدا کرده است، زیرا درون template نیز نام current_date معرفی شده است. در مثال فوق، locals() یک پیشرفت عظیم را ارائه نمی کند، ولی این تکنیک می تواند شما را از شر تایپ کردن زیاد خلاص می کند، البته اگر شما چندین متغیر template برای تعریف دارید و یا اینکه کمی تنبل هستید. چیزی که باید در مورد استفاده از locals() مراقب آن باشید این است که این تابع حاوی تمام متغیرهای محیطی و شاید خیلی بیشتر از آنچه شما واقعا نیاز دارید می باشد، در مثال قبلی، locals() همچنین حاولی request نیز می باشد. البته استفاده از locals() به برنامه و نوع استفاده شما بستگی دارد. دایرکتوری های زیر مجموعه در get_template() ذخیره ی تمام template ها درون یک دایرکتوری می تواند کمی سنگین باشد. ممکن است بخواهید template ها را درون دایرکتوری های زیر مجموعه ی دایرکتوری template قرار داهید. ذخیره ی template ها درون دایرکتوری های زیرمجموعه ی دایرکتوری template بسیار آسان می باشد. تنها کافیست درون get_template()، نام دایرکتوری زیرمجموعه و بعد از آن یک علامت (/) و بعد نام template را قرار دهید: t = get_template('dateapp/current_datetime.html') همچنین می توانید از این امکان در تابع render_to_response() نیز استفاده کنید بدین صورت که اعمال فوق را درون اولین پارامتر این تابع قرار می دهید: return render_to_response('dateapp/current_datetime.html', {'current_date': now}) هیچ محدودیتی نسبت به تعداد دایرکتوری های زیر مجموعه ی استفاده شده وجود ندارد و می توانید در صورت نیاز از هر تعداد از آن ها استفاده کنید. نکته : کاربران ویندوز، مطمئن شوید که از علامت (/) به جای (\) استفاده می کنید. تابع get_template() طراحی آدرس دهی را بر اساس Unix-style فرض می کند. تگ include اکنون که مکانیزم بارگذاری template شرح داده شده است، می توان یک تگ داخلی template و مزایای آن را معرفی کرد: {% include %}. این تگ اجازه می دهد تا محتویات template های دیگر را درون template فعلی وارد کرد. آرگومان این تگ باید نام template ای باشد که می خواهید وارد template فعلی بکنید. همچنین این آرگومان می تواند یک متغیر و یا کد مستقیم HTML باشد که درون تک کتیشن یا دابل کتیشن قرار دارد. زمانی که یک کد همسان درون چندین template وجود دارد، می توان برای جلوگیری از تکرار کد نویسی از تگ include استفاده کرد. هر دو مثال زیر برای include معتبر می باشند: {% include 'nav.html' %} {% include "nav.html" %} مثال زیر محتویات template، includes/nav.html را وارد template خواهد کرد: {% include 'includes/nav.html' %} مثال زیر محتویات template ای را که نامش درون متغیر template_name ذخیره شده است را وارد می کند: {% include template_name %} همانند get_template()، نام فایل template با اضافه شدن به مسیر دایرکتوری template که در تنظیم TEMPLATE_DIRS قرار دارد تعیین می شود. template های وارد شده با context مربوط به template که آن ها را وارد کرده است ارزیابی می شوند. به عنوان مثال دو template زیر را ملاحظه کنید. # mypage.html <html> <body> {% include "includes/nav.html" %} <h1>{{ title }}</h1> </body> </html> # includes/nav.html <div id="nav"> You are in: {{ current_section }} </div> در صورتیکه که شما mypage.html را با یک context حاوی current_section ارائه (render) کنید، متغیر template وارد شده همانطور که انتظار خواهید داشت در دسترس خواهد بود. در صورتیکه یک تگ {% include %}، template ای را وارد کند که وجود نداشته باشد، یکی از حالت های زیر پیش می اید: ** اگر تنظیم DEBUG به صورت True در نظر گرفته شده باشد، صفحه ی خطای جنگو با خطای TemplateDoesNotExist نمایش داده خواهد شد. ** اگر تنظیم DEBUG به صورت False در نظر گرفته شده باشد، تگ مورد نظر بدون هیچ خطایی رد شده، و درون قسمت تگ include چیزی نمایش داده نخواهد شد. ارث بری در Template مثال های template ای که تاکنون استفاده شده است از نظر محتوی خیلی مختصر و کم حجم بوده اند. ولی در دنیای واقعی، شما تز template system جنگو برای ساختن صفحات HTML با حجم و محتویات بسیار گسترده استفاده خواهید کرد. در این صورت با یک مشکل مشترک و عمومی توسعه ی وب رو به رو خواهید بود: چگونه می توان از بوجود آمدن صفحات و کدها تکراری در ساخت صفحات وب که اجتناب ناپذیر است جلوگیری کرد؟ روش عمومی برای حل این مشکل استفاده از incude های سمت سرور می باشد، دستورالعمل هایی که شما می توانید داخل صفحه ی خود صفحات دیگر را نیز وارد کنید. در واقع، جنگو از این روش با استفاده از تگ template {% include %} پشتیبانی می کند که توضیح آن پیش تر داده شده است. ولی روش بهتری برای حل این مشکل وجود دارد که یکی از استراتژی های مطلوب جنگو به شمار می اید که "ارث بری template" نام دارد. در واقع، ارث بری template، این اجازه را می دهد که یک اسکلت بندی پایه و اولیه از template بسازید که حاوی تمام بخش های عمومی می باشد. این بخش ها به صورت block ها تعریف می شوند و template هایی که از آن template پدر، ارث بری می کنند می توانند آن بخش ها را دوباره نویسی و یا به اصطلاح overwrite کنند. به مثال زیر توجه کنید، که همان بر روی template قبلی یعنی current_datetime.html موضوع فوق را توضیح داده است: <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"> <html lang="en"> <head> <title>The current time</title> </head> <body> <h1>My helpful timestamp site</h1> <p>It is now {{ current_date }}.</p> <hr> <p>Thanks for visiting my site.</p> </body> </html> تا اینجا مشکلی وجود نخواهد داشت، ولی چه اتفاقی می افتد اگر بخواهید یک template برای یک view دیگر مانند تابع hours_ahead که در آموزش view و urlconf جنگو وجود داشت ایجاد کنید؟ در صورتیکه بخواهید یک template کامل دیگر برای view دوم بسازید، چیزی شبیه به مثال زیر خواهد بود: <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"> <html lang="en"> <head> <title>Future time</title> </head> <body> <h1>My helpful timestamp site</h1> <p>In {{ hour_offset }} hour(s), it will be {{ next_time }}.</p> <hr> <p>Thanks for visiting my site.</p> </body> </html> کاملا واضح هست که مقدار زیادی کد تکراری در دو مثال فوق وجود دارد. تصور کنید اگر بخواهید صفحات بیشتری داشته باشید مانند یک سایت بزرگ که حاوی style sheet ها و یا مقادیر زیادی کد Java Script می باشد چه خواهید کرد؟ راهکار include سمت سرور برای این مشکل راه حل مناسبی نمی باشد، چرا که به عنوان مثال برای قسمت بالایی کد شما یک template با نام header.html خواهید داشت: <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"> <html lang="en"> <head> و برای قسمت پایین کد یک template با نام footer.html مانند مثال زیر: <hr> <p>Thanks for visiting my site.</p> </body> </html> با یک استراتژی مانند ارث بری هر دو قسمت بسیار آسان پیاده سازی خواهند شد. در مثال فوق هر دو صفحه تیتر صفحه را نشان می دهند (<h1>My helpful timestamp site</h1>) و نمی توان آن را درون header.html قرار داد، چرا که <title> در هر صفحه متفاوت از صفحه ی دیگر خواهد بود. و اگر <titile> درون header.html قرار داده می شد، دیگر امکان تغییر آن برای هر صفحه به طور جدا گانه امکان پذیر نبود و تمام صفحات می بایست یک <title> را نمایش بدهند. ارث بری template جنگو این مشکلات را حل کرده است. نسخه ی insite-out از include های سمت سرور را بیاد می آورید. به جای تعریف تکه کد های مشترک، تکه کد هایی که تعریف می شوند متفاوت از یکدیگر هستند. اولین گام برای تعریف یک template پدر، یک اسکلت بندی از صفحه ی شما که template های فرزند بعدا آن را پر خواهند کرد. در مثال زیر یک template پدر تعریف شده است: <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"> <html lang="en"> <head> <title>{% block title %}{% endblock %}</title> </head> <body> <h1>My helpful timestamp site</h1> {% block content %}{% endblock %} {% block footer %} <hr> <p>Thanks for visiting my site.</p> {% endblock %} </body> </html> مثال فوق که base.html نام دارد، یک اسکلت بندی ساده ی HTML می باشد که برای تمام صفحات استفاده خواهد شد. صفحات درون سایت که از صفحه ی فوق ارث بری کرده اند و به عبارتی صفحات فرزند نامیده می شوند می توانند خصوصیات مشخص شده در کلاس پدر را بازنویسی و یا تغییر دهند، می توانند خصوصیاتی را اضافه کنند و حتی می توانند خصوصیتی را نیز حذف کنند و در خودشان از استفاده نکنند. (در صورتیکه با مثال های کتاب پیش میروید فایل فوق را با نام base.html درون دایرکتوری template ذخیره کنید.) در اینجا از یک تگ template ای که آن را مشاهده کرده اید استفاده می کنید: تگ {% block %}. تمام تگ های {% block %} به موتور template این را می گویند که template فرزند ممکن است این قسمت از template را باز نویسی کند. اکنون یک template پدر موجود می باشد، می توان از آن در فایل current_datetime.html به شکل زیر استفاده کرد: {% extends "base.html" %} {% block title %}The current time{% endblock %} {% block content %} <p>It is now {{ current_date }}.</p> {% endblock %} همچنین فایل hours_ahead را نیز که در آموزش view و urlconf جنگو در مورد آن صحبت شده است را نیز در مثال زیر مشاهده خواهید کرد: (در صورتیکه همگام با مثال های کتاب پیش میروید hours_ahead را از حالت قبلی که به صورت کد مستقیم درون view نوشته شده است خارج کرده و مانند زیر به صورت یکی از template ها درون دایرکتوری template دخیره کنید.) {% extends "base.html" %} {% block title %}Future time{% endblock %} {% block content %} <p>In {{ hour_offset }} hour(s), it will be {{ next_time }}.</p> {% endblock %} آیا روش فوق روش زیبایی نیست؟ هر template حاوی کدهای منحصر به خود می باشد. هیچ کد زائدی وجود ندارد. در صورتیکه نیاز به تغییر طراحی در یک سایت عظیم دارید، تنها کافیست که درون template پدر تغییر ایجاد کنید، در اینصورت تمام template هایی که از کلاس پدر ارث بری کرده اند نیز به سرعت تغییر خواهند خواهند کرد. در زیر نحوه ی کار روش فوق توضیح داده شده است. هنگامی که template، current_datetime.html بارگذاری می شود، موتور template به تگ {% extends %} نگاه می کند، که به این اشاره دارد که فایل مورد نظر یک template فرزند می باشد. در اینصورت موتور template به سرعت template پدر را بارگذاری می کند که در این مورد template پدر base.html می باشد. توجه داشته باشید که template های فرزند بلاک footer را تعریف نکرده اند، template system از مقدار مشخص شده ی بلاک درون template پدر بجای آن استفاده کرده است. مقدار مشخص شده ی درون یک تگ {% block %} در یک template پدر همیشه به صورت یک مقدار یدکی استفاده می شود. ارث بری تاثیری بر روی context template نخواهد داشت. به عبارت دیگر، هر template فرزند به هر یک از متغیر های template درون context دسترسی خواهد داشت. می توان به صورت چندین سطح از ارث بری استفاده کرد. یکی از روش های عمومی استفاده از روش ارث بری در سه سطح می باشد: یک template با نام base.html که بسازید که محتویات اصلی سایت را در بر بگیرد، محتویاتی که به ندرت تغییر خواهند کرد، البته اگر نگوییم هرگز تغییر نخواهند کرد. یک template با نام base_SECTION.html برای هر بخش از سایت خود ایجاد کنید (مانند base_photos.html و base_forum.html). این template ها باید از base.html ارث بری کنند و باید حاوی طراحی مربوط به خود باشند. template های هر نوع از صفحه را ایجاد کنید، مانند صفحه ی انجمن (forum) یا یک آلبوم عکس. این template ها از template مناسب مربوط به خود ارث بری کنند. در زیر دستور العمل های کار با ارث بری template را مشاهده می کنید: ** در صورتیکه درون یک template از {% extends %} اسفتاده می کنید، این تگ می بایست به عنوان اولین تگ template در نظر گرفته شود، در غیر اینصورت ارث بری template کار نخواهد کرد. ** معمولاً، بهتر است از تگ های {% block %} بیشتری درون template پدر استفاده شود، بیاد داشته باشید که، template ها فرزند اجباری برای تعریف تمام block های template پدر ندارند، پس می توان هر تعداد block مناسب به صورت پیش فرض درون template پدر قرار داد، و سپس در صورت نیاز به هرکدام آن را درون template فرزند استفاده کرد. ** در صورتیکه شما تکه کدی تکراری درون تعدادی از template ها پیدا کردید، این می تواند بدین معنا باشد که شما باید آن تکه کد را به درون یک {% block %} در template پدر انتقال دهید. ** در صورتیکه نیاز به محتویات یک block درون template پدر دارید، می توانید از {{ block.super }} استفاده کرد، که یک متغیر magic می باشد که یک متن ارائه شده از template پدر را تهیه می کند. این روش در صورتیکه می خواهید بجای بازنویسی کلی یک block محتویات آن را اضافه کنید مناسب می باشد. ** نمی توان چند تگ {% block %} با نام یکسان درون یک template تعریف کرد. دلیل وجود همچین محدودیتی این است که یک block در هر دو جهت کار می کند. یک تگ block تنها یک حفره برای پر کردن، تهیه نمی کند، بلکه محتویاتی نیز برای این حفره در template پدر تعریف می کند. در صورتیکه دو block همنام درون یک template وجود داشته باشد، template پدر نخواهد دانست کدام محتویات block را استفاده کند. ** نام template ای که به {% extends %} ارسال می شود مانند get_template() بارگذاری می شود. نام template به تنظیم TEMPLATE_DIRS اضافه شده است. در اغلب موارد، آرگومانی که به {% extends %} ارسال می شود یک رشته خواهد بود، ولی این آرگومان می تواند یک متغیر نیز باشد، در صورتیکه شما نام template پدر را تا زمان اجرا نمی دانید. این خصوصیت اجازه می دهد یک حرکت پویا انجام دهید. دوستان عزیز خسته نباشید از این جلسه طولانی امیدوارم که موفق باشید . پایتونی ها ترجمه از سایت www.djangobook.com
  8. این تاپیک پشتیبانی برای آموزش است آموزش Template ها در جنگو ( جلسه چهارم ) 08/04/96 18:42 08/04/96 18:42 لطفا اگرهر سوال یا بازخوردی دارید اینجا ارسال کنید.
  9. این تاپیک پشتیبانی برای آموزش است کتاب جنگو - آموزش View ها و URLconf ها در جنگو ( جلسه سوم ) 24/03/96 17:25 24/03/96 18:01 لطفا اگرهر سوال یا بازخوردی دارید اینجا ارسال کنید.
  10. آموزش View ها و URLconf ها در جنگو در فصل گذشته ما نحوه نصب و راه اندازی سرور جنگو را توضیح دادیم. در این فصل شما قواعد ساختن صفحات داینامیک از طریق فریم ورک جنگو (Django) و همچنین استفاده از view ها و URLconf ها را خواهید آموخت. اولین برنامه جنگو به عنوان اولین قدم بیایید یک صفحه وب که خروجی معروف Hello world را چاپ می کند را بسازیم. در صورتیکه شما یک Hello world ساده را بدون استفاده از یک فریم ورک وب ایجاد کرده باشید، به صورت ساده عبارت Hello world را درون یک فایل متنی وارد کرده و آنرا به عنوان مثال با نام hello.html، در یک پوشه جایی درون وب سرور ذخیره می کردید. دقت کنید که شما دو موضوع کلیدی را در مورد آن صفحه وب در نظر می گیرید: محتویات آن (رشته "Hello world") و URL آن (http://www.example.com/hello.html، و یا شاید http://www.example.com/files/hello.html اگر شما آن فایل را درون یک پوشه زیر مجموعه قرار داده باشید). در جنگو شما این کار را با کمی تفاوت انجام می دهید. محتویات صفحه توسط یک تابع view تولید می شوند، و URL در یک URLconf تعیین شده است. ابتدا بیایید تابع view حاوی Hello world را بنویسیم. اولین view شما داخل پوشه mysite که با دستور django-admin startproject در فصل قبل ساختید، یک فایل خالی با نام views.py ایجاد کنید. این ماژول پایتون (views.py) حاوی view های ما برای این فصل می باشد. نکته اینکه چیز خاصی برای انتخاب نام views.py وجود ندارد، در جنگو اجباری برای انتخاب نام وجود ندارد، اما ایده خوبی است که مانند یک قرارداد نام آنرا views.py گذاشته تا برای توسعه دهندگان دیگر خوانایی کد شما بیشتر باشد. view مورد نظر ما بسیار ساده است. اینجا تابع view را مشاهده خواهید کرد، همچنین باید جمله import را داخل فایل views.py تایپ کنید: from django.http import HttpResponse def hello(request): return HttpResponse("Hello world") بیایید به بررسی کد بالا بپردازیم: در ابتدا، ما کلاس HttpResponse را درون ماژول import کردیم، این کلاس در ماژول django.http می باشد که در ادامه کد به آن نیاز خواهیم داشت. یک تابع به نام hello را در ماژول تعریف کردیم که تابع view نامیده می شود. هر تابع view حداقل یک پارامتر را دریافت می کند، که به صورت قرارداد request نامیده می شود. پارامتر request یک شیء می باشد که حاوی اطلاعات درباره request وب فعلی است، همچنین آن یک instance از کلاس django.HttpRequest است. در این مثال ما هیچ کاری را با شیء request انجام نمی دهیم، اما باید آنرا به عنوان اولین پارامتر از تابع view قرار داد. نکته اینکه نام تابع view اهمیتی برای جنگو ندارد، به صورتی که روش ثابتی برای نام گذاری تابع view وجود ندارد که جنگو بتواند از طریق آن تابع را تشخیص دهد. برای اینکه یک تابع پایتون یک view برای جنگو به شمار بیاید بایستی یک HttpRequest را به عنوان اولین پارامتر دریافت کرده و یک instance از HttpRespose را برگرداند بدین صورت جنگو یک تابع view را از توابع ساده پایتون تشخیص می دهد(البته استثناهایی نیز وجود دارد که در ادامه به آنها خواهیم پرداخت.) تابع یک خطی ساده: view فقط یک تابع پایتون می باشد که یک HttpRequest را به عنوان اولین پارامتر دریافت می کند و یک instance از HttpResponse را بر می گرداند. برای اینکه یک تابع پایتون بتواند یک view برای جنگو باشد، باید این دو کار را انجام دهد. (البته استثناهایی نیز وجود دارد اما بعدا به آنها خواهیم پرداخت) اولین URLconf شما اگر تا اینجای کار دوباره دستور manage.py runserver را اجرا کنید، باز هم صفحه خوش آمدگویی به جنگو را خواهید دید و اثری از Hello world نخواهید دید. دلیل این است پروژه mysite چیزی درباره view نمی داند و تابع hello را نمی شناسد؛ نیاز است به جنگو گفته شود که یک view در یک URL مشخص قرار دارد. برای این منظور، یعنی اتصال تابع view به یک URL مشخص با جنگو، از یک URLconf استفاده می شود. یک URLconf شبیه به فهرست مطالب در یک وب سایت است که رابطه بین URL ها و توابع view را نمایش می دهد که در واقع بیان کننده رابطه بین URL و تابعی که آن URL بایستی فراخوانی کند، می باشد.به عبارت دیگر به جنگو می گوید که برای هر URL، باید کدام کد فراخوانی شود. برای مثال هنگامی که شما آدرس http://example.com/foo را درخواست می کنید، تابع foo_view() که در ماژول views.py قرار دارد فراخوانی شود. هنگامی که شما دستور django-admin.py startproject را در فصل قبلی اجرا کردید، یک URLconf به صورت اتوماتیک برای شما ساخته شد: فایل urls.py به صورت پیش فرض چیزی شبیه به کد زیر می باشد: from django.conf.urls.defaults import * # Uncomment the next two lines to enable the admin: # from django.contrib import admin # admin.autodiscover() urlpatterns = patterns('', # Example: # (r'^mysite/', include('mysite.foo.urls')), # Uncomment the admin/doc line below and add 'django.contrib.admindocs' # to INSTALLED_APPS to enable admin documentation: # (r'^admin/doc/', include('django.contrib.admindocs.urls')), # Uncomment the next line to enable the admin: # (r'^admin/', include(admin.site.urls)), ) URLconf به طور پیشفرض شامل قسمت هایی از خصوصیات جنگو می باشد که به صورت کامنت وجود دارد، کد اصلی URLconf به شکل زیر می باشد: from django.conf.urls.defaults import * urlpatterns = patterns('', ) بیایید کد فوق را مورد بررسی قرار دهیم: در خط اول تمام شیء های ماژول django.conf.urls.defaults که زیر بنای URLconf می باشند به درون ماژول فعلی import شده است، که شامل تابع patterns نیز می شود. در خط بعد تابع patterns فراخوانی شده و حاصل کار درون متغیر urlpatterns ریخته شده است. تابع patterns یک آرگومنت ارسال می کند که یک رشته خالی است. (یک رشته که می تواند یک prefix عمومی برای توابع view باشد، که در آموزش view و urlconf پیشرفته درباره آن صحبت خواهد شد.) نکته اصلی متغیر urlpatterns می باشد که جنگو درون URLconf به آنرا پیدا خواهد کرد. این متغیر رابطه بین URL ها و کد را تعریف می کند. به صورت پیشفرض همانطور که ملاحظه کردید URLconf خالی است (نکته آنکه، جنگو به چه صورت همانطور که در فصل گذشته مشاهده کردید می داند که صفحه خوش آمد گویی را نشان دهد؟ جواب این است که هنگامی که URLconf شما خالی باشد، جنگو فرض می کند شما تنها یک پروژه را آغازکردید، بنابراین، آن صفحه را نمایش می دهد.) برای اضافه کردن URL و view به URLconf، تنها کافی است یک تاپل پایتون متصل شده به یک الگوی URL را به تابع view اضافه کنید. در کد زیر نحوه انجام این کار مشخص شده است: from django.conf.urls.defaults import * from mysite.views import hello urlpatterns = patterns('', ('^hello/$', hello), ) (دقت کنید که ما کدها کامنت را برای کوتاهی کد حذف کردیم، شما می توانید اگر دوست دارید آن ها را در کد خود نگهدارید) دو تغییر در کد فوق ایجاد شده است: ابتدا، تابع hello از ماژول خود (mysite/views.py که به زبان پایتون تغییر کرده و به mysite.view تبدیل شده) import شده است. همچنین قسمت ('^hello/$, hello) به urlpatterns اضافه شده است. اندیس اول تاپل مبوط به URLpattern می باشد که با URL وارد شده در ارتباط خواهد بود و اندیس دوم اشاره به view دارد. به طور خلاصه، ما به جنگو گفتیم که هر request ای که به آدرس /hello/ ارسال می شود باید با تابع view یعنی hello کنترل شود. مسیر پایتون هنگامی که از جمله import استفاده می کنیم، پایتون به یک لیست از دیکشنری ها مراجعه می کند که مسیر پایتون در آن وجود دارد. برای مثال اگر مسیر پایتون شما به این شکل باشد ['', '/usr/lib/python2.4/site-packages', '/home/username/djcode']، و شما جمله from foo import bar را اجرا کنید، پایتون به دنبال یک ماژول به نام foo.py در پوشه فعلی می گردد. (اولین اندیس دیکشنری در مسیر پایتون، یک رشته خالی می باشد، که به معنی پوشه یا مسیر فعلی می باشد) اگر فایل مورد جستجو (foo.py) در مسیر جاری وجود نداشت، پایتون به دنبال آن فایل در این مسیر خواهد گشت /usr/lib/python2.4/site-packages/foo.py. اگر فایل درون آن مسیر هم وجود نداشت، مسیر /home/username/djcode/foo.py را نیز جستجو خواهد کرد، در پایان اگر فایل در مسیرهای ذکر شده یافت نشد. خطای importError ایجاد خواهد شد. اگر مشتاق هستید که مسیر پایتون خودتان را ببینید، interactive interpreter پایتون را باز کرده و کد زیر را وارد کنید. >>> import sys >>> print sys.path عموما شما نسبت به تنظیم مسیر پایتون نگرانی نخواهید داشت، پایتون و جنگو به صورت اتوماتیک در پشت صحنه تنظیمات مربوط به مسیر پایتون را انجام می دهند. (تنظیم مسیر پایتون یکی از وظایفی است که manage.py انجام می دهد) موضوع قابل بحث syntax ای باشد که URLpattern از آن استفاده می کنند، که با حالت آدرس دهی معمولی کمی متفاوت است: جنگو علامت (/) را از مقابل هر URL ورودی قبل از چک کردن URLpatterns حذف می کند. (درباره این موضوع در آموزش view و urlconf پیشرفته صحبت شده است) درون الگوی فوق یک علامت (^) و یک علامت ($) وجود دارد، که حروف regular expression می باشد و معانی خاصی دارند: علامت (^) به معنی این می باشد که URL مربوط ابتدای آدرس است و علامت ($) بدین معنی است URL مربوط انتهای آدرس می باشد. مفهوم فوق با یک مثال خوب قابل توضیح است. اگر بجای الگوی فوق ('^hello/$') از این الگو استفاده کنیم '^hello/' (بدون گذاشتن علامت $ در انتهای URL)، در اینصورت هر URL ای که با /hello/ شروع می شود شامل آدرس URLpattern خواهد شد، مانند /hello/foo و /hello/bar، به همین صورت اگر علامت (^) را از ابتدای URL برداریم ('hello/$') جنگو هر URL ای که با hello/ پایان می یابد را شامل آدرس URLconf خواهد دانست، مانند /foo/bar/hello/، و اگر URL را به این صورت استفاده کنیم hello/، یعنی بدون علامت (^) و ($)، هر URL ای که حاوی hello/ باشد را شامل خواهد شد مانند /foo/hello/bar. بنابراین در اینجا ما از هر دو علامت فوق استفاده کردیم تا تنها آدرس /hello/ بتواند با URL مورد نظر match شود، نه بیشتر و نه کمتر. نکته دیگر اینکه تابع view یعنی hello به صورت یک شیء بدون فراخوانی تابع به patterns ارسال شده است. این یکی از خصوصیات کلیدی از پایتون (و زبانهای داینامیک دیگر) است: توابع شیء های خاصی هستند، بدین معنی که می توان آن ها را مانند هر متغیر دیگری ارسال کرد. برای تست کردن تغییرات درون URLconf، سرور جنگو را اجرا کنید، همانطور که در فصل 2 توضیح داده شد، با دستور python manage.py runserver. (اگر سرور از قبل اجرا شده است، دیگر نیازی به اجرا کردن دوباره آن نمی باشد زیرا همانطور که پیش تر گفته شد، به محض ایجاد تغییر در کد و ذخیره آن سرور جنگو خود را بروز رسانی کرده و به صورت اتوماتیک دوباره اجرا می شود.) سپس مرورگر را باز کرده، و به آدرس http://127.0.0.1:8000/hello/ بروید. نوشته Hello world را باید در خروجی تماشا کنید. هوررا! شما اولین صفحه وب ساخته شده با جنگو را ایجاد کردید. Reqular Expressions Regular expression ها یا regexes یک روش فشرده و یا جمع و جور برای تعیین الگوها در متن می باشد. در اینجا تعدادی از نمادهای عمومی regex را مشاهده می کنید: نماد مچ می شود با . (نقطه) یک تک حرف \d یک عدد یک رقمی [A-Z] هر حرف بین A تا Z بزرگ [a-z] هر حرف بین a تا z کوچک [A-Za-z] هر حرف بین a تا z بدون حساس بودن به بزرگی و کوچکی تعداد یک یا بیشتر از عبارت قبل آن (مانند \d تعداد یک یا بیشتر ارقام) [^/] یک حرف یا بیشتر تا یک (/) ? تعداد صفر یا یک از عبارت قبلی (مانند \d?، صفر یا یک رقم) * تعداد صفر یا بیشتر ار عبارت قبلی (مانند \d*، صفر یا بیشتر ارقام) {1,3} تعداد یک و سه از عبارت قبلی (مانند \d{1,3} یک، دو یا سه رقم) اشاره ای کوتاه به خطای 404 تا اینجای کار، URLconf ما تنها یک URLpattern تعریف کرده است. چه اتفاقی می افتد اگر یک درخواست با URL متفاوت ارسال شود؟ برای پی بردن به جواب، سرور جنگو را اجرا کرده و یک پیج با همچین آدرسی را باز کنید: http://127.0.0.1:8000/goodbye/ یا http://127.0.0.1:8000/hello/subdirectory، یا حتی http://127.0.0.1:8000/ (روت سایت). شما باید صفحه ای با پیام"page not found" که در شکل 1-3 نشان داده شده است مشاهده کنید. جنگو این پیام را نشان می دهد زیرا درخواست شما URL ای می باشد که در URLconf تعریف نشده است. شکل 1-3 پیام خطای 404 جنگو بسیار تواناتر از خطای عادی 404 می باشد. همچنین خطای 404 جنگو دقیقا URLconf استفاده شده و الگوی آن را نشان می دهد. با این اطلاعات نشان داده شده شما می توانید به راحتی دلیل ایجاد شدن خطای 404 را متوجه شوید. طبیعتا اطلاعات نشان داده شده توسط جنگو برای خطای 404 تنها برای شما ایجاد شده است یعنی برای توسعه دهندگان وب. اگر که نمی خواهید این اطلاعات برای عموم نشان داده نشوند، این نکته اهمیت دارد که جنگو زمانی پیام مخصوص به خود را نشان می دهد که پروژه جنگو در حالت debug باشد. در فصل های آینده نحوه غیر فعال کردن حالت debug را توضیح خواهیم داد. تنها چیزی که باید الان بدانید این است که هر پروژه جنگو هنگامی که ساخته می شود به صورت پیشفرض در حالت debug می باشد و در صورتی که این حالت غیر فعال باشد، جنگو خروجی متفاوتی را نشان خواهد داد. اشاره ای کوتاه به ریشه سایت (site root) همانطور که در قسمت قبلی گفته شد، حتی اگر شما به آدرس ریشه سایت http://127.0.0.1:8000/ هم مراجعه می کردید خطای 404 ایجاد می شد. برای اینکه بتوان در URLconf آدرس ریشه سایت را با یک تابع view مرتبط کرد مانند مثال زیر باید عمل کرد: from mysite.views import hello, my_homepage_view urlpatterns = patterns('', ('^$', my_homepage_view), # ... ) نحوه پردازش درخواست قبل از ادامه کار برای نوشتن دومین تابع view، اجازه دهید مکثی برای فهمیدن بیشتر نحوه عملکرد جنگو داشته باشیم. هنگامی که شما پیام Hello world را با رفتن به آدرس http://127.0.0.1:8000/hello/ در مرورگر خود مشاهده می کنید، جنگو در پشت صحنه چگونه عمل می کند؟ همه چیز با فایل settings.py آغاز می شود. هنگامی که شما فرمان python manage.py runserver را اجرا می کنید، اسکریپت به دنبال فایل settings.py در مسیر همسان با مسیر manage.py می گردد. این فایل حاوی تمام پیکربندی های مربوط به پروژه جنگو می باشد که همگی به صورت حروف بزرگ انگلیسی می باشند: TEMPLATE_DIRS، DATABSE_NAME، و غیره. مهمترین تنظیم ROOT_URLCONF نام دارد. ROOT_URLCONF به جنگو می گوید که کدام ماژول پایتون باید به عنوان URLconf برای این وب سایت استفاده شود. هنگامی که django-admin.py startproject فایل های settings.py و urls.py را ایجاد می کرد را بخاطر می آورید؟ فایل به صورت اتوماتیک ساخته شده settings.py حاوی تنظیم ROOT_URLCONF است که به فایل اتوماتیک ساخته شده urls.py اشاره می کند. فایل settings.py را باز کرده و خودتان مشاهده کنید، مانند: ROOT_URLCONF = 'mysite.urls' کد فوق برابر با mysite/urls.py می باشد. زمانی که یک درخواست برای یک URL خاص فرستاده می شود، جنگو URLconf ای که در تنظیم ROOT_URLCONF به آن اشاره شده است را بار گذاری می کند. سپس شروع به چک کردن URL ای که در request آمده است با الگوهای موجود در URLconf، تا زمانی که یک الگوی مرتبط پیدا شود. هنگامی که یک الگوی مرتبط پیدا شد، تابع view مربوط به آن الگو را فراخوانی کرده و یک شیء HttpRequest بعنوان اولین پارامتر به آن ارسال می کند. (در مورد HttpRequest به طور ویژه ای در فصل های بعدی صحبت خواهد شد.) به طور خلاصه: یک درخواست به /hello/ فرستاده می شود. جنگو ریشه URLconf را با نگاه به تنظیم ROOT_URLCONF تعیین می کند. جنگو به تمامی URLpattern ها برای پیدا کردن یک URL مرتبط با /hello/ جستجو می کند. اگر URL مرتبطی یافت شد، تابع view مربوط به آن URL فراخوانی می شود. تابع view یک HttpResponse بر می گرداند. جنگو HttpResponse را برای نشان دادن نتیجه در یک صفحه وب به شکل مناسب تبدیل می کند. حالا شما به طور کامل نحوه عمکرد جنگو را می دانید، البته تا این حد که چگونه تابع view به URL مربوط به خود از طریق URLconf وصل می شود. دومین view: دارای محتوای داینامیک view قبلی تنها یک نمایش آموزنده از نحوه کار جنگو بود، و مثال یک صفحه پویا (dynamic) بحساب نمی آید، زیرا محتوای صفحه همواره یک چیز ثابت می باشد. در هر زمانی که شما آدرس /hello/ را مشاهده کنید یک چیز ثابت را خواهید دید، که همانند یک فایل استاتیک HTML می باشد. برای دومین view، صفحه ای داینامیک خواهیم ساخت، یک صفحه وب که زمان و تاریخ فعلی را نمایش خواهد داد. این یک مثال ساده و مناسب می باشد، چرا که در این مثال با دیتابیس یا ورودی کاربر سر و کار نخواهیم داشت، تنها زمان داخلی سرور را به صورت خروجی استفاده خواهیم کرد. برای نوشتن view فوق باید زمان و تاریخ فعلی را محاسبه کرده، و به صورت یک HttpResponse آنرا بر گردانیم. اگر شما با زبان پایتون آشنایی داشته باشید، باید بدانید که پایتون حاوی یک ماژول به نام datetime می باشد که زمان و تاریخ را محاسبه می کند. در این نحوه استفاده از این ماژول را مشاهده خواهید کرد: >>> import datetime >>> now = datetime.datetime.now() >>> now datetime.datetime(2008, 12, 13, 14, 9, 39, 2731) >>> print now 2008-12-13 14:09:39.002731 به اندازه کافی استفاده از این ماژول ساده می باشد، و نیازی به انجام کاری توسط جنگو نیست. کد فوق تنها کد پایتون می باشد. تاکید ما بر این است که شما از محتویات کد که تنها برای پایتون می باشد و محتویاتی که مربوط به جنگو می باشد اطلاع کامل پیدا کنید، و به اشتباه در قسمت هایی که نیازی به کد جنگو نمی باشد از آن استفاده بیهوده و اضافه بر سازمان نکنید. برای ساختن یک view جنگو که زمان و تاریخ جاری را نمایش دهد، نیاز به قرار دادن جمله datetime.datetime.now() درون view و برگرداندن یک HttpResponse می باشد. که در کد زیر مشاهده می کنید: from django.http import HttpResponse import datetime def current_datetime(request): now = datetime.datetime.now() html = "<html><body>It is now %s.</body></html>" % now return HttpResponse(html) همچنین تابع hello نیز باید درون views.py وجود داشته باشد، ما تابع hello را در این کد فوق برای اختصار حذف کردیم. در اینجا view کامل را مشاهده می کنید. from django.http import HttpResponse import datetime def hello(request): return HttpResponse("Hello world") def current_datetime(request): now = datetime.datetime.now() html = "<html><body>It is now %s.</body></html>" % now return HttpResponse(html) بررسی کد فوق: در ابتدا برای محاسبه تاریخ و زمان، ماژول datetime را به بالای views.py اضافه کردیم. تابع جدید current_datetime زمان و تاریخ جاری را محاسبه می کند، و آنرا به صورت شیء درون متغیر محلی now ذخیره می کند. دومین خط از کد داخل تابع view یک پاسخ (request) HTML با استفاده از قابلیت format-string پایتون ایجاد می کند. %s داخل رشته بدین معناست که مقدار متغیر now جایگزین %s خواهد شد. متغیر now رشته نیست بلکه یک شیء datetime.datetime می باشد، ولی %s آن را به رشته تبدیل می کند، که چیزی شبیه به "14:09:39.002731 13-12-2008" می باشد. در پایان، تابع view همانند تابع hello یک شیء HttpResponse که حاوی پاسخ تولید شده است بر می گرداند. بعد از اضافه کردن تابع جدید به views.py، یک URLpattern نیز داخل urls.py ایجاد می کنیم، که برای جنگو مشخص شود که کدام URL باید view مورد نظر خود را کنترل کند. from django.conf.urls.defaults import * from mysite.views import hello, current_datetime urlpatterns = patterns('', ('^hello/$', hello), ('^time/$', current_datetime), ) دو تغییر ایجاد شده است. اول اینکه تابع current-datetime را در بالا import کردیم. و دومین تغییر که مهم تر از تغییر اول می باشد، یک URLpattern با آدرس /tim/ برای view جدید اضافه کرده ایم. آیا قلق کار دستتان آمد؟ با نوشتن view جدید و تغییر دادن URLconf سرور را اجرا کرده و درون مرورگر به این آدرس بروید http://127.0.0.1:8000/time/. شما باید زمان جاری را در صفحه مورد نظر مشاهده کنید. منطقه زمانی جنگو بسته به رایانه شما، زمان و تاریخ ممکن است چند ساعتی متفاوت باشد. دلیل این است که جنگو دارای منطقه زمانی می باشد و تنظیم پیشفرض آن بر روی America/Chicago می باشد. (این زمان برای جایی است که توسعه دهندگان اصلی در آنجا زندگی می کنند) اگر شما در جای دیگری زندگی می کنید می توانید این پیشفرض را تغییر دهید. برای این تنظیم کامنتی وجود دارد که می توانید در آن لینک مربوط برای به روز رسانی لیست جهانی منطقه زمانی را پیدا کنید. URLconf و مفهوم Loose Coupling حالا زمان خوبی است برای پرداختن به فلسفه کلیدی پشت URLconfs و جنگو: قانون loose coupling. به عبارت ساده، loose coupling یک شیوه توسعه نرم افزار است که در ساختن بخش های قابل تعویض اهمیت دارد. اگر دو بخش از کد به صورت loosely couple پیاده سازی شده باشند، هنگامی که در یک بخش تغییری ایجاد می کنیم، بر روی بخش دیگر تاثیر نمی گذارد و یا تاثیر بسیار کمی دارد. URLconf جنگو یک مثال بسیار خوب از این قانون می باشد. در یک برنامه وب جنگو تعریف های URL و توابع view، به صورت loosely couple نامیده می شوند؛ برای مثال، به تابع current_datetime ملاحظه کنید. اگر بخواهیم URL مربوط یه این تابع view را از /time/ به /current-time/ تغییر دهیم، می توانیم به سرعت و بدون هیچ نگرانی نسبت به تابع view مربوط به آن در URLconf تغییر ایجاد کنیم. به همین صورت اگر بخواهیم تابع view را نیز تغییر دهیم می توانیم بدون تاثیر بر روی URL آن این تابع را تغییر دهیم. بعلاوه اگر بخواهیم تابع current-date را برای چندین URL نمایش دهیم، می توانیم خیلی آسان URLconf را بدون هیچ گونه لمسی در تابع view تغییر دهیم. در مثال که در زیر مشاهده خواهید کرد، current-datetime برای دو URL در دسترس خواهد بود. urlpatterns = patterns('', ('^hello/$', hello), ('^time/$', current_datetime), ('^another-time-page/$', current_datetime), ) URLconf ها و view ها در عمل به صورت loosely couple پیاده سازی شده اند. ما در سرتاسر این کتاب از طریق مثال ها به این فلسفه مهم (loosely coupling) اشاره خواهیم کرد سومین view: آدرس های پویا (dynamic) در تابع current_datetime، محتویات صفحه یعنی زمان و تاریخ نشان داده شده، داینامیک بوده، اما URl (/time/) استاتیک می باشد. در اغلب برنامه های داینامیک وب، یک URL حاوی پارامترهایی است که بر روی خروجی صفحه تاثیر می گذارد. برای مثال یک فروشگاه کتاب آنلاین ممکن است برای هر کتاب URL مخصوص به خود را داشته باشد، مانند /books/243/ و /book/81196/. بیایید view سوم خودمان را با حالت URL داینامیک ایجاد کنیم که درون URL ساعت را دریافت کند. هدف از ساختن این سایت این است که در صورت وارد کردن /time/plus/1/ خروجی یعنی همان زمان و تاریخ در یک ساعت جلوتر نشان دهد، صفحه /time/plus/2/ زمان را 2 ساعت جلوتر از زمان فعلی نشان دهد، صفحه /time/plus/3/ زمان را 3 ساعت جلوتر نشان دهد و الی آخر. یک تازه کار یا مبتدی ممکن است فکر کند برای هر ساعت یک تابع view مجزا لازم است: urlpatterns = patterns('', ('^time/$', current_datetime), ('^time/plus/1/$', one_hour_ahead), ('^time/plus/2/$', two_hours_ahead), ('^time/plus/3/$', three_hours_ahead), ('^time/plus/4/$', four_hours_ahead), ) کد فوق به وضوح مشخص است که ناقص می باشد. نه تنها توابع view اضافه و زائد می باشند، بلکه برنامه اساسا به طور محدود تنها از 4 ساعت تعریف شده پشتیبانی می کند. اگر بخواهیم صفحه ای بسازیم پنج ساعت جلوتر را نشان دهد باید یک تابع View و URLconf برای آن ایجاد کنیم، که کاری تکراری می باشد. نیاز به مقداری اختصار در اینجا داریم. سخنی درباره URL های بهینه اگر با برنامه های دیگر توسعه ی وب نظیر Java و یا PHP کار کرده باشید، شاید این فکر به نظر شما خطور کند که باید از یک پارامتر query string استفاده کنید، مانند /time/plus?hours=3، بدین شکل که ساعت مورد نظر را درون پارامتر query string همانطور که نشان داده شد بعد از علامت (?) ارسال کنید. شما می توانید این مورد را با جنگو پیاده سازی کنید (نحوه ی انجام آن در فرم به خوبی بیان شده است)، اما یکی از فلسفه های هسته ی جنگو این است که URL به صورت کاملا زیبا استفاده شوند. آدرس /time/plus/3/ به مراتب تمیزتر، ساده تر، خواناتر و خواندن آن آسانتر از query string می باشد. URL های زیبا مشخصه ی کیفیت برنامه ی وب می باشند. حالا چطور می توان ساعت مشخص شده در URL را درون برنامه کنترل کرد؟ همانطور که پیش تر ذکر شد، URLpattern یک regular expression می باشد؛ از این رو، ما می توانیم از الگوی \d برای مچ کردن یک یا بیشتر ارقام استفاده کنیم. urlpatterns = patterns('', # ... (r'^time/plus/\d /$', hours_ahead), # ... ) (ما از # ... برای اشاره کردن به این موضوع که ممکن است URLpattern های دیگری نیز درون مثال وجود داشته باشند استفاده می کنیم.) این URLpattern جدید با هر آدرسی مانند /time/plus/2/، /time/plus/25/ یا حتی /time/plus/100000000/ مچ می شود. بهتر آن است که عدد وارد شده برای ساعت را محدود کنیم، به طوری که حداکثر عددی که بتوان وارد کرد 99 باشد. این بدین معنی است که می خواهیم تنها به وارد کردن اعداد یک یا دو رقمی اکتفا کنیم، شکل آن در regular expression بدین شکل خواهد بود \d{1,2}: (r'^time/plus/\d{1,2}/$', hours_ahead), نکته هنگام ایجاد برنامه های وب، چیزی که همیشه مهم می باشد کنترل بیشترین مقدار ممکن ورودی می باشد، و تصمیم گرفتن در مورد آنکه برنامه باید آن ورودی را پشتیبانی کند یا خیر. ما در اینجا با محدود کردن مقدار ساعت ورودی تا 99 این مورد را کنترل کرده ایم. یکی از جزئیات مهمی که معرفی شده است در اینجا حرف r می باشد که قبل URL استفاده شده است. این حرف به پایتون می گوید که رشته ی بعد از آن یک raw string می باشد، در این نوع رشته علامت (\) ترجمه یا تفسیر نمی شود. در رشته های معمولی پایتون علامت های (\) به حروف ویژه تفسیر می شوند مانند '\n'، که به یک کاراکتر خط جدید تبدیل می شود. هنگامی که از حرف r قبل یک رشته استفاده شود، مفسر پایتون دیگر علامت های (\) را تفسیر نمی کند، بنابراین r'\n' دیگر یک کاراکتر خط جدید نمی باشد و تنها دو کاراکتر می باشد، یک (\) و یک حرف کوچک n. بین کاربرد علامت (\) در پایتون و regular expression یک برخورد طبیعی وجود دارد، بنابراین شدیدا پیشنهاد می شود که هنگامی که می خواهید از regular expression استفاده کنید حتما از raw string ها استفاده کنید. از حالا به بعد، تمام URLpattern ها در این کتاب به صورت raw string خواهند بود. اکنون که توانستیم توسط یک URL چندین URL مختلف را در URLpattern پشتیبانی کنیم، این مشکل مطرح می شود که چگونه داده مورد نظر در URL را به تابع view انتقال دهیم، به طوری که توسط یک تابع view تمام ساعت ها را کنترل کنیم. این مشکل با قرار دادن پرانتز به دور داده ی مورد نظر در URLpattern قابل حل می باشد. برای مثال فوق، ما می خواهیم شماره ی وارد شده در URL را به تابع view انتقال دهیم، بنابراین عبارت \d{1,2} را درون پرانتز قرار می دهیم: (r'^time/plus/(\d{1,2})/$', hours_ahead), آخرین URLconf شامل دو تابع view قبلی می باشد: from django.conf.urls.defaults import * from mysite.views import hello, current_datetime, hours_ahead urlpatterns = patterns('', (r'^hello/$', hello), (r'^time/$', current_datetime), (r'^time/plus/(\d{1,2})/$', hours_ahead), ) ترتیب کد نویسی در مثال فوق، ابتدا URLpattern نوشته شد و بعد تابع view، اما در مثال های قبل از آن، ابتدا تابع view نوشته شد و بعد URLconf. کدام تکنیک بهتر است؟ روش هر توسعه دهنده متفاوت است. اگر شما از جمله افراد با مهارت هستید، ممکن است هنگام شروع پروژه ابتدا URLpattern های برنامه ی خود را نوشته و سپس به view های برنامه بپردازید. این روش به دلیل دادن به اصطلاح یک نوع لیست کاری واضح به شما مفید می باشد و اساسا پارامتر های مورد نیاز برای view را در ابتدای کار تعریف می کند. اگر شما از جمله برنامه نویسانی می باشید که دوست دارند از جزئیات به کلیات جلو بروند، ممکن است ترجیح بدهید ابتدا view ها را بنویسید و سپس URL ها را به آنها مرتبط کنید. این روش نیز مانند روش قبل می تواند مناسب باشد. در پایان، هر دو روش معتبر می باشند، هر کدام از روش ها که با فکر شما سازگار می باشد را می توانید بکار ببرید. حالا تابع hours_ahead را ایجاد خواهیم کرد که در URLconf با URL مورد نظر یعنی r'^time/plus/(\d{1,2})/$' مرتبط شده است. تابع hours_ahead بسیار شبیه به تابع current_datetime می باشد که در ابتدا نوشته شده است، با یک تفاوت کلیدی: تابع مذکور (hours_ahead) یک آرگومنت اضافه دریافت می کند، که شماره ی ساعت ها می باشد: from django.http import Http404, HttpResponse import datetime def hours_ahead(request, offset): try: offset = int(offset) except ValueError: raise Http404() dt = datetime.datetime.now() datetime.timedelta(hours=offset) html = "<html><body>In %s hour(s), it will be %s.</body></html>" % (offset, dt) return HttpResponse(html) اجازه دهید کد فوق را مورد بررسی قرار دهیم: تابع view، hours_ahead، دو پارامتر دریافت می کند: request و offset. request همانطور که در تابع hello و current_datetime مشاهده کردید یک شیء HttpRequest می باشد. دوباره می گوییم که هر تابع view همیشه یک شیء HttpRequest به عنوان اولین پارامتر دریافت می کند. offset یک رشته است که داخل URLpattern درون پرانتز قرار گرفته است. به عنوان مثال، اگر URL درخواست شده /time/plus/3/ باشد، بنابراین offset رشته ی '3' خواهد بود. اگر URL درخواست شده /time/plus/21/ باشد، بنابراین offset رشته ی '21' خواهد بود. نکته اینکه مقدار که در URLpattern داخل پرانتز قرار گرفته شده است همواره رشته خواهد بود، نه Integer، حتی اگر رشته ی مورد نظر تنها از ارقام ساخته شده باشد مانند '21'. (از نظر فنی، مقدار درون پرانتز در URLpattern همواره شیء یونیکد می باشد، نه رشته ی ساده ی پایتون، ولی در حال حاضر درباره ی این فرق نگران نباشید.) در این مثال فوق متغیر مورد نظر offset نامیده شده است، شما می توانید آن را هر چیزی که دوست دارید نام گذاری کنید، البته هر نامی در محدوده ی نام گذاری متغیرهای پایتون. نام متغیر به هیچ وجه مهم نمی باشد، تنها چیز مهم این است که، این متغیر به عنوان دومین پارامتر تابع view بعد از request باشد. (همچنین می توان آنرا به صورت کلمه ی کلیدی نیز بکار برد که در آموزش view و urlconf پیشرفته درباره ی آن صحبت شده است.) اولین چیزی که درون تابع انجام شده است استفاده از int() و قرار دادن offset درون آن می باشد. این عمل مقدار یک رشته را به یک integer تبدیل می کند. توجه داشته باشید در صورتیکه پایتون قادر به تبدیل مقدار رشته به یک integer نباشد، به عنوان مثال اگر مقدار رشته چیزی شبیه به این باشد 'foo'، در این حالت خطای ValueError ایجاد خواهد شد. در مثال فوق، در صورتیکه برنامه با خطای ValueError برخورد کند، استثناء (exception) django.http.Http404 ایجاد خواهد شد، که نمایش صفحه ی خطای "Page not found" می باشد. خوانندگان هوشیار تعجب خواهند کرد که چگونه می توان به خطای ValueError رسید، در حالی که regular expression در URLpattern (\d{1,2}) تنها ارقام را قبول خواهد کرد، و offset همیشه تنها رشته ی ساخته شده از ارقام خواهد بود؟ جواب این است یک تابع view هیچگونه فرضی نسبت به پارامترهای ورودی خود در این حالت نخواهد کرد و با چک کردن مقدار متغیر درون تابع view به اصطلاح یک محکم کاری نسبت به مقدار متغیر ایجاد خواهد شد، همچنین اگر مبحث loosely coupling را به خاطر بیاورید تابع view جدای از URLconf به کار خود می پردازد. در خط بعدی از تابع، زمان و تاریخ فعلی محاسبه شده و شماره ساعت مناسب به آن اضافه شده است. عبارت datetime.datetime.now() را درون تابع current_datetime قبلا مشاهده کرده اید؛ مفهوم جدید در اینجا این است که می توانید با ساختن و اضافه کردن شیء datetime.timedelta به یک شیء datetime.datetime زمان و تاریخ را حساب کرده و نمایش دهید. در نهایت نتیجه این عمل درون متغیر dt ذخیره شده است. این خط دلیل استفاده از int() را نشان می دهد، چرا که برای استفاده از تابع datetime.timedelta باید پارامتر hours یک integer باشد. در قدم بعدی، یک خروجی HTML ساخته شده است، همانطور که در تابع current_datetime مشاهده کردید. تنها تفاوت این است که در اینجا از قابلیت format-string پایتون با دو مقدار استفاده شده است، نه یک مقدار. از این رو دو علامت %s درون رشته و یک تاپل برای درج مقدایر در انتها وجود دارد. نهایتا، یک HttpResponse از HTML برگردانده شده است. با تابع view و URLconf نوشته شده، سرور جنگو را (اگر در حال اجرا نمی باشد) اجرا کنید، و به منظور بررسی اینکه برنامه کار می کند یا خیر به آدرس http://127.0.0.1:8000/time/plus/3/ بروید. سپس به آدرس http://127.0.0.1:8000/time/plus/5/ رفته و همچنین آدرس http://127.0.0.1:8000/time/plus/24/ را نیز امتحان کنید. نهایتا به منظور بررسی اینکه الگوی شما تنها اعداد یک رقمی و دو رقمی را قبول می کند آدرس http://127.0.0.1:8000/time/plus/100/ را نیز امتحان کنید؛ جنگو باید خطای "Page not found" را در این مورد نمایش دهد. همچنین آدرس http://127.0.0.1:8000/time/plus/ (بدون هیچ ساعت تعیین شده ای) نیز باید باعث بروز خطای 404 شود. صفحات خطای جالب جنگو چند لحظه ای از برنامه های وبی که تاکنون ساخته ایم لذت ببرید ... حالا بیایید خرابشان کنیم! بیایید به طور عمد یکی از خطاهای پایتون را درون فایل views.py با کامنت کردن عبارت offset = int(offset) در hours_ahead معرفی کنیم. def hours_ahead(request, offset): # try: # offset = int(offset) # except ValueError: # raise Http404() dt = datetime.datetime.now() datetime.timedelta(hours=offset) html = "<html><body>In %s hour(s), it will be %s.</body></html>" % (offset, dt) return HttpResponse(html) سرور جنگو را (اگر در حال اجرا نیست) اجرا کرده و به آدرس /time/plus/3/ بروید. یک صفحه ی خطا با یک مقدار قابل توجهی از اطلاعات را مشاهده خواهید کرد، که همچنین در بالای صفحه پیام TypeError نمایش داده شده است: "unsupported type for timedelta hours component: Unicode" چه اتفاقی افتاد؟ تابع datetime.timedelta انتظار دارد پارامتر hours یک integer باشد، و در کد فوق قسمتی از کد که offset را به integer تبدیل می کرد کامنت شده است، که باعث شده است در عبارت datetime.timedelta خطای TypeError ایجاد شود. هدف از این مثال نشان دادن صفحه ی خطای جنگو بود. مقداری درون صفحه ی خطا بگردید و با اطلاعات مختلف داده شده آشنا شوید. مسائل قابل توجهی در اینجا وجود دارند: در بالای صفحه، اطلاعات کلیدی در مورد استثناء (exception) بدست می آورید: نوع استثناء، پارامترهای استثناء (در این مورد پیام "unsupported type")، فایلی که استثناء در آن ایجاد شده است، و شماره ی خط آن. در زیر اطلاعات کلیدی استثناء، صفحه traceback کامل پایتون را برای این استثناء نمایش می دهد. این همانند traceback استانداردی است که در خط فرمان interpreter نشان داده می شود، که در اینجا حالت تعاملی بیشتری دارد. برای هر سطح ("frame") در توده های مشخص، جنگو نام فایل، نام متد/تابع، شماره ی خط، و سورس کد خط مورد نظر را نمایش می دهد. بر روی خط خاکستری تیره رنگ کد کلیک کنید، خط های قبل و بعد خطی که باعث بروز خطا شده است را مشاهده خواهید کرد. بر روی "local vars" در زیر هر frame کلید کنید تا جدول تمام متغیرهای محلی و مقادیرشان نشان داده شود. این اطلاعات اشکال زدایی می تواند یک کمک بزرگ برای هر توسعه دهنده باشد. بر روی "local vars" در زیر هر frame کلید کنید تا جدول تمام متغیرهای محلی و مقادیرشان نشان داده شود. این اطلاعات اشکال زدایی می تواند یک کمک بزرگ برای هر توسعه دهنده باشد. در قسمت پایین دکمه ی "Share this traceback on a public Web site" اطلاعات traceback را درون سایت dpaste: New تنها با یک کلیک کپی می کند و شما می توانید URL آن سایت را برای مشاهده ی traceback شما به دیگران بدهید. در قسمت پایین دکمه ی "Share this traceback on a public Web site" اطلاعات traceback را درون سایت dpaste: New تنها با یک کلیک کپی می کند و شما می توانید URL آن سایت را برای مشاهده ی traceback شما به دیگران بدهید. زیر قسمت "Request information"، بخش "Settings" قرار دارد که لیست تمام تنظیمات انجام شده ی جنگو می باشد. (قسمت ROOT_URLCONF پیش تر بیان شده است، و تنظیمات مختلف دیگر جنگو در سراسر کتاب نشان داده خواهد شد.) صفحه ی خطای جنگو برای نشان دادن اطلاعات بیشتر موارد ویژه، از قبیل خطاهای template syntax بسیار توانا می باشد. در زمان بحث در مورد سیستم tamplate جنگو به این موضوع خواهیم پرداخت. برای حالا، خط offset = int(offset) را از حالت کامنت خارج کنید تا تابع view بتواند دوباره کار کند. آیا شما از آن دسته از برنامه نویسانی هستید که دوست دارید برنامه ی خود را با قرار دادن عبارت print اشکال زدایی کنید؟ شما می توانید برای انجام چنین کاری بدون بکار بردن عبارت print از صفحه ی خطای جنگو استفاده کنید. در هر نقطه ای از view به صورت موقت یک assert False قرار دهید. سپس شما می توانید متغیرهای محلی و وضعیت برنامه را مشاهده کنید: def hours_ahead(request, offset): try: offset = int(offset) except ValueError: raise Http404() dt = datetime.datetime.now() datetime.timedelta(hours=offset) assert False html = "<html><body>In %s hour(s), it will be %s.</body></html>" % (offset, dt) return HttpResponse(html) در پایان، واضح است که بسیاری از اطلاعات حساس هستند، و این موضوع که اطلاعات داخلی کد پایتون و تنظیمات جنگو را برای عموم نشان شود کاری ابلهانه می باشد. افراد مخرب می توانند با استفاده از این اطلاعات دست به کارهای نامطلوبی بزنند. به این دلیل، صفحه ی خطای جنگو تنها زمانی نمایش داده می شود که پروژه ی جنگو در حالت debug باشد. نحوه ی غیر فعال کردن حالت debug در فصل دوازدهم توضیح داده خواهد شد. در حال حاضر، دانستن اینکه هر پروژه ی جنگویی در هنگام ساخت به طور پیشفرض در حال debug می باشد. کافی است. خسته نباشید دوستان عزیز . جلسه سوم کتاب جنگو به پایان رسید . کار ترجمه این کتاب زیاد عالی نیست . ولی برای شروع بد نیست . امیدوارم که موفق باشید . برگرفته از سایت oruji.org ترجمه از سایت www.djangobook.com
  11. با سلام خدمت شما عزیزان با جلسه دوم کتاب جنگو در خدمت شما عزیزان هستیم . این کتاب برگرفته از سایت oruji.org می باشد . امیدوارم که لذت ببرید . هرگونه سوالی دارید در انجمن مربوط به این آموزش بپرسید . در ضمن عزیزانی که علاقه دارن آموزش انگلیسی این کتاب رو مطالعه کنند به آدرس وب سایت زیر مراجعه کنند : www.djangobook.com شروع کار با جنگو (Django) به علت بخش های متحرک چندگانه در محیط های توسعه وب امروزی، نصب کردن جنگو (Django) یک پردازش چند مرحله ای می باشد. در این فصل، به نحوه نصب جنگو فریم ورک وب پایتون (Python) و وابستگی های آن می پردازیم. از آن جهت که جنگو فقط کد پایتون می باشد، هرجایی که پایتون کار کند جنگو نیز کار خواهد کرد، که شامل برخی موبایل ها نیز می شود! اما این فصل تنها مراحل نصب جنگو را پوشش می دهد. فرض می کنیم شما در حال نصب آن روی یک دسکتاپ/نت بوک یا یک سرور هستید. نصب کردن پایتون خود جنگو از پایه با زبان پایتون نوشته شده است، بنابراین اولین قدم در نصب جنگو، نصب کردن پایتون بر روی سیستم می باشد. نسخه های پایتون هسته فریم ورک جنگو با نسخه های پایتون از 2.3 تا 2.7 کار می کند. اگر شما مطمئن نیستید که از کدام نسخه از پایتون استفاده کنید، آخرین نسخه در سری 2 را انتخاب کنید. هر چند جنگو به خوبی با نسخه‌های 2.3 تا 2.7 کار می‌ کند، آخرین نسخه از پایتون بهبودهایی در کارایی و همینطور خصوصیات اضافه‌تری دارد که ممکن است دوست داشته باشید در برنامه‌ی خود استفاده کنید. بنابراین استفاده از آخرین نسخه پایتون شما را در انتخاب آزاد می گذارد. جنگو و پایتون 3 در زمان نوشتن این کتاب، پایتون 3.0 منتشر شده است، اما جنگو هنوز از آن پشتیبانی نمی‌کند. پایتون 3.0 تعدادی تغییرات اساسی دارد که باعث ناسازگاری آن با نسخه‌های قبلی شده است، در نتیجه ما انتظار کتابخانه‌ها و فریم ورک‌های بیشتر را داریم، از جمله جنگو که تا چند سال آینده آن را جبران خواهد کرد. اگر شما در یادگیری پایتون تازه کار هستید و نگران این هستید که آیا باید از پایتون 2 یا 3 شروع کنید، ما توصیه می‌کنیم که با پایتون 2 شروع کنید. مراحل نصب اگر شما با سیستم عامل های لینوکس و یا مکینتاش کار می کنید، احتمالا پایتون را به صورت نصب شده در سیستم خود دارید. دستور python را در command prompt (یا در Applications/Utilities/Terminal) تایپ کنید. اگر شما چیزی شبیه به این مشاهده کردید، بنابراین پایتون نصب شده است. Python 2.4.1 (#2, Mar 31 2005, 00:05:10) [GCC 3.3 20030304 (Apple Computer, Inc. build 1666)] on darwin Type "help", "copyright", "credits" or "license" for more information. >>> در غیر اینصورت شما نیاز دارید تا پایتون را دانلود و نصب کنید. نصب آن بسیار آسان و سریع می باشد. همچنین دستورالعمل های نصب آن در آدرسDownload Python... در دسترس می باشد. در هر زمان دو نسخه متفاوت از جنگو در دسترس می باشد: آخرین نسخه رسمی و نسخه trunk. نسخه‌ای که شما تصمیم به نصب آن دارید به اولیت شما بستگی دارد. آیا شما یک نسخه تست شده و پایدار از جنگو را می خواهید، یا یک نسخه که حاوی آخرین خصوصیات باشد، و شاید شما بتوانید جنگو را برای خودتان گسترش دهید؟ توصیه می کنیم با نسخه رسمی شروع کنید، اما شناختن و دانستن این که نسخه توسعه trunk وجود دارد نیز مهم است، زیرا شما با عضو شدن در انجمن توسعه جنگو می توانید با مستندات جنگو و ساختن آن آشنا شوید. مراحل نصب انتشار رسمی جنگو انتشارهای رسمی دارای شماره نسخه می‌باشند، همانند 1.0.3 یا 1.1، و آخرین نسخه‌ی آن همیشه در این آدرس در دسترس است Download Django... اگر شما از یکی از توزیع‌های لینوکس استفاده می‌کنید که شامل یک پکیج آماده از جنگو است، ایده خوبی است که از نسخه توزیع‌کننده استفاده کنید. در این روش، شما آپدیت‌های امنیتی همراه با بقیه پکیج‌های سیستم را خودکار دریافت خواهید کرد. اگر شما به نسخه prepackaged دسترسی ندارید، می‌توانید به صورت دستی آن را دانلود کرده و نصب کنید. برای انجام چنین کاری، ابتدا باید پرونده tarball را که معمولا نامی مشابه Django-1.0.2-final.tar.gz دارد را دانلود کنید، سپس آن را از حالت فشرده خارج کرده و در خط فرمان setup.py install را اجرا کنید. نحوه عمل کردن در سیستم های یونیکس مشابه زیر است: tar xzvf Django-1.0.2-final.tar.gz cd Django-* sudo python setup.py install در سیستم عامل ویندوز استفاده از 7-Zip (http://www.djangoproject.com/r/7zip/) را توصیه می کنیم. فایل را از حالت فشرده خارج کرده و محیط DOS (Command Promt) را با دسترسی مدیر باز کرده و درون پوشه ای که با نام Django-1.0 ... شروع می‌شود دستور زیر را وارد کنید: python setup.py install فایل های جنگو درون پوشه site-packages برای فایل های نصب شده پایتون نصب خواهند شد، معمولا در این آدرس قرار دارد. usr/lib/python2.4/site-packages تست کردن نصب جنگو بعد از نصب جنگو برای اینکه اطمینان حاصل کنید جنگو به درستی نصب شده و کار می‌کند، درون خط فرمان به شاخه‌ی دیگری بروید (به طور مثال، شاخه‌ای که شامل شاخه‌ی django نباشد) و interactive interpreter پایتون را با تایپ کردن python اجرا کنید. اگر نصب با موفقیت انجام شده باشد، شما باید قادر به import کردن ماژول جنگو باشید: >>> import django >>> django.VERSION (1, 1, 0, 'final', 1) مثال های Interactive Interpreter interactive interpreter پایتون یک برنامه خط فرمان است که به شما اجازه می‌دهد تا کدها و برنامه‌های پایتون را به صورت تعاملی بنویسید. برای شروع کار با آن، تنها کافی است دستور python را در خط فرمان اجرا کنید. در سرتاسر این کتاب، از بخش های interactive interpreter پایتون استفاده شده است. شما می توانید این مثال ها را با سه علامت بزرگتر (<<<) تشخیص دهید. اگر می خواهید این کدها را کپی کنید، نباید علامت های بزرگتر را انتخاب کنید. جملات چند خطی در interactive interpreter با استفاده از سه نقطه (...)، مشخص می شوند: >>> print """This is a ... string that spans ... three lines.""" This is a string that spans three lines. >>> def my_function(value): ... print value >>> my_function('hello') hello این سه نقطه در شروع دستورات چند خطی بوسیله shell پایتون ایجاد می شوند، یعنی جزء بخش هایی نیست که ما وارد کرده باشیم. آغاز یک پروژه هنگامی که شما پایتون، جنگو و (به طور اختیاری) دیتابیس خود را نصب کردید، شما می توانید اولین گام را در توسعه یک برنامه جنگو، با ساختن یک پروژه بردارید. یک پروژه مجموعه ای از تنظیمات برای یک نمونه از جنگو، شامل تنظیمات دیتابیس، گزینه های ویژه جنگو و برنامه ویژه تنظیمات می باشد. اگر این اولین باری است که از جنگو استفاده می کنید، شما باید مراقب بعضی از تنظیمات اولیه باشید. یک پوشه جدید برای شروع کار بسازید، شاید چیزی شبیه به این/home/username/djcode/. این پوشه باید کجا قرار بگیرد اگر زمینه فکری شما PHP باشد، شاید درون document root سرور (جایی مانند /var/www) کد خود را قرار دهید. موقع کدنویسی با جنگو، این کار را انجام ندهید. این ایده خوبی نیست که هر کد پایتونی را داخل document root سرور قرار دهید، زیرا در این حالت این ریسک وجود دارد که امکان دارد بقیه قادر شوند کد خام شما را درون وب تماشا کنند و این خوب نیست. کد خود را در یک پوشه ای بیرون از document root قرار دهید. به مسیر پوشه ای که ساخته اید رفته، و دستور django-admin.py startproject mysite را اجرا کنید. دستور فوق پوشه mysite را درون پوشه ای که قرار دارید می سازد. اگر شما پیام "permission denied" را هنگام اجرا کردن django-admin.py startproject مشاهده کردید، شما نیاز خواهید داشت حق دسترسی فایل را تغییر دهید. برای این منظور، به پوشه ای که django-admin.py در آن نصب شده است رفته (مانند /usr/local/bin) و دستور chmod x django-admin.py را اجرا کنید. دستور startproject یک پوشه حاوی چهار فایل می سازد: mysite/ __init__.py manage.py settings.py urls.py وضیح فایل های بالا در زیر آمده است: __init__.py: یک فایل مورد نیاز پایتون می باشد که توسط آن پوشه mysite یک پکیج تلقی می شود. همچنین فایل فوق یک فایل خالی می باشد، و معمولا شما هیچ چیزی درون آن اضافه نخواهید کرد. manage.py: یک مزیت خط فرمان می باشد که به شما اجازه می دهد با این پروژه جنگو در روش های مختلف در تعامل باشید. دستور python manage.py help را تایپ کنید تا آنچه را که می توانید با این فایل انجام دهید را مشاهده کنید. شما نباید هرگز این فایل را ویرایش یا دستکاری کنید این فایل صرفا برای راحتی کار در این پوشه ساخته شده است. settings.py: تنظیمات/پیکربندی برای پروژه جنگو می باشد. نگاهی به آن بیاندازید تا تنظیمات در دسترس، به همراه مقادیر پیشفرض آن را مشاهده کنید. urls.py: URL ها برای پروژه جنگو. برای لحظاتی فکر کنید فهرست مطالب سایت شما خالی باشد.با وجود حجم کم، این فایل ها کارکرد برنامه جنگو را تشکیل می دهند. با وجود حجم کم، این فایل ها کارکرد برنامه جنگو را تشکیل می دهند. اجرا کردن سرور سرور جنگو (همچنین runserver هم نامیده می شود بعد از دستور راه اندازی آن) یک سرور سبک و داخلی جنگو می باشد که شما می توانید با استفاده از آن سایت خود را توسعه دهید. با استفاده از این سرور شما می تونید به سرعت سایت خود را توسعه دهید، بدون سر و کارداشتن با تنظیمات سرور (مانند Apache) تا زمانی که شما آماده شوید برای راه اندازی سایت. این سرور به طور اتوماتیک هنگامی که شما در کد خود تغییر ایجاد می کنید آن تغییرات را در خودش بروز سازی می کند بدون اینکه شما نیازی به راه اندازی مجدد آن پیدا کنید. برای اجرا کردن سرور، به درون پوشه پروژه رفته (cd mysite)، و دستور زیر را اجرا کنید: python manage.py runserver شما چیزی شبیه به این خواهید دید: Validating models... 0 errors found. Django version 1.0, using settings 'mysite.settings' Development server is running at http://127.0.0.1:8000/ Quit the server with CONTROL-C. دستور بالا سرور را به صورت داخلی روی پورت 8000 راه اندازی می کند، که تنها بر روی رایانه شما قابل دسترس خواهد بود. حالا که سرور در حال اجراست، مسیر http://127.0.0.1:8000/ را روی مرورگر خود مشاهده کنید. شما یک صفحه مانند شکل 1-2 مشاهده خواهید کرد. شکل 1-2 در پایان، نکته مهمی که درباره سرور خود جنگو می باشد را بیان می کنیم، اگر چه این سرور برای توسعه مناسب می باشد، ولی در یک زمان تنها می تواند یک درخواست (request) جواب گو باشد، و همچنین از نظر امنیتی نیز کامل نیست. اطلاعات بیشتر در مورد این موضوع در فصل دوازدهم بیان شده است. تغییر دادن هاست یا پورت به طور پیشفرض، دستور runserver سرور را روی پورت 8000 اجرا می کند، که تنها برای اتصالات محلی می باشد. اگر پورت سرور را تغییر دهید، آنرا به صورت آرگومان به خط فرمان ارسال کنید. python manage.py runserver 8080 با تعیین آدرس IP، شما می توانید به سرور بگویید تا به اتصالات غیر محلی (non-local) اجازه اتصال دهد. این بویژه زمانی مفید خواهد بود که شما بخواهید سایت را با دیگر اعضای تیم خود به اشتراک بگذارید. IP آدرس 0.0.0.0 به سرور می گوید به هر رابط شبکه گوش کن: python manage.py runserver 0.0.0.0:8000 هنگامی که شما دستور فوق را اجرا کنید، رایانه های دیگر در شبکه محلی شما قادر خواهند بود سایت جنگوی شما را با آدرس IP شما در مرورگر خود تماشا کنند، مانند http://192.168.1.103:8000/. (نکته این که شما باید تنظیمات شبکه خودتان را برای تعیین آدرس IP خودتان روی شبکه محلی داشته باشید. کاربران یونیکس، باید سعی کنند ifconfig را در یک خط فرمان برای گرفتن اطلاعات اجرا کنند. کاربران ویندوز باید با دستور ipconfig این کار را انجام دهند.) خسته نباشید دوستان عزیز . جلسه دوم کتاب جنگو به پایان رسید . کار ترجمه این کتاب زیاد عالی نیست . ولی برای شروع بد نیست . امیدوارم که موفق باشید . برگرفته از سایت oruji.org ترجمه از سایت www.djangobook.com
  12. این تاپیک پشتیبانی برای آموزش است کتاب جنگو - شروع کار ( جلسه دوم ) 24/03/96 15:56 24/03/96 16:08 لطفا اگرهر سوال یا بازخوردی دارید اینجا ارسال کنید.