کار با دیتابیس جنگو
تو این آموزش قراره نحوه تعامل و کار با دیتابیس جنگو رو با هم یاد بگیریم.
QuerySet ها در جنگو
حالا که یه پنل ادمین خوشگل و تر و تمیز داریم، دیگه وقتشه که یاد بگیریم چطور میتونیم با اطلاعاتی که توی دیتابیسمون ذخیره کردیم کار کنیم.
جنگو به صورت پیشفرض یه API abstract داره که به ما اجازه ساختن، فراخوانی کردن، آپدیت کردن و همینطور حذف کردن اشیا رو میده.
سیستم ORM جنگو یا همون (object-relational mapper) با انواع دیتابیس ها از جمله MySql، PostgreSQL، SQLite، Oracle و MariaDB سازگاری داره که قابلیت های فوق العاده عالی فریمورک جنگو به شمار میره.
فریمورک جنگو میتونه در آن واحد با چند تا دیتابیس مختلف بصورت همزمان کار کنه، و همینطور میشه روترهایی برای دیتابیس نوشت که چطوری با دیتابیس های موجود تعامل کنه!
سیستم ORM جنگو بر اساس QuerySet ها بنا شده.
حالا QuerySet چیه؟
QuerySet یه دیکشنری از کوئری های دیتابیس هستش که برای استخراج اشیا از دیتابیس بکار میرن.
ضمناً میتونیم با ارسال کردن پارامترهای دلخواهمون به QuerySet، نتایجی که از دیتابیس استخراج میشن رو فیلتر بکنیم.
ساخت اشیا در دیتابیس جنگو
وقتی داشتیم راجع به پنل مدیریت جنگو صحبت میکردیم، با هم یه مطلب ساختیم.
حالا برای اینکه یه چیز جدید هم یاد بگیریم، به جای استفاده از اون مطلب که پیشتر ساختیمش، میایم و از طریق shell یه پست جدید ایجاد میکنیم:
چطوری؟! اینطوری:
توی ترمینال کنسولتون دستور زیر رو وارد کنین:
python manage.py shell
و بعدش به ترتیب دستورات زیر رو تایپ کنین(هر خط رو تایپ کردید اینتر کنین که دستورتون مورد قبول سیستم واقع بشه و به سطر بعد برید):
>>> from django.contrib.auth.models import User >>> from blog.models import Post >>> user = User.objects.get(username='admin') >>> post = Post(title='Another post', ... slug='another-post', ... body='Post body.', ... author=user)
تا اینجا، هر کدی که نوشتیم فقط توی حافظه موقت سیستم هستش.
در نهایت برای ذخیره این شئ تو دیتابیس، حتماً باید save کنیمش:
>>> post.save()
حالا بریم سر وقت بررسی کدهایی که نوشتیم:
خط اول و دوم که مشخصه داریم کلاسهای مورد نیاز رو ایمپورت میکنیم.
خط سوم چیه؟
تو اینجا از یه متد به اسم ()get استفاده کردیم.
حالا کار متد ()get چیه؟
متد ()get توی جنگو برای استخراج کردن یک شئ خاص(توجه کنید که فقط و فقط یک شئ) از دیتابیس استفاده میشه. نکته ای که باید بهش دقت کرد اینه که این متد انتظار نتیجه ای رو داره که با کوئری ای که داخلش نوشتیم مطابقت داشته باشه. اگر نتیجه ای مطابق اون چیزی که انتظار داره پیدا نشه، خطای DoesNotExist رو بر میگردونه. همینطور هم اگه بیشتر از یه نتیجه رو برگردونه یه خطای دیگه با عنوان MultipleObjctsReturned بر میگردونه.
پس با این تفاسیر توی خط سوم مشخص شد که داریم میگیم از بین اشیای موجود در دیتابیس User، بیا و username ای رو برامون استخراج کن که مقدارش admin هستش و در نهایت هم اون رو داخل متغیری به اسم user بریز.
تو چند خط بعدی داریم یک نمونه شئ مطلب (یک نمونه از Post) میسازیم و مقادیر اون رو همونطور که میبینید قرار میدیم.
در نهایت با استفاده از متد ()save شئ جدیدمون رو تو دیتابیس ذخیره میکنیم.
حالا این متد ()save که استفاده کردیم میاد چیکار میکنه؟
این متد میاد و پشت صحنه برامون یه دستور INSERT به SQL رو اجرا میکنه.
حالا اگه بخوایم همه کارهایی که الان تو چند خط انجام دادیم رو فقط از طریق یه خط انجام بدیم(ینی همزمان هم مقادیر دلخواه تو فیلدها بذاریم و هم تو دیتابیس ذخیره کنیم، میتونیم از متد ()create استفاده کنیم:
Post.objects.create(title='One more post', slug='one-more-post', body='Post body.', author=user)
بروزرسانی اشیا در دیتابیس جنگو
اگه بخوایم مثلاً عنوان(title) مطلبمون رو از طریق کنسول ترمینال جنگو تغییر بدیم، خیلی راحت میتونیم در ادامه shell بیایم و دستورات زیر رو وارد کنیم:
>>> post.title = 'New title' >>> post.save()
اینبار متد ()Save که ازش استفاده کردیم میاد و عملیات update رو انجام میده.
استخراج اشیا از دیتابیس جنگو
یه مقدار قبلتر، فهمیدیم که با استفاده از متد ()get توی جنگو میتونیم یک شئ خاص رو از دیتابیسمون به این صورت: ()Post.objects.get استخراج کنیم.
توی جنگو، هر مدلی که میسازیم، حداقل یک manager داره که به صورت پیشفرض توسط objects فراخوانی میکنیمش.
(توجه کنید که با استفاده از manager مدلمون، یک شئ QuerySet دریافت خواهیم کرد.)
حالا برای استخراج کردن همه اشیای موجود توی جدول دیتابیسمون، فقط نیاز هستش که از متد ()all استفاده کنیم:
>>> all_posts = Post.objects.all()
به این ترتیب ما یه QuerySet ساختیم که همه اشیای موجود توی دیتابیس رو برامون در بیاره.
فقط دقت کنید که این QuerySet هنوز اجرا نشده و فقط نوشتیمش.
QuerySet های جنگو اصطلاحاً lazy (تنبل!) هستن، یعنی اینکه فقط در زمانی که مجبور باشن اجرا میشن. به همین خاطرم هست که QuerySet های جنگو خیلی بهینه هستن.
حالا چه زمانی مجبور میشن کاری که ازشون خواستیم(مثلاً اینجا ازشون خواستیم که همه Post ها رو برامون استخراج کنن) رو انجام بدن؟
وقتی بیایم و مستقیماً بهش بگیم که مقادیر متغیر مورد نظرم رو بهم نشون بده:
>>> all_posts
متد ()filter جنگو
برای فیلتر کردن یک QuerySet در جنگو میتونیم از متد ()filter موجود در manager پیشفرض مدلمون استفاده کنیم.
مثلاً اگه بخوایم همه مطالب منتشر شده در سال 2021 رو استخراج کنیم QuerySet زیر رو مینویسیم:
>>> Post.objects.filter(publish__year=2021)
همینطور اگه بخوایم مطالبی که در سال 2021 و توسط نویسنده admin نوشده شده رو استخراج کنیم، میتونیم QuerySet زیر رو بنویسیم:
>>> Post.objects.filter(publish__year=2021, author__username='admin')
نکته مهم: توجه کنید دستوری که توی پرانتز متد ()filter مینویسیم یه دستور SQL هستش.
یکی از قابلیت های دیگه ای که توی کوئری ها میتونیم برای گذاشتن شروط مختلف ازش استفاده کنیم متدهای lookup هستن. مثلاً اگه بخوایم مطالبی که توسط نویسنده admin و بعد از شروع سال 2021 منتشر شده اند رو استخراج کنیم، باید QuerySet زیر رو بنویسیم:
>>> Post.objects.filter(publish__year__gte=2021, author__username__contains=’admin’)
دقت کنید که برای استفاده از lookup ها باید از 2 تا آندرلاین استفاده کنیم.
متد ()exclude در جنگو
با استفاده از متد exclude() میتونیم نتایج خاصی رو از QuerySet مون خارج کنیم. بر فرض مثال اگر بخوایم همه مطالب منتشر شده در سال 2021 که عنوانشون با First شروع نمیشه رو استخراج کنیم، QuerySet زیر رو می نویسیم:
>>> Post.objects.filter(publish__year=2021) \ >>> .exclude(title__startswith='First')
متد ()order_by در QuerySet جنگو
همونطور که از اسمش مشخصه، اگر بخوایم QuerySet ای که تو جنگو زدیم رو مرتب شده استخراج کنیم، میتونیم از متد ()order_by موجود در manager مدلمون استفاده کنیم.
به عنوان نمونه، برای مرتب کردن نزولی همه مطالب استخراج شده بر مبنای title، از QuerySet زیر استفاده میکنیم:
>>> Post.objects.order_by('title')
و در صورتی که بخوایم مرتب سازی بصورت صعودی انجام بدیم، کافیه فقط یه علامت منفی قبل از title قرار بدیم:
>>> Post.objects.order_by('-title')
حذف اشیا توسط QuerySet جنگو
برای حذف کردن شئ مورد نظرمون میتونیم از متد ()delete استفاده کنیم:
>>> post = Post.objects.get(id=1) >>> post.delete()
فقط نکته ای که باید بهش دقت کرد اینه که اگر توی مدلمون متد on_delete رو روی CASCADE تنظیم کرده باشیم، با حذف کردن شئ ای که ForeignKey باشه، همه وابسته هاش هم حذف میشن!
زمان اجرا شدن QuerySet ها
همونطور که قبلتر گفتیم، تا زمانی که دستور فعالیت یه QuerySet رو صادر نکنیم، ساختن QuerySet هیچ ارتباطی با انجام شدن عملیاتی روی دیتابیس نداره.
QuerySet ها معمولاً یه QuerySet دیگه رو برامون بر میگردونن.
هر چقدر هم که بخواین میتونین filter های مختلف رو با QuerySet پیادهسازی کنین، اما تا زمانی که دستور فعالیت به QuerySet صادر نشده، هیچ اتفاقی روی دیتابیس نمیفته.
حالا وقتی که دستور فعالیت برای QuerySet صادر بشه چه اتفاقی میفته؟
وقتی که دستور صادر میشه، QuerySet به صورت یه کوئری SQL برای دیتابیس ما ترجمه میشه.
و در نهایت باید این رو بگیم که QuerySet ها چه زمانی فعالیت خواهند کرد:
- اولین باری که میخوایم iterate کنیمشون
- وقتی که میخوایم یه تیکه ازشون جدا(slice) کنیم. مثلاً وقتی میگیم: objects.all()[:3]
- وقتی که کش کنیمشون
- وقتی متدهای ()repr و ()len رو روی اونها فراخونی کنیم.
- وقتی متد ()list رو روشون اجرا کنیم.
- وقتی بخوایم تست کنیمشون. مثلاً توی یه دستور ()bool یا and و or و if .
تو این آموزش با QUerySet های جنگو آشنا شدیم و فهمیدیم که چه کارهایی میشه باهاشون کرد. هر چند که روش های پیشرفته تری از استفاده از queryset ها هم هستش منتهی برای این قسمت فعلاً به همین موارد بسنده کردیم.
تو دوره ساخت وبلاگ با جنگو میتونین استفاده های بیشتر از QuerySet ها رو مشاهده کنین.
ضمناً میتونین از داکیومنت های خود جنگو هم اطلاعات بیشتری در خصوص Query ها و QuerySet های جنگو کسب کنید:
https://docs.djangoproject.com/en/3.1/ref/models/querysets/
https://docs.djangoproject.com/en/3.1/topics/db/queries/
در قسمت بعدی با Manager ها در جنگو آشنا میشیم.
تو آموزش های بعدی مرکز تخصصی آموزش جنگو، کلی مباحث مختلف و خوب داریم که بتونید هرچی بیشتر با مباحث فریمورک قدرتمند جنگو آشنا بشید و یادشون بگیرید.
سوالات و نظراتتون رو هم حتماً حتماً با ما در میون بذارید.
مطالب زیر را حتما مطالعه کنید
صفحه بندی صفحات در جنگو
کار با template ها در جنگو
ساخت URL برای وبلاگ در جنگو
ساخت view برای وبلاگ در جنگو
manager ها در جنگو
ساخت پنل ادمین جنگو
2 دیدگاه
به گفتگوی ما بپیوندید و دیدگاه خود را با ما در میان بگذارید.
سلام امیدوارم حالتون خوب باشه
خیلی خیلی ممنونم بابت این پست
یه مشکلی رو واسم حل کردید که خیلی دنبال رفعش بودم
سلام و احترام خدمت شما
خوشحالیم که براتون مفید بوده و مشکلتون حل شده