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

 

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

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

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



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

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

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

نوع محتوا


تالار ها

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

وبلاگ‌ها

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

دسته ها

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

دسته ها

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

دسته ها

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

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

  1. این تاپیک پشتیبانی برای آموزش است فریم ورک جنگو ( Django ) چیست ؟ 31/04/96 16:19 31/04/96 16:19 لطفا اگرهر سوال یا بازخوردی دارید اینجا ارسال کنید.
  2. با عرض سلام خدمت تمام پایتونی های عزیز . امیدوارم هرجا هستید موفق و پیروز باشید . در خدمت شما هستیم با مقاله جنگو چیست ؟ با ما همراه باشید . فریم ورک جنگو ( Django ) چیست ؟ در کل یک توضیح کلی درباره فریم ورک جنگو وجود دارد : جنگو ( Django ) یک چارچوب نرم‌افزاری تحت وب آزاد و متن‌باز است که به زبان پایتون نوشته شده است و از معماری MVC ( Model–view–controller) پیروی می‌کند. هدف اصلی جنگو ساخت آسان سایت‌های پیچیده و وابسته به دیتابیس است و بر پایهٔ قابلیت استفادهٔ مجدد و قابل اتصال بودن اجزای مختلف، توسعهٔ سریع و اصل خودت را تکرار نکن (DRY) طراحی شده است. جنگو سراسر از پایتون استفاده می‌کند، حتی برای تنظیمات، فایل‌ها و مدل‌های اطلاعات . تاثیر پایتون بر این فریم ورک کل این فریم ورک با استفاده از زبان پایتون پیاده سازی شده است . پس بسیاری از ویژگی های خود را از زبان پایتون به ارث برده است . با استفاده از این فریم ورک امکان ایجاد وب سایت هایی حرفه ای و پیچیده در کمترین زمان ممکنه و همچنین با در نظر گرفتن مورادی چون امنیت و سرعت و … فراهم می باشد . در ادامه برخی از ویژگی های قابل تاکید زبان پایتون که تاثیر مهمی بر این فریم ورک دارند مطرح می گردد . *** پایتون زبانی تفسیری بوده و برای اجرا نیازی به کامپایل ندارد . در برنامه نویسی وب با استفاده از این ویژگی بعد از تغییر کد یا ایجاد آن نتایج کار بلافاصله قابل مشاهده می باشد . *** انواع داده در پایتون داینامیک می باشد . پس شما نگرانی از تعریف نوع متغییر ندارید . *** سینتکس زبان پایتون کوتاه و در عین حال واضح و قابل فهم می باشد . این بدین معنی هست که برای انجام کار های مشابه کدی بسیار کمتر لازم می باشد . برای مثال معمولا هر خط پایتون معادل ۱۰ خط در جاوا (Java) می باشد !! *** پایتون روشهایی قدرتمند برای meta-programming در اختیار قرار می دهد . این ویژگی امکان ویرایش با اضافه کردن رفتار ها و توابع را با اشیا در زمان اجرای برنامه فراهم می کند . جدایی از ویژگی های فوق جنگو خود روشهایی برای افزایش سرعت و سهولت برنامه نویسی همزمان با رعایت کامل موارد امنیتی و کارایی را دارا می باشد . که در ادامه با برخی از این ویژگی ها بیشتر آشنا خواهیم شد . چرا شما به فریم ورک نیاز دارید؟ برای اینکه واقعا بفهمیم جنگو چیست و چه کاربردهایی داره باید دقت کنیم به سرورها . اولین چیز و مهمترین کار یک سرور این است که برای شما یک صفحه وب را نمایش بگذارد . شما یک صندوق پستی را تصور کنید که نامه ها را دریافت میکند و میخواند . این وظیفه یک سرور می باشد . بعد از خواندن نامه ها یکی یکی صفحاتی که درخواست شده برای نمایش را به نمایش میزاره . اما وقتی میخواهید چیزی را ارسال کنید، باید محتوایی داشته باشید. و جانگو چیزی است که به شما در ایجاد محتوا کمک می کند. چه اتفاقی می افتد وقتی کسی از یک سرور وب سایت شما درخواست می کند؟ هنگامی که یک درخواست به یک وب سرور می آید، به جنگو منتقل می شود که تلاش می کند تا آنچه را که واقعا درخواست شده است، بفهمد. ابتدا آدرس صفحه وب رو تلاش میکنه تا پیدا کنه . این قسمت توسط urlresolver Django انجام می شه . یک لیست از الگوها را می گیرد و تلاش می کند URL را مطابقت بده . جانگو الگوها را از بالا به پایین بررسی می کنه و اگر چیزی هماهنگ باشه با درخواست کاربر ، جانگو درخواست را به تابع مربوطه می فرسته (که آن تابع نمایش داده بشه ). شما دقیقا یک پستچی رو در نظر بگیرید که داره تو یه خیابون راه میره و طبق آدرس نامه ها داره نامه هارو توی خونه ها میندازه . یکی از کارای جنگو هم همینه. پس متوجه شدید که چگونه urlresolver کار می کنه! به نظرم همین توضیح کوتاه کفایت میکنه راجب جنگو در کل همین قدر بدونید که جنگو فریم ورکی و یا به زبان ساده تر یه کتابخونه ای پر از کد هست که قواعد استفاده خاص خودش رو داره و به ما کمک میکنه برای طراحی سایت با پایتون وقت کمتری رو هدر بدیم . وقتی به آموزش های پروژه محور جنگو در لینک زیر نگاه کنید کم کم متوجه خواهید شد که این فریم ورک چقدر کار مارو راحت تر میکنه برای طراحی سایت آموزش پروژه محور جنگو موفق و پیروز باشید . پایتونی ها
  3. این تاپیک پشتیبانی برای آموزش است نصب پایتون ( python ) بر روی لینوکس - اوبونتو ( جلسه چهارم ) 30/02/96 15:53 31/02/96 00:11 لطفا اگرهر سوال یا بازخوردی دارید اینجا ارسال کنید.
  4. View ها و URLconf های پیشرفته در جنگو ( جلسه هشتم ) در آموزش view و urlconf جنگو ، اصول اولیه توابع view و URLconf ها توضیح داده شد. این فصل به جزئیان بیشتری درباره ی عمکرد پیشرفته ی این دو مبحث درون فریم ورک جنگو (Django) خواهد پرداخت. فوت و فن URLconf نکته ی ویژه ای درباره ی URLconf ها وجود ندارد – همانند جنگو، همه چیز فقط کد پایتون می باشد. می توان از این موضوع در روش های مختلفی بهره جست، همانطور که در بخش های این فصل توضیح داده شده است. ساده کردن import توابع URLconf زیر را مشاهده کنید، که در آموزش view و urlconf جنگو ساخته شده است: 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), ) همانطور که در آموزش view و urlconf جنگو توضیح داده شده است، هر آیتم در URLconf شامل تابع view همراه خود می باشد، که به طور مستقیم به صورت شیء تابع، ارسال شده است. این بدین معناست که import کردن توابع view در بالای ماژول امری ضروری می باشد. ولی همانطور که یک برنامه ی جنگو به سمت پیچیدگی رشد می کند، URLconf آن نیز رشد می کند، از این رو استفاده از روش import قبلی می تواند کمی خسته کننده باشد. (برای هر تابع view جدید، باید import کردن آن را نیز فراموش نکرد، و عبارت import در صورتیکه از این روش استفاده کنید بیش از حد بلند می باشد.) این امکان وجود دارد که روش قبلی را با import کردن خود ماژول views دُر بزنید. مثال URLconf زیر برابر با مثال قبلی می باشد: from django.conf.urls.defaults import * from mysite import views urlpatterns = patterns('', (r'^hello/$', views.hello), (r'^time/$', views.current_datetime), (r'^time/plus/(d{1,2})/$', views.hours_ahead), ) جنگو روش دیگری را نیز جهت تعیین تابع view برای یک الگوی خاص در URLconf ارائه می کند: می توان یک رشته حاوی نام ماژول و نام تابع به جای خود شیء تابع ارسال کرد: from django.conf.urls.defaults import * urlpatterns = patterns('', (r'^hello/$', 'mysite.views.hello'), (r'^time/$', 'mysite.views.current_datetime'), (r'^time/plus/(d{1,2})/$', 'mysite.views.hours_ahead'), ) (به علامت تک کتیشن دور نام view ها توجه کنید. در کد فوق از 'mysite.views.current_datetime' با علامت کتیشن به جای mysite.views.current_datetime استفاده شده است.) با استفاده از این تکنیک، import کردن توابع view دیگر ضروری نمی باشد؛ جنگو به طور خودکار با استفاده از رشته ی مشخص شده با نام و مسیر تابع view، تابع view مناسب را import می کند. یک میانبر دیگر که می توان هنگام استفاده از تکنیک رشته از آن استفاده کرد، از قلم انداختن پیشوند view می باشد. در مثال URLconf، هر رشته ی view با 'mysite.views' شروع شده است، که یک حالت اضافی می باشد. می توان پیشوند مشترک این رشته را حذف کرده و آن را به عنوان اولین آرگومان patterns() مانند زیر استفاده کرد: from django.conf.urls.defaults import * urlpatterns = patterns('mysite.views', (r'^hello/$', 'hello'), (r'^time/$', 'current_datetime'), (r'^time/plus/(d{1,2})/$', 'hours_ahead'), ) توجه داشته باشید که نقطه ی عقبی را در پیشوند و رشته های view قرار ندهید. جنگو این نقطه ها را به صورت خودکار قرار خواهد داد. با در نظر گرفتن دو روش فوق، کدام روش بهتر است؟ این بستگی به نحوه ی کد زدن شما و نیازهای کد دارد. مزایای روش رشته: *** این روش بسیار جمع و جور می باشد، زیرا در این روش دیگر نیازی به import کردن توابع view نمی باشد. *** این روش خواناتر بوده و قابلیت مدیریت URLconf ها در صورتیکه توابع view درون چندین ماژول مختلف پخش شده باشد آسان تر خواهد بود. مزایای روش شیء تابع: *** در این روش دسته بندی توابع view آسان می باشد. بخش "دسته بندی توابع view" که در این فصل می باشد را مطالعه کنید. *** این روش پایتونی تر می باشد – چرا که این روش بیشتر در راستای سنت های پایتون می باشد، مانند ارسال توابع به صورت شیء. هر دو روش معتبر می باشند، و می توان حتی این دو روش را درون یک URLconf یکسان با یکدیگر ترکیب کرد. انتخاب با خود شماست. استفاده از پیشوند چندگانه ی view در عمل، در صورتیکه از تکنیک رشته استفاده می کنید، ممکن است هنگامی که URLconf دارای پیشوند مشترک نیست ترکیب view ها را پایان دهید. البته در این حالت نیز می توان هنوز از میانبر پیشوند view برای حذف موارد تکراری سود برد. تنها کافیست از شیء های چندگانه ی patterns() به صورت زیر استفاده کنیم: کد قدیمی: from django.conf.urls.defaults import * urlpatterns = patterns('', (r'^hello/$', 'mysite.views.hello'), (r'^time/$', 'mysite.views.current_datetime'), (r'^time/plus/(\d{1,2})/$', 'mysite.views.hours_ahead'), (r'^tag/(\w )/$', 'weblog.views.tag'), ) کد جدید: from django.conf.urls.defaults import * urlpatterns = patterns('mysite.views', (r'^hello/$', 'hello'), (r'^time/$', 'current_datetime'), (r'^time/plus/(\d{1,2})/$', 'hours_ahead'), ) urlpatterns = patterns('weblog.views', (r'^tag/(\w )/$', 'tag'), ) تمام چهارچوب کار این است که یک متغیر در سطح ماژول با نام urlpatterns وجود داشته باشد. این متغیر می تواند به صورت پویا ساخته شده باشد، همانطور که در مثال فوق انجام داده شده است. به طور خاص باید اشاره کرد که شیء های برگردانده شده با patterns() می توانند به یکدیگر اضافه شده باشند، که این موضوعی است که امکان دارد انتظار آن را نداشته باشید. پوشش خاص URL ها در حالت Debug بعد از صحبت درباره ی ساختن urlpatterns به طور پویا، ممکن است بخواهید از این تکنیک برای تغییر رفتار URLconf ها در حالت debug جنگو استفاده کنید. برای انجام این کار، تنها کافیست مقدار تنظیم DEBUG را در زمان اجرا بررسی کنید، مانند زیر: from django.conf import settings from django.conf.urls.defaults import * from mysite import views urlpatterns = patterns('', (r'^$', views.homepage), (r'^(\d{4})/([a-z]{3})/$', views.archive_month), ) if settings.DEBUG: urlpatterns = patterns('', (r'^debuginfo/$', views.debug), ) در این مثال، آدرس /debuginfo/ تنها در صورتیکه مقدار تنظیم DEBUG، True باشد در دسترس خواهد بود. استفاده از Named Groups در تمام مثال های URLconf ای که تاکنون در این کتاب آورده شده است، از regular expression های ساده ی بدون نام استفاده شده است – یعنی اینکه، تنها آن قسمت از URL مورد نظر درون پرانتز قرار داده شده است، و جنگو آن متن داخل پرانتز را به تابع view به صورت یک آرگومان موضعی (positional argument) ارسال می کرد. برای کاربرد پیشرفته تر، این امکان وجود دارد که از گروه های regular expression نام گذاری شده، برای ارسال قسمت هایی از URL، به صورت آرگومان های کیورد به view استفاده کرد. آرگومان های کیورد در مقابل آرگومان های موضعی یک تابع پایتون می تواند با استفاده از آرگومان های کیورد یا آرگومان های موضعی فراخوانی شود – و در برخی موارد، با استفاده از هردوی آن ها در یک زمان. در یک فراخوانی با استفاده از آرگومان کیورد، شما نام هایی را، برای آرگومان های به همراه مقدارهایی که ارسال خواهد شد، تعیین می کنید. در یک فراخوانی با استفاده آرگومان موضعی، شما به سادگی آرگومان هایی را بدون تعیین صریح مقدار برای آن ارسال می کنید؛ مقدار آن آرگومان به ترتیب قرار گیری آرگومان ها بستگی دارد. برای مثال تابع ساده ی زیر را ملاحظه کنید: def sell(item, price, quantity): print "Selling %s unit(s) of %s at %s" % (quantity, item, price) جهت فراخوانی تابع فوق با آرگومان های موضعی، شما آرگومان ها را به ترتیبی که در تعریف تابع چیده شده اند قرار می دهید: sell('Socks', '$2.50', 6) جهت فراخوانی آن با آرگومان های کیورد، شما نام های آرگومان ها را به همراه مقادیر برای آنها تعیین می کنید. عبارات زیر با هم برابر می باشند: sell(item='Socks', price='$2.50', quantity=6) sell(item='Socks', quantity=6, price='$2.50') sell(price='$2.50', item='Socks', quantity=6) sell(price='$2.50', quantity=6, item='Socks') sell(quantity=6, item='Socks', price='$2.50') sell(quantity=6, price='$2.50', item='Socks') در پایان، تا زمانی که تمام آرگومان های موضعی قبل از آرگومان های کیورد قرار بگیرند می توان آرگومان های کیورد و موضعی را ترکیب کرد،: sell('Socks', '$2.50', quantity=6) sell('Socks', price='$2.50', quantity=6) sell('Socks', quantity=6, price='$2.50') در regular expression های پایتون، نحوه ی کد نویسی برای گروه های نام گذاری شده ی regular expression به این شکل می باشد: (?P<name>pattern)، که name نام گروه و pattern الگوی تطبیق داده شده می باشد. مثال زیر URLconf ای می باشد که از گروه های بدون نام استفاده کرده است: from django.conf.urls.defaults import * from mysite import views urlpatterns = patterns('', (r'^articles/(\d{4})/$', views.year_archive), (r'^articles/(\d{4})/(\d{2})/$', views.month_archive), ) مثال زیر URLconf همسان با مثال قبلی می باشد که با استفاده از گروه های نام گذاری شده باز نویسی شده است: from django.conf.urls.defaults import * from mysite import views urlpatterns = patterns('', (r'^articles/(?P<year>\d{4})/$', views.year_archive), (r'^articles/(?P<year>\d{4})/(?P<month>\d{2})/$', views.month_archive), ) کد فوق دقیقا همان کاری را که در مثال قبلی آمد انجام می دهد، تنها با یک تفاوت: مقادیر داخل پرانتز به جای آرگومان های موضعی به صورت آرگومان های کیورد به توابع view ارسال می شوند. به عنوان مثال، برای گروه های بدون نام، یک درخواست به /articles/2006/03/ در یک فراخوانی تابع برابر با کد زیر خواهد بود: month_archive(request, '2006', '03') برای گروه های نام گذاری شده، فراخوانی تابع به صورت زیر خواهد بود: month_archive(request, year='2006', month='03') در عمل، استفاده از گروه های نام گذاری شده، URLconf ها را کمی واضح تر می کند و آن ها را کمتر در معرض خطاهای ترتیب آرگومان قرار می دهد – و می توان با استفاده از گروه های نام گذاری شده ترتیب آرگومان ها را در تعریف توابع view تغییر داد. در مثال قبلی، در صورت استفاده از گروه های بدون نام اگر می خواستیم آدرس ها را طوری تغییر دهیم که ماه قبل از سال قرار بگیرد، باید این تغییرات را درون تابع month_archive نیز اعمال می کردیم. ولی در صورت استفاده از گروه های نام گذاری شده، تغییر دادن ترتیب پارامتر های داخل پرانتز در regular expression درون URL هیچ تاثیری در view نخواهد داشت. البته،در کنار مزایای گفته شده برای گروه های نام گذاری شده، این روش با هزینه هایی در اختصار همراه است، برخی توسعه دهندگان، گروه های نام گذاری شده را، کد اضافه و بد منظر تشخیص می دهند. ولی همچنان مزیت دیگر گروه های نامگذاری شده خوانایی آن ها می باشد، به ویژه برای کسانی که با regular expression آشنایی نزدیکی در برنامه های جنگو دارند. با یک نگاه در یک URLconf ای که از گروه های نامگذاری شده استفاده کرده است به سادگی می توان آنچه را که اتفاق افتاده است را تشخیص داد. فهمیدن الگوریتم Matchin/Grouping نکته ی مهمی که در استفاده از گروه های نامگذاری شده قابل اهمیت می باشد این است که، یک الگوی URLconf به تنهایی، نمی تواند حاوی گروه های بدون نام و گروه های نام گذاری شده به طور همزمان باشد. در صورتیکه همچین حالتی پیش آید، جنگو هیچ خطایی ایجاد نخواهد کرد، ولی ممکن است URL های شما را، آن طور که انتظار آن را دارید تشخیص ندهد. به طور خاص، در اینجا الگوریتم تجزیه کننده ی URLconf، با توجه به گروه های نام گذاری شده در مقابل گروه های بدون نام در یک regular expression ذکر شده است. *** در صورتیکه هر آرگومان نام گذاری شده ای وجود داشته باشد، از آن ها استفاده خواهد شد و آرگومان های بدون نام نادیده گرفته می شوند. *** در غیر اینصورت، تمام آرگومان های بدون نام به صورت آرگومان های موضعی ارسال می شوند. *** در هر دو مورد، option هایی اضافه به صورت آرگومان های کیورد ارسال می شود. برای اطلاعات بیشتر بخش بعدی را مطالعه کنید. ارسال Option های اضافی به توابع view گاهی اوقات متوجه این موضوع می شوید که توابع view نوشته شده، با وجود اندکی تفاوت، کاملا مشابه با یکدیگر می باشند. برای مثال، فرض می کنیم دو تابع view وجود دارد که بجز template هایی که مورد استفاده قرار می دهند حاوی محتویات یکسان می باشند: # urls.py from django.conf.urls.defaults import * from mysite import views urlpatterns = patterns('', (r'^foo/$', views.foo_view), (r'^bar/$', views.bar_view), ) # views.py from django.shortcuts import render_to_response from mysite.models import MyModel def foo_view(request): m_list = MyModel.objects.filter(is_new=True) return render_to_response('template1.html', {'m_list': m_list}) def bar_view(request): m_list = MyModel.objects.filter(is_new=True) return render_to_response('template2.html', {'m_list': m_list}) در کد فوق تقریبا همه چیز تکرار شده است و این نحوه ی کد زنی به هیچ وجه روش زیبایی به نظر نمی رسد. در ابتدا، ممکن است تصور کنید که با استفاده از یک view برای هر دو URL می توان کدهای اضافه را حذف کرد، و URL ها را در URLconf داخل پرانتز قرار داد، و در آخر نیز آن ها را درون view گفته شده مانند زیر بررسی کنیم: # urls.py from django.conf.urls.defaults import * from mysite import views urlpatterns = patterns('', (r'^(foo)/$', views.foobar_view), (r'^(bar)/$', views.foobar_view), ) # views.py from django.shortcuts import render_to_response from mysite.models import MyModel def foobar_view(request, url): m_list = MyModel.objects.filter(is_new=True) if url == 'foo': template_name = 'template1.html' elif url == 'bar': template_name = 'template2.html' return render_to_response(template_name, {'m_list': m_list}) مشکل راهکار فوق این است که، اگرچه URL های شما با کد شما جفت شده است، ولی در صورتیکه تصمیم بگیرید /foo/ را به /fooey/ تغییر نام دهید، شما نباید فراموش کنید که کد view را نیز تغییر دهید. راهکار زیبا برای این مورد استفاده از یک پارامتر اختیاری برای URLconf می باشد. هر الگویی در یک URLconf ممکن است شامل یک آیتم سوم باشد: یک دیکشنری از آرگومان های کیورد برای ارسال به تابع view. با در نظر گرفتن این، می توان مثال قبلی را به این شکل باز نویسی کرد: # urls.py from django.conf.urls.defaults import * from mysite import views urlpatterns = patterns('', (r'^foo/$', views.foobar_view, {'template_name': 'template1.html'}), (r'^bar/$', views.foobar_view, {'template_name': 'template2.html'}), ) # views.py from django.shortcuts import render_to_response from mysite.models import MyModel def foobar_view(request, template_name): m_list = MyModel.objects.filter(is_new=True) return render_to_response(template_name, {'m_list': m_list}) همانطور که مشاهده می کنید، URLconf در مثال فوق، template_name را درون URLconf تعیین کرده است. تابع view مانند پارامترهای دیگر با template_name رفتار می کند. تکنیک option های اضافه ی URLconf روش مناسبی برای ارسال اطلاعات اضافی برای توابع view با حداقل کد می باشد. به همین دلیل، در بسیاری از برنامه های جنگو از آن استفاده می شود، مهمترین خصوصیت این روش حالت generic داشتن view ها می باشد، که در view های generic درباره ی آن صحبت خواهد شد. بخش های بعدی حاوی تعدادی از ایده ها، نسبت به نحوه ی استفاده از تکنیک option های اضافه ی URLconf در پروژه ها می باشد. Faking Captured URLconf Values فرض را بر این بگیرید که مجموعه ای از view ها دارید که از یک الگو طبعیت می کنند، البته به همراه URL ای دیگر که با الگو سازگار نبوده ولی منطق view آن یکی است. در این مورد، می توان مقدار داخل پرانتز URL را، با استفاده از option های اضافه ی URLconf، برای کنترل URL اضافه با view همسان جا زد. برای مثال، ممکن است برنامه ای داشته باشید که برخی داده ها برای یک روز خاص را نمایش دهند، با URL هایی مانند زیر: /mydata/jan/01/ /mydata/jan/02/ /mydata/jan/03/ # ... /mydata/dec/30/ /mydata/dec/31/ به کار بردن URL های فوق به اندازه ی کافی ساده می باشد – می توان آن ها را درون یک URLconf مانند زیر کنترل کرد (با استفاده از گروه نام گذاری شده): urlpatterns = patterns('', (r'^mydata/(?P<month>\w{3})/(?P<day>\d\d)/$', views.my_view), ) و یک تابع view مانند زیر: def my_view(request, month, day): # .... روش فوق بسیار ساده می باشد – چیزی وجود ندارد که قبلا گفته نشده باشد. تکنیک و فن خاص زمانی پیش می آید، که بخواهید URL دیگری اضافه کنید که از my_view استفاده می کند، ولی حاوی month و day نباشد. برای مثال، ممکن است بخواهید URL دیگری مانند /mydata/birthday/ اضافه کنید، که برابر با /mydata/jan/06/ باشد. می توان از امکان option های اضافه URLconf مانند زیر استفاده کرد: urlpatterns = patterns('', (r'^mydata/birthday/$', views.my_view, {'month': 'jan', 'day': '06'}), (r'^mydata/(?P<month>\w{3})/(?P<day>\d\d)/$', views.my_view), ) نکته ی جالب در کد فوق این است که شما هیچوقت مجبور به تغییر تابع view نمی باشد. تابع view تنها پارامترهای month و day سر و کار دارد – مشکلی نیست اگر این پارامترها به صورت URL داخل پرانتز و یا پارامترهای اضافه ارسال شوند. ساختن یک View Generic حذف کد های تکراری یک تمرین مناسب برای برنامه نویسی می باشد. برای مثال، با این دو تابع پایتون: def say_hello(person_name): print 'Hello, %s' % person_name def say_goodbye(person_name): print 'Goodbye, %s' % person_name می توان hello و goodbye را حذف کرده و آنرا به عنوان پارامتر یک تابع قرار داد: def greet(person_name, greeting): print '%s, %s' % (greeting, person_name) می توان این فلسفه را در view های جنگو نیز با استفاده از پارامترهای اضافه ی URLconf به کار برد. با در نظر گرفتن این موضوع، می توان تصورات سطح بالایی را از view ها ایجاد نمود. بجای آنکه فرض کنیم "این view لیستی از شیء های Event را نمایش می دهد،" می توان در نظر گرفت که "آن view لیستی از شیء های BlogEntry را نمایش می دهد". البته به این موضوع دقت کنید که هر دوی آن ها مورد خاصی هستند "یک view لیستی از شیء ها را نمایش می دهد، که نوع شیء قابل تغییر می باشد." به عنوان مثال نگاهی به کد زیر بیاندازید: # urls.py from django.conf.urls.defaults import * from mysite import views urlpatterns = patterns('', (r'^events/$', views.event_list), (r'^blog/entries/$', views.entry_list), ) # views.py from django.shortcuts import render_to_response from mysite.models import Event, BlogEntry def event_list(request): obj_list = Event.objects.all() return render_to_response('mysite/event_list.html', {'event_list': obj_list}) def entry_list(request): obj_list = BlogEntry.objects.all() return render_to_response('mysite/blogentry_list.html', {'entry_list': obj_list}) هر دو view فوق اساسا یک کار انجام می دهند: آن ها لیستی از شیء ها را نمایش می دهند. بنابراین اجازه دهید نوع شیءی را که نمایش می دهند را حذف کنیم: # urls.py from django.conf.urls.defaults import * from mysite import models, views urlpatterns = patterns('', (r'^events/$', views.object_list, {'model': models.Event}), (r'^blog/entries/$', views.object_list, {'model': models.BlogEntry}), ) # views.py from django.shortcuts import render_to_response def object_list(request, model): obj_list = model.objects.all() template_name = 'mysite/%s_list.html' % model.__name__.lower() return render_to_response(template_name, {'object_list': obj_list}) با تغییرات کوچک فوق، ما به طور ناگهانی دارای یک view قابل استفاده ی مجدد و عمومی شده ایم! از حالا به بعد، در هر زمان که نیاز به یک view داشته باشیم که مجموعه ای از شیء ها را لیست کند، می توان به سادگی از object_list به جای نوشتن کد view استفاده کرد. در زیر توضیحاتی درباره ی کارهای انجام داده ی فوق وجود دارد: کلاس های مدل به طور مستقیم به صورت پارامتر model ارسال شده اند. پارامترهای ارسالی اضافه در URLconf می توانند نه تنها رشته ها، بلکه هر نوعی از شیء های پایتون را ارسال کنند. *** خط model.objects.all() یک مثال ساده از duck typing می باشد: "در صورتیکه چیزی مانند اردک راه برود و مانند اردک صحبت کند، می توان با آن مانند اردک رفتار کرد." دقت کنید که کد مورد نظر نمی داند، که نوع شیء model چه می باشد، تنها نکته ی لازم این است که model دارای یک attribute به نام objects باشد که آن نیز به نوبه ی خود دارای یک متد all() باشد. *** در تعیین نام template از model.__name__.lower() استفاده شده است. هر کلاس پایتون دارای یک attribute با نام __name__ می باشد که نام کلاس را بر می گرداند. این ویژگی برای زمان هایی مانند مثال فوق مفید می باشد، هنگامی که نام کلاس را تا زمان اجرای برنامه نمی دانیم. برای مثال مقدار __name__ برای کلاس BlogEntry رشته ی 'BlogEntry' می باشد. *** تفاوت جزئی بین این مثال و مثال قبلی این است که، متغیر generic ای با نام object_list به template ارسال شده است. می توان به سادگی نام این متغیر را به blogentry_list و یا even_list تغییر داد، ولی ما به عنوان تمرین برای خواننده آن را بدین صورت باقی گذاشته ایم. به دلیل آن که وب سایت های پایگاه داده محور، دارای چندین الگوی مشترک می باشند، جنگو مجموعه ای از "generic view" ها را که دقیقا از تکنیک فوق برای صرفه جویی در زمان استفاده می کنند، ارائه می کند. view های داخلی generic در view های generic توضیح داده شده اند. دادن Option های پیکربندی View در صورتیکه یک برنامه ی جنگو را توزیع (distribute) می کنید، این احتمال وجود دارد که کاربران شما برخی درجات پیکربندی را بخواهند. در این مورد، ایده ی خوبی است که برای هر انتخاب پیکربندی که فکر می کنید افراد ممکن است بخواهند آن را تغییر دهند، hook هایی را در view ها اضافه کنید. یک قسمت مشترک از یک برنامه برای ایجاد قابلیت پیکربندی، نام template می باشد: def my_view(request, template_name): var = do_something() return render_to_response(template_name, {'var': var}) فهمیدن اولویت مقدار داخل پرانتز در مقابل Option های اضافه هنگام وجود مغایرت، پارامترهای اضافه ی URLconf بر پارامترهای داخل پرانتز اولویت دارند. به عبارت دیگر، در صورتیکه URLconf شما، یک متغیر از نوع گروه نام گذاری شده درون پرانتز داشته باشد، و همچنین یک پارامتر اضافه ی URLconf را با متغیر همنام با آن، در این صورت مقدار پارامتر اضافه ی URLconf استفاده خواهد شد. برای مثال URLconf زیر را مشاهده کنید: from django.conf.urls.defaults import * from mysite import views urlpatterns = patterns('', (r'^mydata/(?P<id>\d )/$', views.my_view, {'id': 3}), ) در کد فوق، هر دوی regular expression و دیکشنری اضافه، حاوی یک id می باشند که دیکشنری اضافه دارای اولویت می باشد. این بدین معناست که هر درخواستی (مانند /mydata/2/ یا /mydata/432432) بدین صورت رفتار خواهد کرد که مقدار id بدون در نظر گرفتن مقدار داخل پرانتز URLconf عدد 3 می باشد. خوانندگان زیرک در این مورد توجه خواهند داشت، که قرار دادن id داخل پرانتز در regular expression اتلاف وقت می باشد، زیرا مقدار آن همواره توسط مقدار دیکشنری باز نویسی می شود. درست آن است که؛ در دست ترجمه ... استفاده از آرگومان های پیشفرض View فوت و فن مناسب دیگر، تعیین پارامتر های پیشفرض برای آرگومان های view می باشد. با استفاده از این تکنیک در صورتیکه مقدار یک پارامتر اصلا تعیین نشود از مقدار پیشفرض تعیین شده استفاده می کند. مثال: # urls.py from django.conf.urls.defaults import * from mysite import views urlpatterns = patterns('', (r'^blog/$', views.page), (r'^blog/page(?P<num>\d )/$', views.page), ) # views.py def page(request, num='1'): # Output the appropriate page of blog entries, according to num. # ... در کد فوق، هر دو الگوی URL به یک view اشاره می کنند – views.page – ولی اولین الگو درون URL هیچ مقداری داخل پرانتز قرار نداده است. در صورتیکه اولین الگو تطبیق پیدا کند، تابع page() از مقدار آرگومان پیشفرض num یعنی '1' استفاده خواهد کرد. همچنین در صورت تطبیق الگوی دوم، تابع page() از هر مقداری که توسط regular expression درون پرانتز حاصل می شود استفاده خواهد کرد. (توحه داشته باشید که بایستی مقدار پیشفرض آرگومان را رشته ی '1' قرار دهیم، نه یک integer. زیرا هر مقداری که داخل پرانتز URLconf برای num قرار گرفته است همواره یک رشته خواهد بود.) استفاده از این تکنیک، در رابطه با option های پیکربندی نیز متداول می باشد، همانطور که پیش تر توضیح داده شد. مثال زیر مثال بهبود پیدا کرده ی بخش "دادن option های پیکربندی view" با تهیه ی یک مقدار پیشفرض برای template_name می باشد: def my_view(request, template_name='mysite/my_view.html'): var = do_something() return render_to_response(template_name, {'var': var}) موارد خاص View ها گاهی اوقات شما الگویی در URLconf خواهید داشت که مجموعه ی بزرگی از URL ها را کنترل می کند، ولی شما تنها به یک مورد خاص از آن ها نیاز خواهید داشت. در این موارد، از روش خطی یک URLconf ای که پردازش شده است می توانید استفاده کنید و مورد خاص را اول قرار دهید. برای مثال، می توانید صفحات "add an object" در سایت مدیر جنگو را به صورت نمایش داده شده با یک URLpattern مانند زیر تصور کنید: urlpatterns = patterns('', # ... ('^([^/] )/([^/] )/add/$', views.add_stage), # ... ) کد فوق با URL هایی از قبیل /myblog/entries/add/ و /auth/groups/add/ تطبیق پیدا می کند. اگرچه صفحه ی "add" برای یک شیء user (/auth/user/add/) یک مورد خاص می باشد – تمام فیلدهای فرم را نمایش نمی دهد، بلکه دو فیلد رمز عبور و الی آخر را نمایش می دهد. ما این مشکل را به شکل زیر حل کرده ایم: def add_stage(request, app_label, model_name): if app_label == 'auth' and model_name == 'user': # do special-case code else: # do normal code ولی روش فوق برای یک دلیل که چندین بار در این فصل آن را لمس کرده ایم روش زیبایی نیست: روش فوق منطق URL را درون view قرار می دهد. راهکار بهتر این است که، از این واقعیت سود ببریم که URLconf ها از بالا به پایین پردازش می شوند: urlpatterns = patterns('', # ... ('^auth/user/add/$', views.user_add_stage), ('^([^/] )/([^/] )/add/$', views.add_stage), # ... ) با استفاده از روش فوق، درخواست برای /auth/user/add/ از طریق user_add_stage کنترل خواهد شد. اگرچه که URL با الگوی دوم مطابقت دارد، ولی ابتدا با الگوی بالاتر تطبیق پیدا می کند. پوشش دادن متن در URL ها هر آرگومان پوشش داده شده ای به صورت یک رشته ی یونیکد پایتون به view فرستاده می شود. به عنوان مثال در خط URLconf زیر: (r'^articles/(?P<year>\d{4})/$', views.year_archive), آرگومان year برای views.year_archive() یک رشته خواهد بود، نه یک integer، حتی اگر \d{4} تنها با رشته های از نوع integer مطابقت داشته باشد. بخاطر داشتن این موضوع هنگامی که کد view را می نویسید مهم می باشد. بسیاری از توابع داخلی پایتون نسبت به قبول کردن تنها شیء های از نوع مشخص حساس می باشند. یکی از خطاهای متداول ساختن یک شیء datetime.date با مقادیر رشته به جای مقادیر integer می باشد: >>> import datetime >>> datetime.date('1993', '7', '9') Traceback (most recent call last): ... TypeError: an integer is required >>> datetime.date(1993, 7, 9) datetime.date(1993, 7, 9) تبدیل شده ی به یک URLconf و view، خطایی مانند زیر خواهد بود: # urls.py from django.conf.urls.defaults import * from mysite import views urlpatterns = patterns('', (r'^articles/(\d{4})/(\d{2})/(\d{2})/$', views.day_archive), ) # views.py import datetime def day_archive(request, year, month, day): # The following statement raises a TypeError! date = datetime.date(year, month, day) به جای day_archive() می توان به این شکل آنرا اصلاح نمود: def day_archive(request, year, month, day): date = datetime.date(int(year), int(month), int(day)) توجه داشته باشید که تابع int() خودش هنگامی که یک رشته ی غیر قابل تبدیل به integer به آن ارسال شود یک خطای ValueError ایجاد می کند، ولی از آن جهت که regular expression در URLconf در این مورد تنها رشته های قابل تبدیل به integer (مانند "245") را قبول می کند دیگر نگرانی برای این موضوع وجود نخواهد داشت. تعیین آنچه را که URLconf به دنبال آن جستجو می کند هنگامی که یک درخواست ارسال می شود، جنگو در تلاش بر می آید که الگوهای URLconf را برای URL درخواست شده به صورت رشته ی پایتون تطبیق دهد. این شامل پارامترهای GET یا POST و یا نام دامین نمی شود. همچنین شامل علامت (/) آغازین نیز نمی شود، زیرا هر URL دارای یک علامت (/) آغازین می باشد. برای عنوان مثال، در یک درخواست به http://www.example.com/myapp/، جنگو تلاش می کند تا آن را با myapp/ تطبیق دهد. در یک درخواست به exampl.com جنگو تلاش می کند تا آن را با myapp/ تطبیق دهد. method درخواست (مانند POST، GET) هنگام عبور کردن URLconf به حساب نمی آید. به عبارت دیگر، تمام method های درخواست درون تابع همسان برای URL همسان بررسی می شوند. اجرا کردن method های درخواست به عهده ی تابع view می باشد. تصور سطح بالا از توابع view صحبت کردن درباره ی روش branching based در method درخواست، اجازه دهید به نحوه ی ساخت یک روش زیبا از انجام این روش نگاهی بیاندازیم. لایه ی URLconf و view زیر را ملاحظه کنید: # urls.py from django.conf.urls.defaults import * from mysite import views urlpatterns = patterns('', # ... (r'^somepage/$', views.some_page), # ... ) # views.py from django.http import Http404, HttpResponseRedirect from django.shortcuts import render_to_response def some_page(request): if request.method == 'POST': do_something_for_post() return HttpResponseRedirect('/someurl/') elif request.method == 'GET': do_something_for_get() return render_to_response('page.html') else: raise Http404() در مثال فوق، some_page()، درخواست های POST و GET را کاملا متفاوت کنترل می کند. تنها چیزی که به صورت مشترک دارا می باشند یک URL به اشتراک گذاشته می باشد: /somepage/. به همین دلیل، اینکه با هر دوی POST و GET در یک تابع view سر و کار داشت، روش زیبایی نمی باشد. روش مناسب آن است که دو تابع view مجزا داشته باشیم – یکی درخواست های GET را کنترل کرده و دیگری درخواست های POST را – و مطمئن بود که هر یک تنها در زمان مناسب فراخوانی می شوند. می توان با توشتن یک تابع view که نماینده ی دیگر view ها می باشد، قبل و بعد اجرا برخی جملات منطقی این کار را انجام داد. در مثال زیر نحوه ی انجام این روش در some_page() وجود دارد: # views.py from django.http import Http404, HttpResponseRedirect from django.shortcuts import render_to_response def method_splitter(request, GET=None, POST=None): if request.method == 'GET' and GET is not None: return GET(request) elif request.method == 'POST' and POST is not None: return POST(request) raise Http404 def some_page_get(request): assert request.method == 'GET' do_something_for_get() return render_to_response('page.html') def some_page_post(request): assert request.method == 'POST' do_something_for_post() return HttpResponseRedirect('/someurl/') # urls.py from django.conf.urls.defaults import * from mysite import views urlpatterns = patterns('', # ... (r'^somepage/$', views.method_splitter, {'GET': views.some_page_get, 'POST': views.some_page_post}), # ... ) اجازه دهید کد فوق را مورد بررسی قرار دهیم: *** یک view جدید با نام method_splitter() نوشته شده است، که نماینده ی view های دیگر می باشد. این تابع دو آرگومان کیورد یعنی GET و POST که باید توابع view باشند را جستجو می کند. در صورتیکه request.method مقدارش 'GET' باشد، view مورد نظر یعنی GET را فراخوانی و در صورتیکه مقدار آن 'POST' باشد POST را فراخوانی می کند. همچنین در صورتیکه request.method چیزی غیر از موارد ذکر شده باشد (مانند HEAD و غیره ...) و یا در صورتیکه GET یا POST در تابع عرضه نشده باشند، سپس یک Http404 ایجاد خواهد شد. *** درون URLconf به /somepage/ در method_splitter() اشاره شده و آرگومان های اضافه به آن ارسال شده اند – توابع view به ترتیب برای استفاده از GET و POST. *** در پایان، تابع some_page() به دو تابع view تقسیم شده است – some_page_get() و some_page_post(). این روش بسیار زیباتر از نشان دادن تمام منطق درون یک view می باشد. توجه داشته باشید این توابع view از نظر فنی دیگر لازم نیست request.method را بررسی کنند، زیرا method_splitter() این کار را انجام می دهد. (در آن زمان که some_page_post() فراخوانی شده است، می توان مطئمن بود که مقدار request.method، 'post' می باشد.) حالا، ما دارای یک تابع generic خوب برای خودمان می باشیم که منطق نمایندگی دادن به یک view را با استفاده از request.method به اصطلاح encapsulate کرده است. هیچ چیزی درباره ی method_splitter() گره خورده به برنامه ی خاص نیست، بنابراین می توان در پروژه های دیگر نیز از آن استفاده کرد. یک روش برای بهبود method_splitter() وجود دارد. همانطور که نوشته شده است، این تابع فرض می کند که view های GET و POST آرگومان های غیر از request دریافت نمی کنند. چه می شود اگر بخواهیم از method_splitter یا view هایی که، پارامترهایی متنی را از URL ها می گیرند و یا آرگومان های اختیاری برای خود می گیرند استفاده کنیم؟ برای انجام چنین کاری، می توان از یک ویژگی زیبای پایتون استفاده کرد: آرگومان های متغیر با علامت ستاره. در ابتدا مثالی را نشان خواهیم داد و سپس آن را توضیح می دهیم: def method_splitter(request, *args, **kwargs): get_view = kwargs.pop('GET', None) post_view = kwargs.pop('POST', None) if request.method == 'GET' and get_view is not None: return get_view(request, *args, **kwargs) elif request.method == 'POST' and post_view is not None: return post_view(request, *args, **kwargs) raise Http404 در کد فوق، method_splitter() را تغییر داده ایم، به طوری که آرگومان های کیورد GET و POST در آن حذف شده اند و جای آن ها از *args و **kwargs (به علامت ستاره توجه کنید) استفاده شده است. این یک خصوصیت پویای پایتون می باشد که به یک تابع اجازه می دهد یک تعداد دلخواه از آرگومان ها را که نام آن ها تا زمان اجرا مشخص نخواهد بود قبول کند. در صورتیکه یک علامت ستاره تکی در تعریف یک تابع قبل یک پارامتر قرار دهید، هر آرگومان موضعی به آن تابع در یک تاپل جمع خواهد شد. در صورتیکه دو علامت ستاره قبل از یک پارامتر در تعریف تابع قرار دهید، هر آرگومان کیورد به آن تابع داخل یک دیکشنری جمع می شوند. def foo(*args, **kwargs): print "Positional arguments are:" print args print "Keyword arguments are:" print kwargs در زیر نحوه ی عملکرد آن مشخص شده است: >>> foo(1, 2, 3) Positional arguments are: (1, 2, 3) Keyword arguments are: {} >>> foo(1, 2, name='Adrian', framework='Django') Positional arguments are: (1, 2) Keyword arguments are: {'framework': 'Django', 'name': 'Adrian'} به method_splitter() باز می گردیم، می توانید مشاهده کنید که برای قبول کردن هر آرگومان به تابع و ارسال آنها به همراه view مناسب از *args و **kwargs استفاده کرده ایم. ولی بعد از انجام این کار، دو فراخوانی به kwargs.pop() برای بدست آوردن آرگومان های GET و POST در صورت دسترس ایجاد کرده ایم. (از pop() با یک مقدار پیشفرض None جهت دوری از خطای KeyError در صورتیکه یکی از آن ها تعریف نشده باشد استفاده شده است.) Wrapping View Functions آخرین فن view سود جستن از یک تکنیک پیشرفته ی پایتون می باشد. تصور کنید در سرتاسر view های مختلف متوجه دسته ای از کدهای تکراری شده اید مانند مثال زیر: def my_view1(request): if not request.user.is_authenticated(): return HttpResponseRedirect('/accounts/login/') # ... return render_to_response('template1.html') def my_view2(request): if not request.user.is_authenticated(): return HttpResponseRedirect('/accounts/login/') # ... return render_to_response('template2.html') def my_view3(request): if not request.user.is_authenticated(): return HttpResponseRedirect('/accounts/login/') # ... return render_to_response('template3.html') در کد فوق، هر view با بررسی اینکه request.user تایید شده است یا خیر شروع می شود – کاربر فعلی با موفقیت وارد سایت شده است – و به مسیر /accounts/login/ تغییر مسیر داده می شود. (توجه داشته باشید که هنوز request.user توضیح داده نشده است – در بخش کاربران عضویت و session درباره ی این موضوع بحث شده است – ولی، همانطور که ممکن است تصور کنید، request.user کاربر فعلی را نمایش می دهد) بسیار زیبا می باشد اگر قسمت های تکراری کد موجود در هر کدام از view ها حذف شوند و تنها در صورت نیاز آن ها را علامت گذاری کرد. می توان این کار را با ساختن یک view wrapper انجام داد. چند لحظه ای کد زیر را مطالعه کنید: def requires_login(view): def new_view(request, *args, **kwargs): if not request.user.is_authenticated(): return HttpResponseRedirect('/accounts/login/') return view(request, *args, **kwargs) return new_view تابع فوق، requires_login، یک تابع view (view) را دریافت می کند و یک تابع view جدید (new_view) بر می گرداند. تابع جدید، new_view داخل requires_login تعریف شده و منطق بررسی request.user.is_authenticated() و محول کردن view اصلی (view) را کنترل می کند. حالا می توان بررسی if not request.user.is_authenticated() از view ها حذف کرد و با requires_login در URLconf قرار داد: from django.conf.urls.defaults import * from mysite.views import requires_login, my_view1, my_view2, my_view3 urlpatterns = patterns('', (r'^view1/$', requires_login(my_view1)), (r'^view2/$', requires_login(my_view2)), (r'^view3/$', requires_login(my_view3)), ) کد فوق تاثیر یکسانی را به صورت قبل داراست، ولی با زوائد کد کمتر. حالا ما یک تابع generic زیبا ساخته ایم – requires_login() که می توان برای هر تابع view به منظور نیاز به ورود به سایت استفاده کرد. در بر داشتن URLconf های دیگر در صورتیکه قصد دارید کد شما در سایت های گوناگون ایجاد شده توسط جنگو استفاده شود، شما باید URLconf های خود را به روشی تنظیم کنید که "including" برای آن ها مقدور باشد. در هر نقطه، URLconf شما می تواند ماژول های دیگر URLconf را شامل شود. برای مثال، URLconf زیر حاوی URLconf های دیگری نیز می باشد: from django.conf.urls.defaults import * urlpatterns = patterns('', (r'^weblog/', include('mysite.blog.urls')), (r'^photos/', include('mysite.photos.urls')), (r'^about/$', 'mysite.views.about'), ) (روش فوق را قبل تر در سایت مدیر مشاهده کرده اید، هنگامی که سایت مدیر جنگو معرفی شده است. سایت مدیر دارای URLconf خودش می باشد که شما تنها داخل URLconf دیگر آن ها را وارد کردید.) یک مفهوم مهم در اینجا وجود دارد: regular expression ها که در این مثال به یک include() اشاره می کنند، دارای علامت ($) نمی باشند. هر زمان که جنگو با include() برخورد می کند، هر بخش از URL مطابقت داده شده با آن نقطه را برش می دهد و رشته ی باقیمانده برای URLconf ای که Include شده را جهت پردازش بیشتر می فرستد. به مثال زیر توجه کنید: from django.conf.urls.defaults import * urlpatterns = patterns('', (r'^(\d\d\d\d)/$', 'mysite.blog.views.year_detail'), (r'^(\d\d\d\d)/(\d\d)/$', 'mysite.blog.views.month_detail'), ) با این دو URLconf، در اینجا نحوه ی کنترل تعدادی از درخواست ها وجود دارند: *** /weblog/2007/: در اولین URLconf، الگوی r'weblog/' تطبیق داده می شود. زیرا آن یک include() است، جنگو تمام متن مطابق را در می آورد، که در این مورد 'weblog/' می باشد. پاقیمانده ی بخش URL 2007/ می باشد، که اولین خط در URlconf مورد نظر یعنی mysite.blog.urls تطبیق داده می شود. *** /weblog//2007/ (با دو علامت /) در اولین URLconf، الگوی r'weblog/' تطبیق داده می شود. زیرا یک include() می باشد، جنگو تمام متن مطابق را در می آورد، که در این مورد 'weblog/' می باشد. باقیمانده ی بخش URL /2007/ می باشد (با یک علامت / اولیه)، که هیچ خطی از URLconf مورد نظر یعنی mysite.blog.urls با آن تطبیق داده نمی شود. *** /about/: این URL در URLconf اول و view مورد نظر یعنی mystie.views.about تطبیق داده می شود، نشان می دهد که می توان الگوهای include() را با الگوهای non-include() ترکیب کرد. نحوه ی کار با include() پارامترهای پوشش داده شده یک URLconf شامل شده، هر پارامتر پوشش داده شده ای از URLconf های پدر را دریافت می کند، برای مثال: # root urls.py from django.conf.urls.defaults import * urlpatterns = patterns('', (r'^(?P<username>\w )/blog/', include('foo.urls.blog')), ) # foo/urls/blog.py from django.conf.urls.defaults import * urlpatterns = patterns('', (r'^$', 'foo.views.blog_index'), (r'^archive/$', 'foo.views.blog_archive'), ) در مثال فوق، متغیر پوشش داده شده ی username به URLconf شامل شده و هر تابع view موجود در آن URLconf ارسال شده است. توجه داشته باشید که پارامترهای پوشش داده شده همواره به هر خط در URLconf شامل شده صرف نظر از اینکه آیا view آن خط واقعا آن پارامتر های به صورت معتبر قبول خواهد کرد یا خیر ارسال شده خواهند بود. به همین دلیل، این تکنیک تنها در صورتیکه شما مطمئن باشید که هر view در URLconf شامل شده پارامترهای ارسال شده را قبول می کند مفید خواهد بود. نحوه option های اضافه URLconf در کار با include() به طور مشابه، می توان انتخاب های اضافه ی URLconf به include() ارسال کرد، همانطور که می توان option های اضافه ی URLconf را به یک view معمولی ارسال کرد – به صورت یک دیکشنری. هنگامی که شما این کار را انجام دهید، هر خط در URLconf شامل شده، option اضافه ی ارسال شده خواهد بود. برای مثال، دو دسته ی URLconf زیر دارای عملکرد یکسان می باشند. دسته ی اول: # urls.py from django.conf.urls.defaults import * urlpatterns = patterns('', (r'^blog/', include('inner'), {'blogid': 3}), ) # inner.py from django.conf.urls.defaults import * urlpatterns = patterns('', (r'^archive/$', 'mysite.views.archive'), (r'^about/$', 'mysite.views.about'), (r'^rss/$', 'mysite.views.rss'), ) دسته دوم : # urls.py from django.conf.urls.defaults import * urlpatterns = patterns('', (r'^blog/', include('inner')), ) # inner.py from django.conf.urls.defaults import * urlpatterns = patterns('', (r'^archive/$', 'mysite.views.archive', {'blogid': 3}), (r'^about/$', 'mysite.views.about', {'blogid': 3}), (r'^rss/$', 'mysite.views.rss', {'blogid': 3}), ) خسته نباشید دوستان عزیز . جلسه هشتم کتاب جنگو به پایان رسید . امیدوارم که موفق باشید . برگرفته از سایت oruji.org ترجمه از سایت www.djangobook.com
  5. آموزش فرم در جنگو فرم های HTML ستون فقرات تعامل وب سایت ها می باشند، برای فرم های ساده می توان جعبه ی جستجوی گوگل را مثال زد و برای فرم های پیچیده می توان رابط های ثبت نام برای سایت های بزرگ را مثال زد. در این فصل نحوه ی دسترسی به داده های فرم که توسط کاربر ارائه می شود، تایید کردن آن و انجام برخی کارها به روی آن ها خواهیم پرداخت. در طول فصل، HttpRequest و شیء های Form را توضیح خواهیم داد. دریافت داده از شیء Request شیء های HttpRequest در آموزش view و urlconf جنگو هنگامی که اولین توابع view را ایجاد کردیم معرفی شده است، ولی صحبت زیادی درباره ی آن ها در آن زمان صورت نگرفت. یادآوری می کنیم که هر تابع view یک شیء HttpRequest به عنوان اولین پارامتر دریافت می کند، همانطور که در تابع hello() مشاهده می کنید: from django.http import HttpResponse def hello(request): return HttpResponse("Hello world") شیء های HttpRequest مانند متغیر request فوق، دارای attribute های و متدهای جالبی می باشند که می بایست با آن ها آشنا شوید. می توان از این attribute ها برای به دست آوردن اطلاعات درباره ی درخواست فعلی استفاده کرد (مانند مرورگری که در حال بارگذاری صفحه ی فعلی می باشد)، در زمانی که تابع view اجرا شده است. اطلاعات درباره ی آدرس همواره از attribute ها/متدها به جای کد مستقیم آدرس درون view ها استفاده کنید. حرکت مذکور انعطاف پذیری کد را جهت استفاده در مکان های دیگر بیشتر می کند. یک مثال ساده: # BAD! def current_url_view_bad(request): return HttpResponse("Welcome to the page at /current/") # GOOD def current_url_view_good(request): return HttpResponse("Welcome to the page at %s" % request.path) اطلاعات دیگر درباره ی Request request.META یک دیکشنری پایتون است که تمام HTTP header های درخواست داده شده را شامل شده است – مانند آدرس IP و همچنین نام و نسخه ی مرورگر کاربر. توجه داشته باشید که لیست header های در دسترس به آن header هایی بستگی دارد که کاربر فرستاده و وب سرور قرار داده است. برخی از کلید های در دسترس رایج در این دیکشنری: *** HTTP_REFERER : اشاره کردن به آدرس، در صورت وجود. *** HTTP_USER_AGENT : رشته ی مرورگر کاربر، در صورت وجود. که چیزی شبیه به این می باشد: "Mozilla/5.0 (X11; U; Linux i686; fr-FR; rv:1.8.1.17) Gecko/20080829 Firefox/2.0.0.17". *** REMOTE_ADDR : آدرس IP کلاینت مانند "12.345.67.89". (در صورتیکه درخواست از میان پروکسی ارسال شده باشد، ممکن است با یک جدا کننده ی کاما نشان داده شود مانند "12.345.67.89,23.456.78.90") توجه داشته باشید، چراکه request.META یک دیکشنری پایتون می باشد، در صورتیکه بخواهید به کلیدی که وجود ندارد دسترسی پیدا کنیدخطای KeyError رخ خواهد داد. (زیرا HTTP header داده ی خارجی می باشد – که توسط مرورگر کاربر شما تایید شده است – نباید به آن ها اعتماد شود، و باید همواره برنامه ی خود را طوری طراحی کنید که در صورت خالی بودن یک header خاص یا عدم وجود به شکل درستی آن را رد کند.) می بایست از یک عبارت try/except یا متد get() برای مواردی که یک کلید تعریف نشده است استفاده کرد: # BAD! def ua_display_bad(request): ua = request.META['HTTP_USER_AGENT'] # Might raise KeyError! return HttpResponse("Your browser is %s" % ua) # GOOD (VERSION 1) def ua_display_good1(request): try: ua = request.META['HTTP_USER_AGENT'] except KeyError: ua = 'unknown' return HttpResponse("Your browser is %s" % ua) # GOOD (VERSION 2) def ua_display_good2(request): ua = request.META.get('HTTP_USER_AGENT', 'unknown') return HttpResponse("Your browser is %s" % ua) شما را تشویق می کنیم تا یک view کوچک بنویسید که تمام داده های request.META را نمایش دهد بنابراین می توانید با دلیل وجود آن ها را آشنا شوید: def display_meta(request): values = request.META.items() values.sort() html = [] for k, v in values: html.append('<tr><td>%s</td><td>%s</td></tr>' % (k, v)) return HttpResponse('<table>%s</table>' % '\n'.join(html)) همچنین می توان view فوق را با استفاده از سیستم template جنگو به جای نوشتن کد مستقیم HTML تبدیل کنید. همچنین سعی کنید request.path و دیگر متدهای HttpRequest را از فصل قبل اضافه کنید. اطلاعات درباره ی داده ی تایید (submit) شده خارج از ابر داده های پایه درباره ی درخواست، شیء های HttpRequest دارای دو attribute هستند که حاوی اطلاعات تایید شده توسط کاربر می باشند: request.GET و request.POST. هر دوی این ها شیء های دیکشنری مانند می باشند که از طریق آن ها می توان به داده های نوع GET و POST دسترسی پیدا کرد. شیء های دیکشنری مانند هنگامی که گفته می شود request.GET و request.POST شیء های دیکشنری مانند می باشند، منظور این است که آن ها مانند دیکشنری های استاندارد پایتون رفتار می کنند ولی از نظر فنی دیکشنری پایتون نمی باشند. به عنوان مثال، request.GET و request.POST دارای متدهای get()، keys() و value() هستند، می توان درون کلیدها با for key in request.GET به جستجو پرداخت. بنابراین چرا با یکدیگر فرق می کنند؟ زیرا هر دوی request.GET و request.POST دارای متدهای اضافی ای می باشند که دیکشنری های معمولی فاقد آن متدها می باشند. شما ممکن است با اصطلاح شبیه به اصطلاح قبلی یعنی شیء های فایل مانند مواجه شده باشید – شیء های پایتون دارای تعدادی متد اولیه می باشند، مانند read() که اجازه می دهد به صورت جانشین برای شیء های واقعی فایل ایفای نقش کنند. داده ی POST عموما تایید شده از <form> HTML می باشد، در حالی که داده ی GET می تواند از یک <form> یا query string در آدرس صفحه آمده باشد. یک مثال ساده ی کنترل فرم مثال books کتاب را با کتاب ها، نویسندگان و ناشران دنبال می کنیم، اجازه دهید یک view ساده را که به کاربران اجازه ی جستجو کتاب ها را بر اساس عنوان می دهد، بسازیم. معمولا، دو بخش برای توسعه ی یک فرم وجود دارد: رابط کاربر HTML و کد view که در بطن کار قرار دارد و داده ی تایید شده توسط کاربر را پردازش می کند. بخش اول ساده می باشد؛ اجازه دهید یک view را که فرم جستجو را نمایش می دهد راه اندازی کنیم : from django.shortcuts import render_to_response def search_form(request): return render_to_response('search_form.html') همانطور که در آموزش view در جنگو یاد گرفتیم، view فوق را می تواند هر جایی در مسیر پایتون قرار دهیم. در اینجا آن را درون books/views.py قرار می دهیم. template همراه، search_form.html چیزی شبیه به کد زیر خواهد بود: <html> <head> <title>Search</title> </head> <body> <form action="/search/" method="get"> <input type="text" name="q"> <input type="submit" value="Search"> </form> </body> </html> URLpattern در urls.py نیز می تواند چیزی شبیه به کد زیر باشد: from mysite.books import views urlpatterns = patterns('', # ... (r'^search-form/$', views.search_form), # ... ) (توجه داشته باشید که ماژول views به جای آنکه به این شکل from mysite.views imort search_form به درون برنامه import شود، به طور مستقیم import شده است، زیرا این روش کوتاه تر می باشد، این روش import در آموزش view و urlconf پیشرفته با جزئیات بیشتری بحث خواهد شد.) حالا، در صورتیکه دستور runserver را اجرا کنید و آدرس http://127.0.0.1:8000/search‑form/ درون مرورگر ملاحظه کنید، رابط جستجو را ملاحظه خواهید کرد که به اندازه ی کافی ساده می باشد. سعی کنید که فرم را تایید کنید، که در اینصورت خطای 404 جنگو را مشاهده خواهید کرد. فرم به آدرس /search/ اشاره می کند، که هنوز اجرا نشده است. اجازه دهید این مشکل را با view دوم حل کنیم: # urls.py urlpatterns = patterns('', # ... (r'^search-form/$', views.search_form), (r'^search/$', views.search), # ... ) # views.py def search(request): if 'q' in request.GET: message = 'You searched for: %r' % request.GET['q'] else: message = 'You submitted an empty form.' return HttpResponse(message) در حال حاضر، کد فوق تنها یک صفحه ی جستجو را نمایش می دهد، ولی می توان مطمئن شد که داده برای جنگو ارسال شده است، و می توان نحوه ی جریان جستجو را در سیستم متوجه شد. به طور خلاصه: <form> یک متغیر q تعریف می کند. هنگامی که فرم تایید می شود، ارزش q از طریق GET (method="get") به آدرس /search/ فرستاده می شود. view جنگو که آدرس /search/ (search()) را کنترل می کند به ارزش q در request.GET دسترسی دارد. نکته مهم برای اشاره در اینجا این است که، به طور صریح بررسی شده است که 'q'درون request.GET وجود دارد یا خیر. همانطور که در بخش گذشته به request.META اشاره شد، شما نباید به هرچیزی که توسط کاربر فرستاده می شود اعتماد کنید و یا حتی فرض کنید که در وهله ی اول چیزی ارسال نمی شود. در صورتیکه این بررسی صورت نگیرد، هر ارسالی از فرم خالی باعث بروز خطای KeyError خواهد شد: # BAD! def bad_search(request): # The following line will raise KeyError if 'q' hasn't # been submitted! message = 'You searched for: %r' % request.GET['q'] return HttpResponse(message) پارامترهای query string داده ی GET در query string ارسال می شود (مانند /search/?q=django)، می توان برای دسترسی به متغیرهای query string از request.GET استفاده کرد. در آموزش view و urlconf جنگو در بخش معرفی سیستم URLconf جنگو، آدرس های زیبای جنگو با آدرس های قدیمی PHP/Java مانند /time/plus?hours=3 مقایسه شد و همچنین گفته شد که در فرم نحوه ی دسترسی به به این آدرس های قدیمی نشان داده خواهد شد. حالا نحوه ی دسترسی به پارامترهای query string در view (مانند hours=3 در مثال فوق) را می دانید – با استفاده از request.GET. داده ی پست نیر مانند داده ی GET عمل می کند – تنها از request.POST به جای request.GET استفاده می کند. تفاوت بین GET و POST در چیست؟ از روش GET هنگامی که تنها یک درخواست برای بدست آوردن داده می باشد استفاده می شود. از داده ی پست هر زمان که ارسال درخواست دارای برخی تاثیرات زیان بار باشد استفاده می شود – تغییر دادن داده، اراسل یک پست الکترونیک، و یا چیز دیگر که ورای نمایش ساده ی داده باشد. در مثال جستجوی ما، از روش GET استفاده شده است که زیرا هیچ داده ای قرار نیست درون سرور تغییر کند. (در صورتیکه می خواهید اطلاعات بیشتری در رابطه با روش های GET و POST به دست آورید می توانید به این آدرس مراجعه کنید: http://www.w3.org/2001/tag/doc/whenToUseGet.html). اکنون که از روش GET استفاده شده است، اجازه دهید درون پایگاه داده به جستجوی کتاب مورد نظر بگردیم: from django.http import HttpResponse from django.shortcuts import render_to_response from mysite.books.models import Book def search(request): if 'q' in request.GET and request.GET['q']: q = request.GET['q'] books = Book.objects.filter(title__icontains=q) return render_to_response('search_results.html', {'books': books, 'query': q}) else: return HttpResponse('Please submit a search term.') نکاتی که در کد فوق وجود دارد: *** گذشته از بررسی اینکه 'q' درون request.GET وجود دارد یا خیر، همچنین در کد فوق قبل از اینکه مقادی به پایگاه داده ارسال شود اطمینان حاصل شده است که request.GET['q'] مقدار خالی نداشته باشد. *** درون کد فوق از Book.objects.filter(title__icontains=q) جهت پرسیدن اینکه آیا عنوانی شامل 'q' درون جدول کتاب ها وجود دارد یا خیر استفاده شده است. icontains یک نوع جستجو (که در آموزش مدل جنگو توضیح داده شده است) می باشد، عبارت می تواند تقریبا به این حالت ترجمه شود که "کتاب هایی که حاوی q بدون حساسیت به حروف بزرگ و کوچک می باشند را جستجو کن". این یک روش بسیار ساده برای جستجوی کتاب می باشد. البته پیشنهاد نمی شود که از icontains در پایگاه داده های بزرگ محصولات استفاده شود زیرا در این حالت می تواند بسیار کند عمل کند. *** books (یک لیست از شیء های کتاب) به template ارسال شده است. کد template برای search_results.html ممکن است شامل چیزی شبیه به این باشد: <p>You searched for: <strong>{{ query }}</strong></p> {% if books %} <p>Found {{ books|length }} book{{ books|pluralize }}.</p> <ul> {% for book in books %} <li>{{ book.title }}</li> {% endfor %} </ul> {% else %} <p>No books matched your search criteria.</p> {% endif %} به کاربرد فیلتر template فوق یعنی pluralize توجه کنید، در صورتیکه مقدار لیست books بیشتر از یکی باشد حرف "s" را بر می گرداند. اصلاح نمودن مثال ساده ی کنترل فرم همانند فصل گذشته، یک فرم ساده از موضوع مورد بحث را نشان دادیم، حالا به برخی از مشکلات اشاره کرده و نحوه ی اصلاح آن را نشان خواهیم داد. ابتدا، کنترل کردن یک ورودی خالی توسط تابع search() بسیار ضعیف می باشد – تنها نمایش داده یک پیام "Please submit a search term."، نیازمند این است که کاربر دکمه ی برگشت مرورگر را برای بازگشت به صفحه فشار دهد. این یک حالت نامطلوب و غیر حرفه ای می باشد، و در صورتیکه همیشه به این شکل کار می کنید، شما از امتیازات ویژه ی جنگو خود را محروم خواهید کرد. اینکه در هنگام بروز خطا فرم نیز دوباره نمایش داده شود خیلی روش بهتری می باشد، به طوری که خطا در همان صفحه و در بالای فرم نمایش داده شود و کاربر بتواند به سرعت دوباره فرم را پر کرده و ارسال کند، چیزی مانند کد زیر: from django.http import HttpResponse from django.shortcuts import render_to_response from mysite.books.models import Book def search_form(request): return render_to_response('search_form.html') def search(request): if 'q' in request.GET and request.GET['q']: q = request.GET['q'] books = Book.objects.filter(title__icontains=q) return render_to_response('search_results.html', {'books': books, 'query': q}) else: return render_to_response('search_form.html', {'error': True}) (توجه داشته باشید که تابع search_form() در کد فوق ایجاد شده است، بنابراین شما می توانید هر دوی view را در یک مکان مشاهده کنید.) در مثال فوق تابع search() در صورتیکه فرم ارسالی خالی باشد، برای ارائه ی دوباره ی template مورد نظر یعنی search_form.html اصلاح شده است. و بدلیل نمایش یک پیام خطا در آن template، یک متغیر template ارسال شده است. حالا می توان search_form.html را جهت بررسی متغیر error بدین شکل ویرایش کرد: <html> <head> <title>Search</title> </head> <body> {% if error %} <p style="color: red;">Please submit a search term.</p> {% endif %} <form action="/search/" method="get"> <input type="text" name="q"> <input type="submit" value="Search"> </form> </body> </html> می توان همچنان از این template برای view اصلی یعنی search_form() استفاده کرد، زیرا search_form() هیچ متغیر error ای به template ارسال نمی کند – بنابراین پیام خطا در این مورد نشان داده نخواهد شد. با تغییر فوق در اینجا، برنامه ی فعلی بهتر شده است، ولی این سوال پیش می آید: آیا وجود تابع search_form() واقعا ضروری است؟ یک درخواست به آدرس /search/ (بدون هیچ پارامتری از نوع GET) یک فرم خالی را نمایش خواهد داد (ولی با یک خطا). می توان تابع search_form() را به همراه URLpattern های همراه آن، تا زمانیکه کسی با هیچ پارامتر GET ای از /search/ بازدید می کند حذف نمود: def search(request): error = False if 'q' in request.GET: q = request.GET['q'] if not q: error = True else: books = Book.objects.filter(title__icontains=q) return render_to_response('search_results.html', {'books': books, 'query': q}) return render_to_response('search_form.html', {'error': error}) با تغییر فوق، در صورتیکه یک کاربر آدرس /search/ را با هیچ پارامتر GET ای بازدید کند، فرم جستجو را با هیچ پیام خطایی مشاهده خواهد کرد. در صورتیکه یک کاربر فرم را با یک مقدار خالی برای 'q' ارسال کند، صفحه ی جستجو را با یک پیام خطا مشاهده خواهد کرد. و در پایان، در صورتیکه یک کاربر فرم را به یک مقدار پر برای 'q' اراسل کند، نتایج جستجو در پایگاه داده را مشاده خواهد کرد. می توان یک اصلاح پایانی جهت حذف یک قسمت زائد برای برنامه ی فوق ایجاد نمود. اکنون که دو view و آدرس را یکی شد و /search/ هر دوی نمایش فرم جستجو و نمایش نتیجه را کنترل می کند، فرم HTML در search_form.html نباید یک آدرس مستقیم داشته باشد. بجای کد زیر: <form action="/search/" method="get"> می توان بدین شکل عمل کرد: <form action="" method="get"> action="" یعنی "فرم را به آدرس همین صفحه ی فعلی ارسال کن." با تغییر فوق در اینجا، در صورتیکه همیشه تابع search() را به آدرس دیگر ارسال می کرده اید، دیگر لازم نیست تغییر دادن action را بیاد بیاورید. تایید اعتبار آسان مثال جستجوی بخش قبلی از نظر منطقی هنوز هم ساده است، مخصوصا در مورد تایید اعتبار داده؛ تنها اطمینان حاصل شد که مقدار ارسالی خالی نباشد. بسیاری از فرم های HTML حاوی یک سطح تایید اعتبار می باشند که پیچیده تر از اطمینان حاصل کردن از مقدار غیر خالی است. همه ی پیام های خطایی به این شکل درون وب دیده ایم: *** "لطفا یک آدرس الکترونیکی معتبر وارد کنید. 'foo' یک آدرس پست الکترونیکی نیست." *** "لطفا یک کد پستی پنج رقمی معتبر وارد کنید. '123' پست الکترونیکی نیست." *** "لطفا یک تاریخ معتبر با قالب بندی YYYY-MM-DD وارد کنید." *** لطفا رمز عبوری وارد کنید که حداقل هشت حرف داشته و حاوی حداقل یک عدد باشد. یک نکته در تایید اعتبار جاوا اسکریپت این موضوع خارج از حوصله ی این کتاب می باشد، ولی می توان از جاوا اسکریپت برای تایید اعتبار داده در سمت کلاینت به طور مستقیم در مرورگر استفاده کرد. اما آگاه باشید: حتی اگر این کار انجام دهید، باید در سمت سرور نیز داده را تایید اعتبار کنید. برخی افراد جاوا اسکریپت را خاموش می کنند، و برخی کاربران مخرب ممکن است برخی داده های غیر معتبر را برای مشاهده ی اینکه آیا می توانند تخریبی ایجاد کنند یا خیر درون کنترل کننده ی فرم ارسال می کنند. هیچ کاری نمی توانید انجام دهید، غیر از اینکه همواره داده های ارسالی از سمت کاربر را در سمت سرور (مانند view های جنگو) تایید اعتبار کنید. باید اینگونه تصور کرد که تایید اعتبار جاوا اسکریپت نوعی ویژگی قابل استفاده اضافی می باشد، نه تنها به معنی یک تایید اعتبار. اجازه دهید view قبلی یعنی search() را کمی پیچیده کنیم، به طوری که کاربر تنها بتواند داده ی ورودی برای جستجو را کمتر یا مساوی با بیست حرف وارد کند. (برای مثال، می توان این چنین گفت که هر چیزی طولانی تر مقدار گفته شده می تواند باعث کندی جستجو شود.) چه طور می توان آن را انجام داد؟ ساده ترین روش ممکن است قرار دادن منطق مورد نظر به طور مستقیم درون view می باشد، مانند زیر: def search(request): error = False if 'q' in request.GET: q = request.GET['q'] if not q: error = True elif len(q) > 20: error = True else: books = Book.objects.filter(title__icontains=q) return render_to_response('search_results.html', {'books': books, 'query': q}) return render_to_response('search_form.html', {'error': error}) حالا، در صورتیکه سعی کنید یک داده را برای جستجو با بیشتر از بیست حرف ارسال کنید، اجازه ی جستجو داده نخواهد شد؛ یک پیام خطا دریافت خواهید کرد. ولی پیام خطا در search_form.html در حال حاضر "Please submit a search term." می باشد. – بنابراین باید طوری آن را تغییر داد که برای هر دو مورد صحیح باشد: <html> <head> <title>Search</title> </head> <body> {% if error %} <p style="color: red;">Please submit a search term 20 characters or shorter.</p> {% endif %} <form action="/search/" method="get"> <input type="text" name="q"> <input type="submit" value="Search"> </form> </body> </html> در کد فوق نکته ای غیر زیبا وجود دارد. پیام خطای واحد برای همه کمی گیج کننده است. چرا باید پیام خطا برای یک فرم خالی ارسالی محدودیت بیست حرف را بیان کند؟ پیام خطا باید خاص، غیر مبهم بوده و گیج کننده نباشد. در واقع مشکل آن است که از یک مقدار Boolean سایده برای خطا استفاده شده است، در حالیکه باید از یک لیست رشته های پیام خطا استفاده شود، در زیر نحوه ی حل این مشکل نشان داده شده است: def search(request): errors = [] if 'q' in request.GET: q = request.GET['q'] if not q: errors.append('Enter a search term.') elif len(q) > 20: errors.append('Please enter at most 20 characters.') else: books = Book.objects.filter(title__icontains=q) return render_to_response('search_results.html', {'books': books, 'query': q}) return render_to_response('search_form.html', {'errors': errors}) سپس نیاز به ایجاد یک پیچیدگی کوچک درون فایل search_form.html برای بیان اینکه بجای یک مقدار Boolean یک لیست از error ها ارسال شده است. <html> <head> <title>Search</title> </head> <body> {% if errors %} <ul> {% for error in errors %} <li>{{ error }}</li> {% endfor %} </ul> {% endif %} <form action="/search/" method="get"> <input type="text" name="q"> <input type="submit" value="Search"> </form> </body> </html> ساخت یک فرم تماس در جنگو اگرچه در سرتاسر مثال فرم جستجوی کتاب بررسی کرده و به طور ظریف آن را اصلاح نمودیم، ولی اساسا هنوز این مثال ساده می باشد: زیرا تنها دارای یک فیلد 'q' می باشد. به دلیل سادگی بیش از حد مثال مذکور حتی از کتابخانه ی فرم جنگو برای آن استفاده ای نشد. ولی فرم های پیچیده تر برای رفتار پیچیده تر فراخوانی می شوند – و حالا، چیزی پیچده تر را توسعه خواهیم داد: یک سایت فرم تماس. این مثال یک فرم خواهد بود که به کاربران سایت اجازه اصلاح و وارد کردن اطلاعات را به همراه یک فیلد اختیاری آدرس پست الکترونیکی می دهد. بعد از آنکه فرم ارسال و داده تایید اعتبار شد، به طور خودکار یک پیام از طریق آدرس پست الکترونیک به کارمندان سایت ارسال خواهد شد. با template مورد نظر contact_form.html شروع می کنیم: <html> <head> <title>Contact us</title> </head> <body> <h1>Contact us</h1> {% if errors %} <ul> {% for error in errors %} <li>{{ error }}</li> {% endfor %} </ul> {% endif %} <form action="/contact/" method="post"> <p>Subject: <input type="text" name="subject"></p> <p>Your e-mail (optional): <input type="text" name="email"></p> <p>Message: <textarea name="message" rows="10" cols="50"></textarea></p> <input type="submit" value="Submit"> </form> </body> </html> سه فیلد تعریف شده است: موضوع، آدرس پست الکترونیک و پیام. دومین فیلد اختیاری می باشد، ولی دو فیلد دیگر الزاما باید پر شوند. توجه داشته باشید که به جای method="get" در اینجا از method="POST" استفاده شده است، زیرا ارسال فرم ممکن است دارای یک اثر زیان بار باشد – فرستادن یک پست الکترونیکی. همچنین، کد نمایش خطا از template قبلی search_form.html کپی شده است. در صورتیکه کار را با view بخش قبلی search() ادامه دهیم، یک نسخه ی خام از contact() ممکن است چیزی شبیه به کد زیر باشد: from django.core.mail import send_mail from django.http import HttpResponseRedirect from django.shortcuts import render_to_response def contact(request): errors = [] if request.method == 'POST': if not request.POST.get('subject', ''): errors.append('Enter a subject.') if not request.POST.get('message', ''): errors.append('Enter a message.') if request.POST.get('email') and '@' not in request.POST['email']: errors.append('Enter a valid e-mail address.') if not errors: send_mail( request.POST['subject'], request.POST['message'], request.POST.get('email', 'noreply@example.com'), ['siteowner@example.com'], ) return HttpResponseRedirect('/contact/thanks/') return render_to_response('contact_form.html', {'errors': errors}) (در صورتیکه مثال های کتاب را دنبال می کنید، ممکن است مردد باشید که آیا view فوق را درون فایل books/views.py قرار دهید یا خیر. کد فوق هیچ کاری با برنامه ی books انجام نمی دهد، بنابراین آیا می توان جای دیگری آن را قرار داد؟ این کاملا به تصمیم شما بستگی دارد؛ جنگو هیچ توجهی به این موضوع ندارد، البته تا زمانیکه شما درون URLconf به درستی به view مورد نظر اشاره کنید. ترجیح شخصی ما بر این است که یک دایرکتوری جدا به نام contact هم سطح با دایرکتوری books بسازید. این دایرکتوری یک __init__.py و views.py خواهد داشت.) چند نکته ی جدید که در مثال فوق اتفاق افتاده است: *** بررسی شده است که request.method مقدار 'POST' باشد. تنها در صورتیکه فرم ارسال شده باشد مقدار آن True خواهد بود؛ در صورتیکه شخصی تنها فرم تماس را مشاهده کند مقدار آن True نخواهد بود. (در مورد مشاهده ی فرم تماس request.method مقدار 'GET' خواهد داشت، زیرا در حالت عادی جستجو در وب، مرورگرها از GET استفاده می کنند نه از POST. این حالت روش زیبایی را برای مجزا کردن مورد نمایش فرم از مورد پردازش فرم ایجاد می کند.) *** بجای request.GET، برای دسترسی به داده های ارسال شده ی فرم از request.POST استفاده شده است. این حرکت بسیار ضروری می باشد، زیرا تگ <form> در contact_form.html از method="post" استفاده کرده است. در صورتیکه view از طریق POST قابل دسترسی باشد، بنابراین request.GET خالی خواهد بود. *** در مثال فوق، دو فیلد subject و message به صورت الزامی وجود دارد، بنابراین باید هر دوی آن ها تایید اعتبار شوند، توجه داشته باشید که به جای request.POST[] از request.POST.get() استفاده شده است، هنگام استفاده از request.POST[] در صورتیکه کلید مورد نظر وجود نداشته باشد موجب بروز خطای MultiValueDictKeyError خواهد شد، برای جلوگیری از بروز خطا در صورت نبود کلید از request.POST.get() استفاده شده است که آرگومان دوم مقدار پیشفرضی می باشد که در صورت نبود کلید این مقدار برگردانده می شود. *** اگرچه فیلد email یک فیلد الزامی نمی باشد، ولی در صورت وارد کردن مقداری برای این فیلد تایید اعتبار شده است. الگوریم تایید اعتبار در اینجا بسیار شکننده است، زیرا تنها بررسی شده است که رشته ی مورد نظر حاوی علامت (@) باشد. در دنیای واقعی، شما تایید اعتبارهایی قویتر نیاز دارید (جنگو همچنین تایید اعتباری را ارائه کرده است، که کمی بعد توضیح داده خواهد شد.) *** از تابع django.core.mail.send_mail برای فرستادن یک پست الکترونیکی استفاده شده است. این تابع دارای چهار آرگومان الزامی می باشد: موضوع پست الکترونیکی، بدنه ی پست الکترونیکی، آدرس فرستنده و یک لیستی از آدرس های گیرندگان. send_mail یک wrapper مناسب در اطراف کلاس EmailMessage می باشد، که ویژگی های پیشرفته ای مانند ضمیمه ها (attachments)، پست های الکترونیک چند قسمتی و کنترل کامل سرتاسر header های پست الکترونیک را ارائه می دهد. توجه داشته باشید که به منظور فرستاند پست الکترونیک با استفاده از send_mail()، سرور شما باید برای فرستاده mail، پیکربندی شده باشد و همچنین تنظیمات خاصی برای این منظور نیز لازم می باشد که برای اطلاعات بیشتر در این باره می توانید به آدرس Sending email |... مراجعه کنید. *** بعد از فرستادن پست الکترونیک، با برگرداند یک شیء HttpResponseRedirect به یک صفحه ی "success" تغییر مسیر داده شده است. ولی باید دلیل استفاده از redirect را به جای برای مثال render_to_response() را توضیح دهیم. دلیل: در صورتیکه یک کاربر دکمه ی "Refresh" را در آن صفحه ای که از طریق روش POST بارگذاری شده است فشار دهد، آن درخواست تکرار خواهد شد. این می تواند اغلب باعث بروز رفتاری ناخواسته شود، مانند اضافه شدن چندین بار یک رکورد تکراری در پایگاه داده – یا در مثال فوق، پست الکترونیکی دوباره فرستاده می شود. در صورتیکه کاربر بعد از POST به صفحه ی دیگری redirect شود، بنابراین هیچ شانسی برای تکرار شدن درخواست وجود ندارد. شما باید همواره یک redirect برای نتایج POST موفقیت آمیز ایجاد کنید. view فوق کار می کند، ولی توابع تایید اعتبار از توع ضعیفی می باشند. پردازش کردن یک فرم با ده ها فیلد را تصور کنید؛ آیا واقعا می خواهید برای همه ی آن ها عبارت های if بنویسید؟ مشکل دیگر نمایش دوباره ی فرم می باشد. در زمان ایجاد خطاهای اعتبار، بهترین تمرین نمایش دوباره ی فرم با داده های قبلی ارسال شده می باشد، به طوری که کاربر بتواند چیزی را که به طور اشتباه پر کرده است را مشاهده کند (و همچنین کاربر نیازی به دوباره پر کردن فیلدهایی که درست بوده اند پیدا نکند). می توان به صورت دستی داده های POST را به به سمت template پس فرستاد، ولی لازم است هر فیلد HTML را برای درج کردن مقدار مناسب در مکان مناسب ویرایش کرد: # views.py def contact(request): errors = [] if request.method == 'POST': if not request.POST.get('subject', ''): errors.append('Enter a subject.') if not request.POST.get('message', ''): errors.append('Enter a message.') if request.POST.get('email') and '@' not in request.POST['email']: errors.append('Enter a valid e-mail address.') if not errors: send_mail( request.POST['subject'], request.POST['message'], request.POST.get('email', 'noreply@example.com'), ['siteowner@example.com'], ) return HttpResponseRedirect('/contact/thanks/') return render_to_response('contact_form.html', { 'errors': errors, 'subject': request.POST.get('subject', ''), 'message': request.POST.get('message', ''), 'email': request.POST.get('email', ''), }) # contact_form.html <html> <head> <title>Contact us</title> </head> <body> <h1>Contact us</h1> {% if errors %} <ul> {% for error in errors %} <li>{{ error }}</li> {% endfor %} </ul> {% endif %} <form action="/contact/" method="post"> <p>Subject: <input type="text" name="subject" value="{{ subject }}"></p> <p>Your e-mail (optional): <input type="text" name="email" value="{{ email }}"></p> <p>Message: <textarea name="message" rows="10" cols="50">**{{ message }}**</textarea></p> <input type="submit" value="Submit"> </form> </body> </html> کد فوق بسیار ضعیف و غیر ضروری می باشد، و فرصت های زیادی را برای خطاهای فردی را ایجاد می کند. اولین کلاس Form در جنگو جنگو دارای یک کتابخانه ی فرم با نام django.forms می باشد، که بسیاری از مسائل بررسی شده در این فصل را کنترل می کند – از نمایش فرم تا تایید اعتبار. اجازه دهید برنامه ی فرم تماس را با استفاده از فرم فریم ورک جنگو دوباره بنویسیم. کتابخانه ی "newforms" جنگو ممکن است تاکنون چیزی درباره ی django.newforms شنیده باشید. هنگامی که درباره ی django.newforms صحبت می شود، صحبت درباره ی چیزی است که حالا django.forms نام دارد – که در این فصل به پرداخته شده است. دلیل تغییر نام این کتابخانه تاریخی می باشد. هنگامی که جنگو برای عموم منتشر شد، دارای سیستم فرم های پیچیده و گیج کننده به نام django.forms بود. این کتابخانه دوباره به صورت کامل بازنویسی شد، و نسخه ی جدید django.newforms نامیده شد به طوری که افراد هنوز می توانستند از نسخه ی قدیمی استفاده کنند. هنگامی که جنگو 1.0 منتشر شد، django.forms کنار گذاشته شد، و django.newforms به django.forms تغییر نام داد. روش اصلی برای استفاده از فریم ورک فرم ها تعریف یک کلاس Form برای هر <form> HTML می باشد که با آن سرکار دارید. در مثال ما، تنها یک <form> داریم، بنابراین یک کلاس Form هم خواهیم داشت. این کلاس می تواند در هرجایی که می خواهید قرار بگیرد – حتی به طور مستقیم درون فایل views.py – ولی مانند یک قرارداد کلاس های Form درون یک فایل جدا به نام forms.py قرار می گیرند. این فایل را در مسیر فایل views.py بسازید، و کد زیر را درون آن وارد کنید: from django import forms class ContactForm(forms.Form): subject = forms.CharField() email = forms.EmailField(required=False) message = forms.CharField() کد فوق همانند مدل های جنگو می باشد. هر فیلد در فرم با یک نوع از کلاس فیلد – CharField و EmailField نوع هایی هستند که در کد فوق استفاده شده اند – به صورت attribute های کلاس Form نشان داده می شود. هر فیلد به صورت پیشفرض الزامی (required) می باشد، بنابراین برای اختیاری کردن فیلد email، required=False تعیین شده است. اجازه دهید از طریق interactive interpreter پایتون کاری را که این کلاس انجام می دهد را با هم مشاهده کنیم، اولین کاری که می تواند انجام دهد نمایش خودش به صورت HTML می باشد: >>> from contact.forms import ContactForm >>> f = ContactForm() >>> print f <tr><th><label for="id_subject">Subject:</label></th><td><input type="text" name="subject" id="id_subject" /></td></tr> <tr><th><label for="id_email">Email:</label></th><td><input type="text" name="email" id="id_email" /></td></tr> <tr><th><label for="id_message">Message:</label></th><td><input type="text" name="message" id="id_message" /></td></tr> جنگو یک label برای هر فیلد اضافه کرده است. هدف ایجاد رفتار تا حد ممکن بهینه به طور پیشفرض می باشد. کد فوق خروجی پیشفرض در قالب بندی <table> HTML می باشد، ولی خروجی های داخلی دیگری نیز وجود دارند: >>> print f.as_ul() <li><label for="id_subject">Subject:</label> <input type="text" name="subject" id="id_subject" /></li> <li><label for="id_email">Email:</label> <input type="text" name="email" id="id_email" /></li> <li><label for="id_message">Message:</label> <input type="text" name="message" id="id_message" /></li> >>> print f.as_p() <p><label for="id_subject">Subject:</label> <input type="text" name="subject" id="id_subject" /></p> <p><label for="id_email">Email:</label> <input type="text" name="email" id="id_email" /></p> <p><label for="id_message">Message:</label> <input type="text" name="message" id="id_message" /> توجه داشته باشید که تگ های باز و بسته ی <table>، <ul> و <form> درون خروجی وجود ندارند، به طوری که می توان هر ردیف اضافه ای را در صورت نیاز اضافه کرد. این متدها تنها میانبرهای برای موارد رایج نمایش تمام فرم می باشند. همچنین می توان برای هر فیلد خاص نیز فرم را نمایش داد: >>> print f['subject'] <input type="text" name="subject" id="id_subject" /> >>> print f['message'] <input type="text" name="message" id="id_message" /> دومین کاری که شیء های Form می توانند انجام دهند تایید اعتبار داده می باشد. برای تایید اعتبار داده، یک شیء Form جدید ایجاد کرده و یک دیکشنری از داده هایی که نام فیلد را به داده ی مورد نظر مربوط می کند به آن ارسال کنید. >>> f = ContactForm({'subject': 'Hello', 'email': 'adrian@example.com', 'message': 'Nice site!'}) هنگامی که داده ها را با نمونه ی Form مربوط ساختید، شما یک "bound" فرم ساخته اید: >>> f.is_bound True متد is_valid() را روی هر bound Form برای یافتن اینکه داده معتبر است یا خیر فراخوانی کنید. ما برای هر فیلد یک مثدار معتبر ارسال کردیم، بنابراین Form به کلی معتبر می باشد: >>> f.is_valid() True در صورتیکه فیلد email را ارسال نکنیم، همچنان معتبر خواهد ماند، زیرا این فیلد را به صورت required=False تعیین کرده ایم: >>> f = ContactForm({'subject': 'Hello', 'message': 'Nice site!'}) >>> f.is_valid() True ولی، در صورتیکه subject یا message را در نظر نگیریم، فرم دیگر معتبر نخواهد بود: >>> f = ContactForm({'subject': 'Hello'}) >>> f.is_valid() False >>> f = ContactForm({'subject': 'Hello', 'message': ''}) >>> f.is_valid() False می توان اطلاعات بیشتری را از طریق پیام های خطا بدست آورد: >>> f = ContactForm({'subject': 'Hello', 'message': ''}) >>> f['message'].errors [u'This field is required.'] >>> f['subject'].errors [] >>> f['email'].errors [] هر نمونه ی bound Form دارای attribute های خطا می باشد که یک دیکشنری با نام فیلد های مرتبط شده با لیست های پیام خطا ارائه می دهد: >>> f = ContactForm({'subject': 'Hello', 'message': ''}) >>> f.errors {'message': [u'This field is required.']} در پایان، برای نمونه هایی Form ای که دارای داده های معتبر می باشند، یک attribute با نام cleaned_data در دسترس می باشد. این attribute یک دشکنری از داده های ارسال (submit) شده می باشد. فریم ورک فرم جنگو نه تنها داده را تایید اعتبار می کند، بلکه آن را به یک نوع مناسب پایتون تبدیل می کند. >>> f = ContactForm({'subject': 'Hello', 'email': 'adrian@example.com', 'message': 'Nice site!'}) >>> f.is_valid() True >>> f.cleaned_data {'message': u'Nice site!', 'email': u'adrian@example.com', 'subject': u'Hello'} فرم تماس ما تنها با رشته ها سر کار دارد که به شیء های یونیکد تبدیل شده اند – ولی در صورتیکه از یک IntegerField یا dateField استفاده کنیم، فریم ورک فرم از شیء های مناسب integer یا datetime.date برای فیلد داده شده استفاده خواهد کرد. استفاده کردن از شیء های فرم درون view در زیر نحوه ی استفاده از کلاس های فرم به جای روش قبلی را مشاهده خواهید کرد: # views.py from django.shortcuts import render_to_response from mysite.contact.forms import ContactForm def contact(request): if request.method == 'POST': form = ContactForm(request.POST) if form.is_valid(): cd = form.cleaned_data send_mail( cd['subject'], cd['message'], cd.get('email', 'noreply@example.com'), ['siteowner@example.com'], ) return HttpResponseRedirect('/contact/thanks/') else: form = ContactForm() return render_to_response('contact_form.html', {'form': form}) # contact_form.html <html> <head> <title>Contact us</title> </head> <body> <h1>Contact us</h1> {% if form.errors %} <p style="color: red;"> Please correct the error{{ form.errors|pluralize }} below. </p> {% endif %} <form action="" method="post"> <table> {{ form.as_table }} </table> <input type="submit" value="Submit"> </form> </body> </html> نگاه کنید که تا چه مقدار قادر به حذف کردن کدهای اضافه ی قبلی می باشیم! فریم ورک فرم جنگو نمایش HTML، تایید اعتبار، تبدیل داده ها و نمایش دوباره ی فرم با خطاها را کنترل می کند. سعی کنید به صورت محلی روش فوق را امتحان کنید، با فیلدها خالی فرم را ارسال کنید، با فیلد نا معتبر برای email فرم را ارسال کنید، و در پایان فرم را با داده ی معتبر ارسال کنید. (البته بسته پیکربندی mail-server، ممکن است هنگام فراخوانی send_mail() دریافت کنید، که بحث آن جدا می باشد.) تغییر نحوه ی ارائه ی فیلدها در جنگو ممکن است اولین چیزی که مورد توجه شما قرار گیرد این باشد که فیلد message به صورت <input type="text"> نمایش داده شده است، و باید یک <textarea> باشد. می توان این مشکل را به شکل زیر حل کرد: from django import forms class ContactForm(forms.Form): subject = forms.CharField() email = forms.EmailField(required=False) message = forms.CharField(widget=forms.Textarea) هر نوع فیلد دارای حالت پیشفرض خود می باشد، ولی می توان به سادگی این پیشفرض را تغییر داد، یا یک حالت مورد دلخواه را ایجاد نمود. Think of the Field classes as representing validation logic, while widgets represent presentation logic. تنظیم حداکثر طول یک از رایج ترین نیازهای تایید اعتبار بررسی اندازه ی قطعی یک فیلد می باشد. برای اندازه گیری خوب، باید کلاس ContactForm را محدود به subject ای با صد حرف کرد. برای انجام چنین کاری، تنها یک max_length برای CharField قرار می دهیم: from django import forms class ContactForm(forms.Form): subject = forms.CharField(max_length=100) email = forms.EmailField(required=False) message = forms.CharField(widget=forms.Textarea) همچنین یک آرگومان اختیاری min_length نیز در دسترس می باشد. تنظیم مقدار اولیه به منظور بهبود این فرم، اجازه دهید یک مقدار اولیه برای فیلد subject اضافه کنیم: "I love your site". برای انجام چنین کاری می توان از آرگومان initial هنگامی که یک نمونه Form را می سازیم استفاده کرد. def contact(request): if request.method == 'POST': form = ContactForm(request.POST) if form.is_valid(): cd = form.cleaned_data send_mail( cd['subject'], cd['message'], cd.get('email', 'noreply@example.com'), ['siteowner@example.com'], ) return HttpResponseRedirect('/contact/thanks/') else: form = ContactForm( initial={'subject': 'I love your site!'} ) return render_to_response('contact_form.html', {'form': form}) حالا، فیلد subject با مقدار از پیش پر شده ی مورد نظر نمایش داده خواهد شد. سفارشی کردن قوانین تایید اعتبار در جنگو تصور کنید یک فرم را برای پست الکترونیک راه اندازی کرده اید. ولی یک مشکلی وجود دارد: برخی از پیام های ارسال شده دارای تنها یک یا دو کلمه می باشند، که برای فهمیدن موضوع کافی نمی باشد. در این مورد تصمیم می گیرید یک روش تایید اعتبار جدید را برگزینید: لطفا چهار کلمه یا بیشتر. تعدادی روش برای سفارشی ساختن تایید اعتبار فرم جنگو وجود دارد. در صورتیکه قانون جدید چیزی باشد که از آن همواره استفاده می کنیم، می توان یک نوع فیلد سفارشی ساخت. می خواهیم یک تایید اعتبار اضافه در فیلد message ایجاد کنیم، بنابراین یک متد clean_message() به کلاس فرم خود اضافه می کنیم: from django import forms class ContactForm(forms.Form): subject = forms.CharField(max_length=100) email = forms.EmailField(required=False) message = forms.CharField(widget=forms.Textarea) def clean_message(self): message = self.cleaned_data['message'] num_words = len(message.split()) if num_words < 4: raise forms.ValidationError("Not enough words!") return message سیستم فرم جنگو به طور خودکار هر متدی را که با clean_ شروع و با نام یک فیلد تمام شود جستجو می کند. در صورتیکه همچین متدی وجود داشته باشد، در مدت تایید اعتبار فراخوانی خواهد شد. به طور خاص، متد clean_message() بعد از تایید اعتبار منطقی پیشفرض برای فیلد داده شده فراخوانی می شود (در این مورد، تایید اعتبار منطقی برای یک CharField الزامی، می باشد.) زیرا داده ی فیلد در اینصورت تا حدی پردازش شده خواهد بود، این داده ی پردازش شده را از self.cleaned_data بدست می آوریم. همچنین، در این صورت لازم نیست درباره ی بررسی کردن اینکه مقدار وجود دارد و خالی نمی باشد نگران باشیم؛ این کار با تایید کننده ی اعتبار پیشفرض انجام شده است. بسادگی از ترکیب len() و split() برای شمارش کلمات استفاده کرده ایم. در صورتیکه کاربر کلمات کمی وارد کند، خطای forms.ValidationError ایجاد خواهد شد. رشته ی اضافه شده به این خطا به صورت یک آیتم اضافه شده به لیست خطاها به کاربر نمایش داده خواهد شد. مهم است که به طور صریح یک مقدار تمیز شده (cleaned) برای فیلد در پایان متد برگردانده شده است. این کار به ما اجازه می دهد مقدار را درون متد تایید اعتبار سفارشی خودمان تغییر دهیم (یا به نوع های دیگر پایتون تبدیل کنیم). تعیین label ها در جنگو به طور پیشفرض، label ها در در جنگو به طور خودکار از طریق جا به جا کردن خط تیره با فاصله و همچنین تبدیل حرف اول به حرف بزرگ ساخته می شوند – بنابراین label برای فیلد email به این شکل خواهد بود: "Email". (این روش آشنا نیست؟ این الگوریتم همان الگوریتمی می باشد که مدل های جنگو از آن برای محاسبه ی مقدار پیشفرض verbose_name برای فیلدها از آن استفاده می کردند که در آموزش مدل جنگو توضیح داده شده است.) ولی، همانند مدل های جنگو، می توان label فیلد داده شده را سفارشی کرد. تنها کافیست مانند زیر از label استفاده شود: class ContactForm(forms.Form): subject = forms.CharField(max_length=100) email = forms.EmailField(required=False, label='Your e-mail address') message = forms.CharField(widget=forms.Textarea) سفارشی کردن طرح فرم در جنگو template ما یعنی contact_form.html از {{ form.as_table }} برای نمایش فرم استفاده کرده است، ولی می توان فرم را به روش های دیگری نیز برای کنترل ذره به ذره نمایش داد. سریع ترین روش برای سفارشی کردن نمایش فرم ها استفاده از CSS می باشد. تولید کننده ی خودکار لیست های خطا دقیقا از <ul class="errorlist"> استفاده می کنند به طوری که می توان با استفاده از CSS آن ها را علامت گذاری کرد: <style type="text/css"> ul.errorlist { margin: 0; padding: 0; } .errorlist li { background-color: red; color: white; display: block; font-size: 10px; margin: 0 0 3px; padding: 4px 5px; } </style> زمانی این روش مناسب می باشد که بخواهیم حالت پیشفرض ارائه شده را تغییر دهیم. {{ form.as_table }} و ... میانبرهای مفیدی برای توسعه ی برنامه می باشند، ولی هرچیزی درباره ی روش نمایش یک فرم می تواند غالبا درون خود template دوباره نویسی شده و تغییر کند، و شما احتمالا انجام اینکار را برای خودتان خواهید یافت. هر فیلدی (<input type="text">، <select>، <textarea> و ...) می تواند به صورت جداگانه با دسترسی داشتن به {{ form.fieldname }} در template ارائه شده باشد، و هر خطای مربوط به آن با یک فیلد به صورت {{ form.fieldname.errors }} قابل دسترسی می باشد. با در نظر گرفتن نکات فوق، می توان یک template سفارشی برای فرم تماس با کد زیر ایجاد نمود: <html> <head> <title>Contact us</title> </head> <body> <h1>Contact us</h1> {% if form.errors %} <p style="color: red;"> Please correct the error{{ form.errors|pluralize }} below. </p> {% endif %} <form action="" method="post"> <div class="field"> {{ form.subject.errors }} <label for="id_subject">Subject:</label> {{ form.subject }} </div> <div class="field"> {{ form.email.errors }} <label for="id_email">Your e-mail address:</label> {{ form.email }} </div> <div class="field"> {{ form.message.errors }} <label for="id_message">Message:</label> {{ form.message }} </div> <input type="submit" value="Submit"> </form> </body> </html> {{ form.message.errors }} در صورتیکه خطاها موجود باشند رشته ی خالی در صورتیکه فیلد معتبر باشد یک <ul class="errorlist"> را نمایش می دهد. همچنین می توان با form.message.errors به صورت یک Boolean رفتار کنید و یا حتی درون آن مثل یک لیست جستجو کنید. برای مثال: <div class="field{% if form.message.errors %} errors{% endif %}"> {% if form.message.errors %} <ul> {% for error in form.message.errors %} <li><strong>{{ error }}</strong></li> {% endfor %} </ul> {% endif %} <label for="id_message">Message:</label> {{ form.message }} </div> خسته نباشید دوستان عزیز . جلسه هفتم کتاب جنگو به پایان رسید . امیدوارم که موفق باشید . پایتونی ها ترجمه از سایت www.djangobook.com
  6. این تاپیک پشتیبانی برای آموزش است آموزش فرم ها در فریم ورک جنگو ( جلسه هفتم ) 15/04/96 15:51 15/04/96 15:51 لطفا اگرهر سوال یا بازخوردی دارید اینجا ارسال کنید.
  7. به نام خدا با جلسه دهم از سری آموزش برنامه نویسی صفر تا صد زبان پایتون در خدمت شما عزیزان هستیم . همراه پایتونی ها باشید . در این جلسه سعی میکنیم بسیار روان و ساده مبحث عملگرها رو برای شما دوستان در زبان پایتون آموزش بدیم . عملگرها ( Operators ) در زبان پایتون : عملگر ها در تمام زندگی ما انسان ها جای دارند . در همه جا . حتی در زمان کودکی در مدرسه های تمام دنیا اولین چیزهایی که به دانش آموزان آموزش میدن استفاده از عملگرهاست . خب خیلی واضح هست که عملگرها در زبان های برنامه نویسی هم وجود دارند و بخش مهمی از اون زبان برنامه نویسی رو تشکیل میدن . عملگرها نمادهایی هستند که اعمال خاصی رو انجام میدن . مثلا علامت " + " یعنی اینکه 2 چیز رو باهم جمع میکنه . مثلا اگر ما X و Y داشته باشیم عبارت X + Y یعنی اینکه باید این 2 مقدار با هم جمع شوند . پس تا اینجا معنی عملگر رو متوجه شدید . نکته : به X و Y عملوندهای عملگر + می گویند . دسته بندی عملگرها در زبان برنامه نویسی پایتون : عملگرها در زبان برنامه نویسی پایتون به 5 دسته تقسیم می شوند . در زیر 5 مورد رو به تفصیل توضیح میدم براتون : 1- عملگرهای محاسباتی ( arithmatic ) 2- عملگرهای رابطه ای یا مقایسه ای ( comparison ) 3- علمگرهای منطقی ( boolean ) 4- عملگرهای ترکیبی 5- عملگرهای بیتی عملگرهای محاسباتی در پایتون : عملگرهای محاسباتی در پایتون اعمال محاسباتی را روی عملوندهای خود انجام میدهند . عملگر جمع : این عملگر دو عملوند رو با هم جمع میکنه X + Y مثال : 12 = 6 + 6 عملگر تقسیم ( اعشاری ) : این عملگر دو عملوند رو از هم تقسیم میکنه . این عملگر تقسیم رو اعشاری انجام میده . یعنی حتی اگر 2 تا عدد صحیح باشید جواب این تقسیم اعشاری خواهد بود . X / Y مثال : 1.5 = 4 / 6 مثال : 3.0 = 2 / 6 عملگر تقسیم ( صحیح ) : این عملگر دو عملوند رو از هم تقسیم میکنه . این عملگر تقسیم رو صحیح انجام میده . یعنی حتی اگر 2 تا عدد باقی مونده داشته باشند اون هارو نمایش نمیده و اعشاری نمیشه . X // Y مثال : 1 = 4 // 6 مثال : 1.0 = 4.0 // 6.0 عملگر ضرب : این عملگر دو عملوند رو در هم ضرب میکنه X * Y مثال : 12 = 3 * 4 عملگر باقیمانده : این عملگر باقیمانده تقسیم دو عملوند را نشان می دهد . X % Y مثال : 2 = 4 % 6 مثال : 2.3 = 4.3 % 6.6 عملگرهای رابطه ای یا مقایسه ای ( comparison ) : در زبان های محاوره ای و حتی زبان های برنامه نویسی چند تا عملگر داریم برای مقایسه کردن 2 یا چند مقدار . این عملگرها هم درکشون به راحتی عملگرهای محاسباتی در زبان برنامه نویسی پایتون هستند . اعمالی مثل مقایسه " تساوی دو مقدار " یا " کوچکتر بودن " و یا " بزرگتر بودن " و یا " مقایسه با صفر " و ... رو انجام می دهند . کوچکتر از : X < Y بزرگتر از : X > Y کوچکتر یا مساوی : X <= Y بزرگتر یا مساوی : X >= Y نا مساوی : X != Y مساوی بودن ( آیا X با Y مساوی است ؟ ) : X == Y برای امتحان چند دستور رو در محیط IDLE پایتون تایپ میکنیم تا نتیجه رو مستقیم ببینیم : >>> 10 < 5 False >>> 10 != 5 True >>> 10 > 5 True >>> 5==5 True امیدوارم که با این مثال ها نحوه عملگرها رو در پایتون متوجه شده باشید . علمگرهای منطقی ( boolean ) : عملگرهای منطقی بر روی عبارات منطقی عمل میکنند . عبارات منطقی 2 مقدار دارن . یا درست ( False ) یا نادرست ( True ) هستند . عملگر NOT : این عملگر بر روی یک عملوند عمل میکند . اگر اون عملوند درست باشد آن را نادرست میکند و اگر آن عملوند نادرست باشد آن را درست میکند . عملگر AND : این عملگر بر روی 2 عملوند اثر میگذارد . نتیجه عملگر and زمانی True است که هر دو طرف ( هر دو عملوند ) True باشند . عملگر OR : این عملگر بر روی 2 عملوند اثر میگذارد و زمانی نتیجه آن True خواهد بود که حداقل 1 عملوند True باشد . عملگرهای ترکیبی : از ترکیب عملگرهای محاسباتی و عملگر انتساب ( = ) مجموعه ای دیگر از عملگرها ایجاد می شوند . این عملگرها عمل محاسباتی و انتساب را انجام میدن . جمع و انتساب : X += Y عملگر بالا میاد مقدار X رو با مقدار Y جمع میکنه و دوباره میریزه تو X . یعنی 2 کار را در یک خط انجام دادیم . هم جمع و هم انتساب . دستور بالا معادل و کوتاه شده دستور X = X + Y است . ضرب و انتساب : X *= Y عملگر بالا میاد مقدار X رو در مقدار Y ضرب میکنه و دوباره میریزه تو X . یعنی 2 کار را در یک خط انجام دادیم . هم ضرب و هم انتساب . دستور بالا معادل و کوتاه شده دستور X = X * Y است . عملگرهای بیتی : این نوع عملگرها بر روی اطلاعات بیتی عمل می کنند . فعلا زیاد لازم نیست در این مورد تحقیق کنید . اگر هم دوست داشتید میتونید راجبش جستجو انجام بدید . خب امیدوارم تا اینجا قشنگ با عملگرها آشنا شده باشید . در جلسه بعد از سری آموزش برنامه نویسی صفر تا صد پایتون مقدماتی با مبحث تقدم عملگرها در خدمت شما عزیزان هستیم . سعی کنید که این مباحث رو به خوبی یاد بگیرید که زیاد سخت نیست . فقط یکبار خوندنش فکر کنم کفایت کنه . ولی مبحثی هست که تا زمانی که برنامه نویسی میکنید درگیر این بخش خواهید بود . خب به پایان جلسه دهم از آموزش برنامه نویسی پایتون مقدماتی به زبان فارسی رسیدیم . امیدوارم که لذت برده باشید . موفق و پیروز باشید . امیدوارم که از جلسه دهم آموزش استفاده کامل رو برده باشید . تمامی حقوق برای انجمن پایتونی ها محفوظ می باشد . پایتونی ها
  8. این تاپیک پشتیبانی برای آموزش است عملگرها ( Operators ) در زبان پایتون ( جلسه دهم ) 19/03/96 03:03 19/03/96 03:06 لطفا اگرهر سوال یا بازخوردی دارید اینجا ارسال کنید.
  9. به نام خدا در خدمت شما عزیزان هستیم با جلسه نهم از آموزش صفر تا صد پایتون مقدماتی . امیدوارم تا اینجای آموزش ها لذت برده باشید . در این قسمت می پردازیم به معرفی متغییر ها در پایتون و ثابت ها . معرفی متغیر ها ( Variables ) و ثابت ها در زبان پایتون متغیر ها ( Variables ) : در جلسه های قبل درباره انواع داده صحبت کردیم . حال وقتی تعدادی انواع داده در زبان پایتون وجود داره باید متغیر هایی داشته باشیم که مقادیری از آن انواع داده را ذخیره کند . مثلا وقتی نوع داده عددی داریم ( مثلا ۳۴ ) حال باید یک ظرفی در نظر بگیریم که این مقدار را در خودش ذخیره کنه و هرجا خواستیم بتونیم ازش استفاده کنیم . پایتون در واقع فاقد چنین متغیر هایی است بلکه دارای مرجع شی است . تفاوت زیادی بین متغییر و مرجع شی وجود نداره . وقتی داریم از اشیای غیر قابل تغییر مثل int و str استفاده می کنیم تفاوت فاحشی بین متغیر و مرجع شی وجود نداره . اما برای تعریف اشیای قابل تغییر بین آن ها تفاوت است ولی در عمل چندان مهم نیست برای ما . ما در آموزش های خودمون از واژه های متغیر به جای مرجع شی استفاده می کنیم . اسامی ای که برای مرجع اشیا(متغیرها)به کار می رود شناسه نیز نامیده می شود. ما باید برای متغیر های خودمون که قرار هست مقدار داده ای در خود ذخیره کنه یک اسمی در نظر بگیریم . این تعریف اسم برای متغییر چندتا قانون کلی داره که بهتره یک بار برای همیشه یاد بگیریم و خودمون رو راحت کنیم : 1 - نباید با واژه های کلیدی در پایتون یکسان باشند ( در جلسه قبل کلمات کلیدی را در یک جدول معرفی کردیم ) . 2 - باید با حرف یا خط زیر (ـــ) شروع شود و پس از آن چند جرف و رقم بیاد و فاقد فضای خالی باشد . 3 - محدودیتی درطول نام شناسه وجود ندارد . یعنی برای شناسه نامی با هر طول می توانید انتخاب کنید. 4 - شناسه ها نسبت به حروف کوچک وبزرگ حساس هستند. در زیر چند نمونه از نامگذاری متغییر به صورت معتبر و غیر معتبر براتون مثال میزنیم : اسامی متغییر های نا معتبر : 1myname my.name .myname my name اسامی متغییر های معتبر : count test2 t_1 _myname اعلان متغییر ها ( Variable Declaration ) : یکی از مزیت های زبان برنامه نویسی پایتون نسبت به زبان های دیگه این است که لازم نیست متغییر رو قبل از استفاده اعلان کنید . شاید تعجب کنید !! ولی واقعا همینطور است . فقط کافیه به متغیر مقدار بدید و ازش استفاده کنید . نکته قابل توجه دیگه این است که لازم نیست تعریف کنید که متغیر من از چه نوعی است !! فقط کافیست به متغیر خود مقدار دهید تا پایتون بقیه کارها رو انجام بده . برای نسبت دادن یک مقدار به متغیر فقط کافیست از علامت = استفاده کنید . بدون هیچ پسوند یا پیشوندی !!! مثال : تمامی متغیر های زیر حاوی مقداری از انواع نوع داده هستند . بدون اینکه از قبل اعلان شوند و یا نوع داده براشون تعریف بشه : message = " Hello My Brother " number = 12345344 flag = True myAge = 12.365 توجه کنید که برای نوع داده استرینگ فقط به دابل کوتیشن احتیاج داریم . متغیر اول یه مقدار رشته ای را در خود ذخیره کرده است متغیر دوم یه مقدار int یا عددی را در خود ذخیره کرده است . متغیر سوم یک مقدار بولین و با مقدار True ( درست ) را در خود ذخیره کرده است . متغیر چهارم یک مقدار اعشاری را در خود ذخیره کرده است . به همین راحتی و خوش مزگی !! تعیین نوع داده در زبان پایتون به صورت پویا انجام می شود . خواهشا جمله بالا رو چندین بار بخونید تا قشنگ متوجه بشید . این جمله یعنی چی ؟؟ یعنی اینکه شما در سراسر برنامه می توانید مدام بدون هیچ گونه مشکلی مقدار یک متغیر رو عوض کنید ! به کد زیر دقت کنید : MyValue = " Book " ... ... ... MyValue = 1200 زمانی که متغیر فوق مقدار بوک براش در نظر گرفته شد با همون مقدار در برنامه حضور خواهد داشت و پیش میره . ما میتونیم بدون هیچ گونه هماهنگی قبلی ! مقدارش رو یهو عوض کنیم و از این به بعد این متغیر مقدارش برابر ۱۲۰۰ هست و در محاسبات با این مقدار حضور خواهد داشت . این نکته رو در ذهنتون داشته باشید که با تمام این تفاسیر هر متغیر در هر لحظه فقط یک مقدار دارد . عملگر = در پایتون مانند زبان های دیگر عمل نمی کند . این عملگر فقط یک متغیر را به یک شی موجود مقید می کند . جمله بالا یعنی چی ؟؟ لطفا این بخش رو با دقت مطالعه کنید . یک مثال میزنم تا کاملا متوجه بشید . X = 1200 ... ... X = 3000 در ابتدا مقدار X برابر عدد ۱۲۰۰ است ولی یک یا چند خط جلوتر دیگه X به مقدار ۱۲۰۰ اشاره نمی کنه . بلکه داره به مقدار ۳۰۰۰ اشاره میکنه . خب تا اینجا که مشکلی ندارید !! حالا به کد زیر دقت کنید : X = 1200 Y = X X = 3000 به نظر شما الان مقدار x و y چقدر است ؟ بله درست حدس زدید . مقدار X‌ در حال حاضر برابر ۳۰۰۰ است و مقدار Y برابر ۱۲۰۰۰ است . چرا ؟ چون Y داره به X ای اشاره میکنه که مقدارش برابر ۱۲۰۰ هست . شاید یکم براتون گنگ باشه ولی یکم کار کنید قشنگ متوجه می شید . نکته : اگر میخواید یک متغیری ایجاد کنید که فعلا مقداری نداره از کلمه None استفاده کنید : MyVariable = None ثابت ها ( Constants ) و نحوه اعلان آنها درد برنامه : بر خلاف متغیر ها که مقدارشون مدام میتونه در برنامه تغییر کنه ُ ثوابت شناسه هایی هستند که در برنامه وجود دارند ولی غیر قابل تغییر هستند . ثابت ها در زبان پایتون با حروف بزرگ مشخص می شوند . مثال : LABLE = " computer " NUM = 1000 این ثابت ها در تمام برنامه دیگه نمیتونن مقدار جدیدی بگیرند . استفاده از ثابت ها در برنامه باعث افزایش خوانایی برنامه می شه . در جلسات بعدی به طور کامل متوجه خواهید شد که این ثوابت چه کاربردی دارند . خب به پایان جلسه نهم از آموزش برنامه نویسی پایتون مقدماتی به زبان فارسی رسیدیم . امیدوارم که لذت برده باشید . موفق و پیروز باشید . امیدوارم که از جلسه نهم آموزش استفاده کامل رو برده باشید . تمامی حقوق برای انجمن پایتونی ها محفوظ می باشد . پایتونی ها
  10. این تاپیک پشتیبانی برای آموزش است معرفی متغیر ها ( Variables ) و ثابت ها در زبان پایتون ( جلسه نهم ) 06/03/96 01:09 06/03/96 01:09 لطفا اگرهر سوال یا بازخوردی دارید اینجا ارسال کنید.
  11. اسکریپت و تکه کدهای پایه در پایتون ( Python-Snippets ) - قسمت اول تست کردن None نبودن یک متغیر : if value is not None: pass این کد تست میکنه که متغییر value مقدارش None هست یا نه . برای توضیح بیشتر درباره متغییرها به بخش آموزش مقدماتی پایتون قسمت نهم مراجعه فرمایید . عملگر شرطی سه تایی : در این روش به راحتی می تونید یک شرط ۳ بخشی بنویسید . اینجاست که متوجه کوتاه و مفید بودن زبان برنامه نویسی پایتون خواهید شد . >>> 'true' if True else 'false' 'true' >>> 'true' if False else 'false' 'false' چک کردن موجود بودن متغییر مورد نظر : برای چک کردن موجود بودن متغییر لوکال از کد زیر در زبان پایتون استفاده کنید : if 'myVar' in locals(): برای چک کردن موجود بودن متغییر گلوبال ( Global ) از کد زیر در زبان پایتون استفاده کنید : if 'myVar' in globals(): برای چک کردن صفت ( attribute ) یک آبجکت ( object ) از کد زیر استفاده کنید : if hasattr(obj, 'attr_name'): برای اینکه متوجه بشیم آبجکت obj دارای اتریبیوت attr_name هست یا نه .
  12. این تاپیک پشتیبانی برای آموزش است اسکریپت و تکه کدهای پایه در پایتون ( Python-Snippets ) - قسمت اول 01/03/96 01:02 01/03/96 01:02 لطفا اگرهر سوال یا بازخوردی دارید اینجا ارسال کنید. , این تاپیک پشتیبانی برای آموزش است اسکریپت و تکه کدهای پایه در پایتون ( Python-Snippets ) - قسمت اول 01/03/96 01:02 01/03/96 01:02 لطفا اگرهر سوال یا بازخوردی دارید اینجا ارسال کنید.
  13. به نام خدا با عرض سلام خدمت دوستانم عزیزم امیدوارم تا اینجای آموزش براتون مفید واقع شده باشه . در قسمت هشتم از سری آموزش برنامه نویسی پایتون مقدماتی میخوایم انواع داده در زبان پایتون و نحوه استفاده از آنها رو برای شما عزیزان آموزش بدیم . با ما همراه باشید . معرفی انواع داده ها ( Data Type ) در زبان برنامه نویسی پایتون یکی از کارهای اساسی که هر زبان برنامه نویسی باید انجام بده دریافت اطلاعات و دیتا و ایجاد یکسری تغییرات بر روی این اطلاعات و در نهایت نمایش تغییرات دیتا در خروجی . در پایتون چند نوع اولیه وجود دارند که در این بخش به انواع عددی و بولی و رشته ای می پردازیم . 8-1 : نوع داده عددی انواع عددی شامل ۲ مورد زیر است : --- نوع صحیح ( int ) : اعداد صحیح مثبت و منفی ( اعدادی که نقطه اعشار ندارند ) می باشند . در پایتون اندازه عددهای صحیح فقط با حافظه ماشین محدود میشن و ارتباطی با تعداد ثابتی از بایت ها مشخص نمیشن . مثال = اعداد زیر همه صحیح هستند : - 4588 54565966694 - 5656551 بنابراین شما حتی می توانید عدد صحیحی ایجاد کنید که ۲۰۰ رقم داشته باشد . هیچ مشکلی به وجود نمیاد . فقط شاید یکم کندتر اجرا شوند . اعداد صحیح می توانند در مبنای ۱۰ ( دسیمال ) و مبنای ۲ ( باینری ) و مبنای ۸ ( هشت ) و مبنای ۱۶ ( شانزده ) باشند . اعداد در مبنای ۱۰ به صورت طبیعی نوشته می شوند : 58485484 اعداد در مبنای ۲ با پیشوند 0b نوشته می شوند : 0b0101001 اعداد در مبنای ۸ با پیشوند 0o نوشته می شوند : 0o2367652 اعداد در مبنای ۱۶ با پیشوند 0x نوشته می شوند : 0x2DEFFF ---- نوع ممیز شناور ( floating point ) : زبان برنامه نویسی پایتون ۳ نوع مقدار ممیز شناور را فراهم میکنه . Float و complex و decimal . float : نوع float اعداد ممیز شناور رو با دقت مضاعف نگه میداره که بازه اون مربوط میشه به کامپایلر C که پایتون از اون ساخته شده است . این نوع داده تقریبا دقت پایینی داره . با استفاده از ممیز میتوانید اعداد به صورت توان دار هم بنویسید . 57.00 - 23.200 - 8.8e-4 برای نگه داری اعداد float از تعداد ثابتی بیت در کامپیوتر استفاده می شود . بخاطر همین تعداد اعدادی که میتواند نگهداری شود محدود است . داده های نوع عددی رو میتوان با هم دیگه ترکیب کرد . حاصل ترکیب int و float عددی از نوع float است . مثال : 8.0 = 3.0 + 5 Complex : اعداد مختلط نوعی از داده هستند که شاید تا الان اسم آن را نشنیده باشید . این نوع اعداد معمولا در دروس دانشگاهی استفاده می شوند . نوع داده مختلط نوع غیر قابل تغییری است که یک جفت float را نگهداری می کند که یک بخش آن نشان دهنده قسمت حقیقی و یک بخش آن نشان دهنده قسمت موهومی عدد مختلط است . مثلا عدد مختلط ( 5.6j + 4 ) به صورت زیر نوشته می شود در زبان پایتون : >>> a = 4.0 + 5.6j >>> a.real 4.0 >>> a.imag 5.0 8.2 : نوع داده رشته ای رشته ها با نوع داده str مشخص می شوند که غیر قابل تغییر است و دنباله از کاراکتر های یونیکد رو در خود نگهداری میکنند . معمولا از این نوع داده برای نگه داری اشیا ( اسم ها و ... ) استفاده می شود . رشته ها میتوانند در بین تک کوتیشن ( ' ) و یا دابل کوتیشن ( " ) قرار بگیرند . ' Mostafa ' "My first program " ' Hello World ' 8.3 : نوع داده بولین گاهی اوقات لازم است در زمان اجرای کدهای برنامه، مفسر پایتون درست یا نادرست بودن چیزی را ارزیابی کند. مثلاً فرض کنید که در زمان کدنویسی یک بازی کامپیوتری بگوییم که در صورت برخورد موشک به سفینه، یک انفجار رخ دهد. برای اجرای این دستور در زمان بازی، مفسر دائماً این شرط را بررسی می کند که آیا موشک با سفینه برخورد کرده است یا نه. در واقع باید داده ای در اختیار کامپیوتر قرار بگیرد که درست یا نادرست بودن این شرط را نشان دهد. بدین منظور در زبان برنامه نویسی پایتون از نوع داده هایی که از کلاس bool ساخته می شوند استفاده می کنیم که در حقیقت زیر مجموعه ای از نوع int است، چرا که این نوع داده ها تنها می توانند دو مقدار 0 یا 1 را داشته باشند. مقدار 0 نشان دهنده ی حالت False یا نادرست و مقدار 1 نشان دهنده ی حالت True یا درستاست. تا وقتی که داده ای با مقدار Falsee در اختیار مفسر قرار بگیرد انفجار صورت نمی گیرد، اما به محض آن که مفسر داده ای را دریافت کند که در ارزیابی مقدار آن را True تشخیص دهد، سفینه منفجر می شود! معرفی واژه های کلیدی در زبان برنامه نویسی پایتون واژه های کلیدی واژه هایی هستند که برای زبان برنامه نویسی پایتون معنای خاصی دارند و کار خاصی را انجام می دهند . ما حق نداریم از این کلمات بجز مواردی که خود پایتون اعلام کرده استفاده کنیم . مثلا ما نمیتوانیم از هیج کدوم برای نام گذاری متغیر ها استفاده کنیم . تمام واژه های کلیدی در جدول زیر آورده شده اند : نکته : رعایت حروف کوچک و بزرگ مهم است . False elif lambda None else nonlocal True except not and finally or as for pass assert from raise break global return class if try continue import while def in whith del is yield خب امیدواریم از این بخش آموزش لذت برده باشید . با ما باشید با سری کامل آموزش پایتون مقدماتی امیدوارم که از جلسه هشتم آموزش استفاده کامل رو برده باشید . تمامی حقوق برای انجمن پایتونی ها محفوظ می باشد . پایتونی ها
  14. این تاپیک پشتیبانی برای آموزش است معرفی انواع داده ها ( Data Type ) در پایتون ( جلسه هشتم ) 31/02/96 17:17 31/02/96 17:18 لطفا اگرهر سوال یا بازخوردی دارید اینجا ارسال کنید.
  15. به نام خدا . با عرض سلام و خسته نباشید خدمت شما سروران گرامی . با قسمت هفتم از سری آموزش برنامه نویسی پایتون مقدماتی در خدمت شما هستیم . همانطور که در آموزش های قبلی نحوه اجرای محیط کد نویسی پایتون رو به شما آموزش دادیم یادآور شدیم که ما برای شروع کد نویسی در محیط IDLE کار خواهیم کرد . ابتدا به توضیح کوتاهی درباره IDLE‌ می پردازیم . آشنایی با میحط توسعه و کدنویسی آی دی ال ای ( IDLE ) در تمام زبان های برنامه نویسی ما یک محیط کد نویسی یکپارچه به نام IDE داریم که به ما کمک میکنه کدهای مربوط به آن زبان برنامه نویسی را در آن نوشته و اجرا کنیم . وظیفه این IDE این است که کدهای ما را اجرا کنه و اگر خطایی داره خطا یابی کنه و اگر مشکلی نداشت خروجی برنامه ما رو چاپ کنه . البته یکسری دیگه وظایف هم به عهده داره . دوستان ما در تیم توسعه زبان برنامه نویسی پایتون برامون یک محیط یکپارچه کدنویسی به نام IDLE ایجاد کردن و اونو در بسته نصبی پایتون گنجوندن . یعنی وقتی شما نرم افزار پایتون رو نصب میکنی همزمان با اون این IDLE هم نصب میشه . این میحط یکپارچه کدنویسی ( واسط گرافیکی پایتون ) بسیار قدرتمند بوده و تمام نیاز های شما رو برطرف می کنه . خب نوبت به اجرای این محیط یکپارچه کدنویسی رسیده . کاربران ویندوز به استارت رجوع کرده و پک نصب شده پایتون رو باز کنن به راحتی گزینه IDLE‌ رو میبینند . روش دابل کلیک کنید و اجراش کنید . تمام کاربران مکینتاش در Launch Pad به دنبال IDLE بگردند و اجراش کنند . کاربران لینوکس هم در داشبورد به دنبال IDLE بگردند و اجراش کنند . اگر در لینوکس IDLE شما نصب نشده است از دستور sudo apt-get install idle3 استفاده کنید . بعد از اجرا با پنجره ای شبیه زیر مواجه میشید : ما ۲ تا محیط IDLE داریم : ۱ - یکی همین عکس بالایی هست که وقتی IDLE ‌رو اجرا می کنید باز میشه . این صفحه در اصل برای اسکریپت های کوتاه ازش استفاده میشه . اگر دقت کنید بالای پنجره عبارت Shell نوشته شده . ما به شما استفاده از این پنجره رو فقط برای نوشتن تکه کدهای کوتاه استفاده میکنیم . نکته : کدهای نوشته شده در این پنجره ذخیره نخواهند شد و با بسته شدن پنجره تمام کدهای شما پاک خواهد شد . نکته : برای اجرای کد در روش اول ( پنجره Shell ) فقط با زدن اینتر کدها اجرا خواهند شد . ۲ - اما پنجره دوم . همون پنجره اول IDLE که باز شد از منو گزینه File رو انتخاب کنید و بعد گزینه New Window رو بزنید . پنجره ای به شکل زیر برای شما باز خواهد شد . حالا با خیال راحت در این پنجره شروع به کد نویسی کنید . نکته : برای اجرای کدهای نوشته شده در حالت دوم حتما باید قبل آن از اجرا کدهای خود را در از طریق گزینه Save ذخیره کنید . نکته : برای اجرای کدهای خود بعد از ذخیره سازی از گزینه Run در منو استفاده کنید . هرگاه کارتون با فایلی که ایجاد کردید تموم شد پنجره IDLE را با خیال راحت ببندید ( البته قبلش کدهای خود را ذخیره کنید ) و دفعه بعد برای ادیت آن کافیست که روی فایلتون کلیک راست کنید و گزینه Edit with IDLE را بزنید تا کدهای شما در پنجره IDLE باز شده و به ویراش آن بپردازید . تقریبا نکته ای نمونده از این بخش . خلاصه : پس متوجه شدید که وقتی IDLE رو اجرا کنید یه پنجره باز میشه که بهتره کدهای کوتاه خودتون رو اینجا تست کنید . با زدن اینتر کدها اجرا میشه . در ضمن نمیتونید کدهاتون رو تو این پنجره ذخیره کنید . ولی اگه از منوی این پنجره از گزینه File گزینه New Window رو بزنید یه پنجره دیگه باز میشه که بهتره از این به بعد با این پنجره کار کنید . قبل از اجرای کد باید کدهاتون رو ذخیره کنید و از گزینه Run در منوی پنجره برنامه خودتون رو اجرا می کنید . برای تغیرات یکسری از تنظیمات IDLE از منو پنجره وارد بخش Option شوید . بخاطر راحتی کار دیگه آموزشی براش در نظر نگرفتم . امیدوارم که کاملا متوجه شده باشید . خسته نباشید . جلسه هفتم هم به پایان رسید . امیدوارم که از جلسه هفتم آموزش استفاده کامل رو برده باشید . تمامی حقوق برای انجمن پایتونی ها محفوظ می باشد . پایتونی ها
  16. به نام خدا با سلام خدمت همه عزیزان . با جلسه ششم آموزش مقدماتی برنامه نویسی به زبان پایتون همراه شما عزیزان هستیم . همانطور که در جلسه های قبلی با ما همراه بودید توانستیم که پایتون رو بر روی سیستم عامل های ویندوز و مکینتاش و لینوکس نصب کنیم . حالا نوبت به اجرای مفسر پایتون و شروع کد نویسی رسیده است . آموزش شروع کار با حالت اسکریپتی مفسر زبان پایتون وقتی شما شروع می کنید به کد نویسی به زبان پایتون مهم نیست که کجا این کد نویسی انجام می شود ( در ویراشگر متن یا مفسر پایتون و ... ) . در نهایت شما باید یک فایل داشته باشید با پسوند .py و سیستم عامل شما هر زمان که با این فایل مواجه شود متوجه می شود که با فایل پایتون ( معمولا به این فایل ها اسکریپت پایتون گفته می شود ) روبرو شده است . شما برای نوشتن برنامه خود و اجرای آن از ۲ طریق می توانید اقدام کنید : ۱ - یک فایل متنی ایجاد کنید ( خالی ) و اسم آن را تست بگذارید ولی فقط باید حتما پسوند این فایل .py باشد . وقتی شما این فایل رو ایجاد کردید و بعدا داخل آن شروع کردید به کد نویسی و آن را ذخیره کردید کار تمام است . حالا هرگاه لازم بود فقط کافیست روی اسکریپت ( ماژول ) خود دابل کلیک کنید . چون پسوند فایل مربوط به زبان پایتون هست خود سیستم عامل میدونه که باید چجوری فایل رو اجرا کنه ( به سراغ برنامه های py.exe و pyw.exe که لانچرهای ویندوز هستند می رود و با استفاده از آن ها ماژول برنامه را اجرا می کند ) . ۲ - روش دوم از طریق کد نویسی در پنجره کامند ( CMD ) در ویندوز می باشد . اگر از لینوکس و مکینتاش استفاده میکنید باید از طریق پنجره ترمینال این کار را انجام دهید . بعد از باز شدن پنجره ترمینال باید کلمه python را نوشته و در ادامه آدرس فایل مورد نظر را بنویسیم . مثلا شما فایل را با اسم test.py در درایو C و پوشه python-project ایجاد کرده اید . به صورت زیر فرمان مورد نظر را اجرا کنید : python C:\python-project\test.py بعد از اجرا دستور فوق می بینید که محتوای فایلی که نوشته اید اجرا می شود . برای شروع داخل فایل خود کد زیر را بنویسید . این کد یه دستور چاپ ساده است که با یک نگاه متوجه آن می شوید . اگر باز هم متوجه نشدید نگران نباشید چون میریم جلوتر کامل توضیح می دهیم . print("Hello Pythonyha.ir! It is my script .") خب . حالا این فایل را به هرکدوم از ۲ روش بالا اجرا کنید ( چه روی اون دابل کلیک کنید و چه از طریق CMD آدرس اون رو وارد و اجرا کنید ) خواهید دید که جمله فوق پرینت گرفته شده و نمایش داده خواهد شد . این از اجرای برنامه های پایتون با حالت اسکریپتی . آموزش شروع کار با حالت تعاملی مفسر زبان پایتون خب . این روش بهتر و معقولانه تر هست . برای راحتی ما برنامه نویسان زبان پایتون یک محیط کد نویسی آماده کردند که زیاد اذیت نشیم . که بهش محیط تعاملی یا کامند لاین تعاملی ( Interactive Prompt ) می گن . این محیط با محیط کامند لاین ویندوز فرقی نداره . برای اجرای کامند لاین تعاملی اگر سیستم عاملتون ویندوز هست به محل نصب پایتون خود برید ( که معمولا در درایو C و در پوشه ای به نام python هست ) برید . در آنجا فایلی پیدا میکنید با اسم python یا python.exe . این فایل را اجرا کنید . محیط شبیه محیط کامند لاین باز میشود که به راحتی می توانید داخل آن کد پرینتی که بهتون گفته بودم رو اجرا کنید و نتیجه آن را ببینید . البته مستقیما از طریق خود کامند لاین هم میتونید به این محیط برسید . کافیست کامند لاین را باز کنید ( Windows+R ) و ابتدا وارد مسیر محل نصب پایتون شده : cd C:\program Files\Python3.5.2 (ممکن است مسیر فوق برای شما متفاوت باشد ) و بعد پایتون را اجرا کنید : Python فرقی نداره که با کدوم روش به محیط تعاملی پایتون برسید . مهم اینه که به این محیط رسیده اید و می توانید کد نویسی کنید . برای خروج از محیط تعاملی برنامه پایتون کافیست کلمه quit() رو نوشته و اینتر بزنید . همانطور که می بینید سه علامت <<< در ابتدای خط وجود دارد . هرگاه این ۳ علامت را دیدید بدونید که میحط کدنویسی پایتون آماده هست و منتظر شماست برای کد پایتون نوشتن . حالا با خیال راحت در این پنجره کد پرینتی که به شما آموزش دادم رو بنویسید و اینتر بزنید . خواهید دید که جمله شما به زیبایی پرینت گرفته خواهد شد . ما برای ابتدای کار بیشتر در میحط IDLE کد نویسی خواهیم کرد و از هیج کدوم از ۲ روش فوق کار نخواهیم کرد . استفاده از محیط IDLE در پایتون رو در جلسه بعدی آموزش به شما عزیزان خواهم گفت . امیدوارم استفاده کافی رو برده باشید از این آموزش . خسته نباشید . امیدوارم که از جلسه ششم آموزش استفاده کامل رو برده باشید . تمامی حقوق برای انجمن پایتونی ها محفوظ می باشد . پایتونی ها
  17. این تاپیک پشتیبانی برای آموزش است شروع کار با حالت اسکریپتی و تعاملی مفسر زبان پایتون ( جلسه ششم ) 31/02/96 13:05 31/02/96 14:47 لطفا اگرهر سوال یا بازخوردی دارید اینجا ارسال کنید.
  18. به نام خدا . با جلسه چهارم از سری آموزش برنامه نویسی پایتون مقدماتی در خدمت شما عزیزان هستیم . در این قسمت قصد داریم نحوه دانلود و نصب و راه اندازی نرم افزار پایتون رو به شما آموزش بدیم . با ما همراه باشید . آموزش نصب پایتون ( python ) بر روی لینوکس - اوبونتو خب برای اینکه ما بتوانیم به راحتی کدهای پایتون خودمون رو بنویسیم باید نرم افزار پایتون رو نصب کنیم . شرکت ارائه دهنده پایتون یک پکیج رو برای ما آماده کردن که در آن مفسر پایتون ( همون بخشی که کدهای شما را ترجمه و تفسیر میکند ) و ادیتوری به صورت پیش فرض با نام IDLE و یکسری کتابخانه پیش فرض و ... وجود دارند . بر روی اکثر توزیع های سیستم عامل لینوکس پایتون نصب هست و وجود دارد . برای مطمئن شدن ترمینال لینوکس خود را باز کنید و کدهای زیر را برای ورژن های مختلف بنویسید و چک کنید . python --version python2 --version python3 --version در این تاریخی که بنده براتون آموزش گذاشتم خروجی دستورات بالا در ترمینال بنده به صورت زیر هست : Python 2.7.12 Python 2.7.12 Python 3.5.2 اگر به هر دلیلی اعم از آپدیت نبودن نسخه لینوکس و یا ... مشاهده کردید که نسخه پایین تر از نسخه فعلی بر روی سیستم عامل شما نصب است از طریق کدهای زیر آخرین نسخه پایتون ۳ را بر روی سیستم عامل اوبونتو خود نصب کنید : حتما از اتصال کامپیوتر خود به اینترنت اطمینان حاصل کنید . چون احتیاج به دانلود یکسری فایل توسط اوبونتو می باشد . sudo apt-get install python3.5.2 با توجه به دستور apt-get ( در پایین آموزش یه توضیح کوتاه راجب این دستور میدم ) میتونید مستقیما برنامه پایتون ( یا هر برنامه دیگری ) را آپدیت کنید . البته بجای عدد آخر ( ورژن پایتون ) شما جدیدترین ورژن پایتون رو بنویسید ( از سایت رسمی پایتون آمار آخرین ورژن پایتون رو داشته باشید ) . یا میتونید با دستور زیر تمام برنامه های خود را به طور کلی آپدیت کنید . sudo apt-get upgrade یا میتوانید از مجموع کدهای زیر استفاده کنید . فقط باید دستورات به ترتیب و پشت هم نوشته و اجرا شوند . sudo apt-get install libssl-dev openssl cd /opt sudo wget python.org/ftp/python/3.5.0/Python-3.5.0.tgz sudo tar -xzvf Python-3.5.0.tgz cd Python-3.5.0 ./configure make sudo make install نکته : اعداد مربوط به ورژن ها رو همچنان دقت کنید که اشتباه وارد نکنید . از سایت رسمی پایتون آمار آخرین ورژن پایتون رو داشته باشید . توضیح کوتاه درباره دستور apt-get و ساختار دستوری آن : دستور apt get ابزاری است قدرتمند و یک سیستم مدیریت بسته موجود در خط فرمان می‌باشد که مخفف Advanced Packaging Tool می‌باشد . به معنای سیستم بسته بندی پیشرفته و دستور apt get به منظور مدیریت بسته های نرم‌افزاری در سیستم‌های مبتنی بر دبیان ( اوبونتو ) به کار می‌رود . مدیریت یعنی نصب ، بروزرسانی و حذف بسته های نرم افزاری . یعنی از طریق دستور apt get می‌توانید برنامه‌های جدید را نصب و بروزرسانی کنید و برنامه‌های موجود را حذف کنید . چگونه سیستم بسته ها را بروزرسانی کنیم ؟ دستور update به منظور همگام سازی ایندکس فایل‌ها از مخارن تعیین شده در فایل /etc/apt/sources.list به کار می‌رود . توزیع‌های لینوکس دارای یکسری مخازن نرم‌افزاری هستند که لینک هر مخزن در داخل فایل sources.list قرار داده شده است . شما با وارد کردن دستور update به صورت زیر در‌واقع این لینک های موجود را بررسی می‌کنید . لیست بسته ها را از مخازن دریافت کرده و لیست را بروز می‌کند (تصویر زیر کامل نیست) : sudo apt-get update چگونه بسته های نرم افزاری را آپگرید کنیم ؟ دستور upgrade به منظور بروزرسانی و دانلود همه بسته های نرم افزاری جدید به کار می‌رود . این دستور تحت هیچ شرایطی بسته های نصب شده فعلی را حذف نمی‌کند . برای آپگرید کافی است ساختار دستوری زیر را در خط فرمان وارد کنید : sudo apt-get upgrade خب کار ما به پایان رسیده . با دستوراتی که در اول آموزش گفته شد حتما چک کنید باید پایتون شما به آخرین نسخه آپدیت شده باشه . امیدوارم که از این آموزش استفاده کرده باشید . هرگونه سوالی داشتید در تاپیک مخصوص این آموزش مطرح کنید . خسته نباشید . امیدوارم که از جلسه چهارم آموزش استفاده کامل رو برده باشید . تمامی حقوق برای انجمن پایتونی ها محفوظ می باشد . پایتونی ها
  19. این تاپیک پشتیبانی برای آموزش است معرفی کوتاه نسخه های زبان برنامه نویسی پایتون ( جلسه دوم ) 30/02/96 10:46 لطفا اگرهر سوال یا بازخوردی دارید اینجا ارسال کنید.
  20. به نام خدا . با سلام خدمت دوستان عزیز پایتونی ها . با جلسه دوم آموزش صفر تا صد زبان برنامه نویسی پایتون در خدمت شما دوستان عزیز هستیم . ما در ۲۴ ساعت شبانه روز آماده انتقادات و پیشنهادات و حمایت های شما کاربران عزیز هستیم . معرفی نسخه های مختلف زبان برنامه نویسی پایتون ( Python ) پس از طراحی و پیاده سازی زبان پایتون و انتشار اولین نسخه ی برنامه ی کاربردی پایتون که نرم افزاری برای اجرای کدهای نوشته شده به زبان پایتون است، توسعه ی آن ادامه می یافت و توزیع های مختلفی از آن به همراه اصلاحات، بهبود امکانات، یا افزودن قابلیت های جدید منتشر شده اند. این نام گذاری های نسخه های زبان برنامه نویسی پایتون به شکل x.y.z هست که از شماره 0.9.0 شروع شده و همچنان ادامه داره . تغریبا تمام نرم افزارها اینگونه ورژن های بالاتر را ارائه میکنند . اگر در ورژن جدید ارائه شده تغییرات اساسی در بنیاد نرم افزار به وجود آید بر این اساس مطمئنا مقدار x افزایش پیدا میکنه ، اگر تغییراتی با اولویت کمتر نسبت به معیار قبلی به وجود بیاد عدد y مقدارش تغییر میکنه ، و در صورت رفع باگ های احتمالی در یک نسخه ی منتشر شده، مقدار z در توزیع اصلاح شده افزایش می یابد . در بعضی از نرم افزار ها میبینید که به صورت مختصر می نویسند این اعداد رو و عدد آخر رو نمی نویسند . به طور کلی، کاربران همزمان با آپدیت هر نرم افزار به نسخه ی جدید آن نرم افزار مهاجرت می کنند و برنامه نویسان نیز از این قاعده مستثنی نیستند. توسعه دهندگان زبان برنامه نویسی Python در اکتبر سال 2000 نسخه ی پایدار 2.0 را با ایجاد تغییرات اساسی در ادامه ی توزیع 1.6 منتشر کردند و پس از آن نیز روند تغییر و اصلاح روی این توزیع جدید ادامه یافت. با این حال آقای روسوم ( خالق اصلی زبان پایتون ) از روند این اصلاحات رضایت چندانی نداشت و همواره در فکر ایجاد تغییرات بنیادی در ساختار و سینتکس پایتون بود تا به هدف اصلی خود از طراحی این زبان یعنی دستیابی به ساختاری ساده و در عین حال مستحکم و قدرتمند برسد. یکی از مشکلاتی که آقای روسوم در این راه با آن مواجه بود عدم تطبیق پذیری نسخه های قبلی با ساختار ساده ای بود که روسوم در ذهن داشت، به همین دلیل یک دوراهی در مسیر توسعه ی پایتون قرار گرفت: فرآیند توسعه یا باید روی همان ساختار و سینتکس نسخه های قبلی ( که به روز ترین آنها نسخه های 2 به بالا بودند ) ادامه پیدا می کرد، که با افزودن قابلیت های جدید به آن رفته رفته پایتون تبدیل به زبانی پیچیده می شد، یا این که ساختار زبان تغییر اساسی پیدا می کرد که با وجود عدم تطبیق با نسخه های قبلی ساده تر بود و با حذف پیچیدگی ها کار برنامه نویسی را راحت تر می کرد. در نهایت پس از بررسی های فراوان روسوم تصمیم گرفت به جای حفظ ساختار قبلی، هدف خود را دنبال کرده و پس از ایجاد تغییرات مورد نظر در دسامبر سال 2008 توزیع نسخه های 3 پایتون با نام Py3K یا Python 3000 با شماره ی 3.0 آغاز شد. به عقیده ی آقای روسوم احتمالاً کاربران پایتون در نگاه اول تغییرات چندانی را در توزیع جدید تشخیص نمی دهند، با این حال او این اطمینان را می دهد که در طراحی این نسخه بسیاری از موارد آزاردهنده، نقص ها و نتایج حاصل از ساختارهای نادرست قبلی رفع شده اند که از جمله این اصلاحات می توان به تغییر در کلاس اعداد صحیح، قبول ()print به عنوان یک تابع، حذف برخی سینتکس ها مثل (<>)، افزودن سینتکس های جدید، تغییر در سینتکس های قبلی، تغییر در کتابخانه های استاندارد پایتون، تغییر در برخی عملگرها و توابع، پشتیبانی بهتر از یونیکد، و ... اشاره کرد. امیدوارم که از جلسه دوم آموزش استفاده کامل رو برده باشید . تمامی حقوق برای انجمن پایتونی ها محفوظ می باشد . پایتونی ها منبع : آکادمی