دیتابیس Database و مدل Model در Django
دیتابیس Database و مدل Model در جنگو از درس قبل به خاطر دارید که آطلاعات دورهها به صورت ثابت داخل
فرض کنید کلاسی برای حساب بانکی نوشتهاید. اگر هر کسی بتواند موجودی حساب را مستقیماً تغییر دهد، ممکن است مقدار موجودی به عددی منفی یا غیرواقعی تبدیل شود. این موضوع باعث ایجاد خطا و کاهش امنیت برنامه میشود. اینجاست که مفهوم کپسولهسازی (Encapsulation) وارد عمل میشود.
کپسولهسازی یکی از مهمترین اصول برنامهنویسی شیءگرا است که دادهها و توابع مرتبط با آنها را داخل یک کلاس قرار میدهد و از دسترسی یا تغییر مستقیم اطلاعات حساس جلوگیری میکند.
به بیان ساده، کپسولهسازی مانند یک جعبه محافظ عمل میکند؛ اطلاعات مهم داخل کلاس قرار میگیرند و تنها از طریق روشهایی که خود کلاس مشخص کرده است، قابل مشاهده یا تغییر هستند.
این ویژگی باعث میشود:
چند نمونه از کپسولهسازی که هر روز با آنها سروکار داریم:
در همه این مثالها، اطلاعات مهم پنهان شدهاند و تنها از طریق روشهای مشخص و کنترلشده قابل استفاده هستند.
پایتون برخلاف برخی زبانها مانند جاوا یا سیپلاسپلاس، سطح دسترسی سختگیرانه ندارد؛ اما با استفاده از قراردادهای نامگذاری و چند قابلیت داخلی، میتوان اطلاعات را از دسترسی مستقیم محافظت کرد. در این درس با موارد زیر آشنا خواهید شد:
در پایان این درس، میتوانید کلاسهایی طراحی کنید که اطلاعات آنها بهصورت ایمن مدیریت شوند و فقط از مسیرهای مشخص قابل تغییر باشند.
در بسیاری از زبانهای برنامهنویسی مانند جاوا یا ++C، میتوان مشخص کرد که هر ویژگی یا متد تا چه اندازه در دسترس سایر بخشهای برنامه باشد. در پایتون نیز این مفهوم وجود دارد، اما با روشی سادهتر. پایتون بیشتر بر پایه قراردادهای نامگذاری (Naming Conventions) عمل میکند و برنامهنویس با استفاده از یک یا دو خط زیر (_) مشخص میکند که یک ویژگی تا چه اندازه باید در دسترس باشد.
به طور کلی، ویژگیها و متدهای یک کلاس در سه دسته قرار میگیرند:
| نوع دسترسی | نحوه نامگذاری | میزان دسترسی |
|---|---|---|
| Public | name |
از همه جای برنامه قابل دسترسی است. |
| Protected | _name |
بهتر است فقط داخل کلاس و کلاسهای فرزند استفاده شود. |
| Private | __name |
برای استفاده داخلی کلاس در نظر گرفته شده و دسترسی مستقیم به آن محدود میشود. |
اگر نام یک ویژگی را به صورت معمولی بنویسیم، آن ویژگی Public محسوب میشود. این نوع متغیر از هر جای برنامه قابل مشاهده و تغییر است.
مثال
class Student:
def __init__(self):
self.name = "Ali"
student = Student()
print(student.name)
student.name = "Reza"
print(student.name)خروجی
Ali
Rezaدر این مثال، ویژگی name بدون هیچ محدودیتی قابل خواندن و تغییر است.
اگر تغییر مقدار یک ویژگی مشکلی برای برنامه ایجاد نمیکند، بهتر است آن را Public قرار دهیم.
برای مثال:
این اطلاعات معمولاً حساس نیستند و تغییر آنها مشکلی ایجاد نمیکند.
فرض کنید موجودی حساب بانکی را به صورت Public تعریف کنیم.
class BankAccount:
def __init__(self):
self.balance = 1000
account = BankAccount()
account.balance = -50000
print(account.balance)خروجی
-50000واضح است که چنین مقداری منطقی نیست، اما چون balance عمومی است، هر بخشی از برنامه میتواند آن را تغییر دهد. به همین دلیل، برای اطلاعات حساس از Protected یا Private استفاده میکنیم تا کنترل بیشتری روی نحوه دسترسی و تغییر دادهها داشته باشیم.
در پایتون اگر نام یک ویژگی یا متد را با یک خط زیر (_) شروع کنیم، آن عضو Protected محسوب میشود.
_nameبرخلاف برخی زبانهای برنامهنویسی، پایتون دسترسی به اعضای Protected را ممنوع نمیکند. در واقع، استفاده از _ فقط یک قرارداد بین برنامهنویسان (Convention) است. یعنی با دیدن یک خط زیر در ابتدای نام متغیر، سایر برنامهنویسان متوجه میشوند که این عضو برای استفاده داخلی کلاس یا کلاسهای فرزند طراحی شده است و بهتر است مستقیماً از بیرون به آن دسترسی نداشته باشند.
مثال
class Student:
def __init__(self):
self._score = 18
student = Student()
print(student._score)خروجی
18همانطور که مشاهده میکنید، برنامه بدون هیچ خطایی اجرا شد. بنابراین Protected در پایتون فقط یک توصیه است، نه یک محدودیت واقعی.
ممکن است یک ویژگی فقط برای استفاده داخلی کلاس یا کلاسهای فرزند باشد و نخواهیم سایر بخشهای برنامه مستقیماً با آن کار کنند.
برای مثال:
در چنین شرایطی، استفاده از _ باعث میشود سایر برنامهنویسان بدانند که بهتر است این متغیر را مستقیماً تغییر ندهند.
مثال کاربردی
class Employee:
def __init__(self):
self._salary = 50000
employee = Employee()
print(employee._salary)
employee._salary = 70000
print(employee._salary)خروجی
50000
70000اگرچه مقدار متغیر تغییر کرد، اما طبق اصول برنامهنویسی شیءگرا بهتر است چنین تغییری فقط از طریق متدهای کلاس انجام شود.
Protected امنیت واقعی ایجاد نمیکند و همچنان میتوان از خارج کلاس به آن دسترسی داشت. به همین دلیل، اگر بخواهیم از اطلاعات حساس بهتر محافظت کنیم، از Private استفاده میکنیم.
| ویژگی | Public | Protected |
|---|---|---|
| نحوه نامگذاری | name |
_name |
| دسترسی مستقیم از خارج کلاس | امکانپذیر است. | امکانپذیر است. |
| هدف استفاده | استفاده عمومی در کل برنامه | استفاده داخلی کلاس و کلاسهای فرزند |
| محدودیت واقعی دسترسی | ندارد. | ندارد. |
| قرارداد بین برنامهنویسان | خیر | بله |
| مناسب برای اطلاعات حساس | خیر | تا حدی (بهعنوان یک توصیه) |
اگر نام یک ویژگی یا متد را با دو خط زیر (__) شروع کنیم، آن عضو Private محسوب میشود.
__nameهدف از Private این است که از دسترسی مستقیم به اطلاعات مهم کلاس جلوگیری شود. برخلاف Protected که تنها یک قرارداد بین برنامهنویسان بود، پایتون برای اعضای Private مکانیزمی به نام Name Mangling را به کار میبرد تا دسترسی مستقیم به آنها دشوارتر شود. به همین دلیل، اگر از بیرون کلاس بخواهید مستقیماً به یک عضو Private دسترسی پیدا کنید، با خطا مواجه خواهید شد.
مثال
class Student:
def __init__(self):
self.__score = 20
student = Student()
print(student.__score)خروجی
AttributeError: 'Student' object has no attribute '__score'در این مثال، ویژگی __score از خارج کلاس قابل دسترسی نیست و برنامه خطا تولید میکند.
گاهی برخی اطلاعات نباید مستقیماً توسط سایر بخشهای برنامه تغییر کنند. برای مثال:
در چنین شرایطی بهتر است این اطلاعات را به صورت Private تعریف کنیم تا فقط خود کلاس بتواند آنها را مدیریت کند.
class BankAccount:
def __init__(self):
self.__balance = 1000در این کلاس، موجودی حساب به صورت Private تعریف شده است؛ بنابراین سایر بخشهای برنامه نمیتوانند مستقیماً مقدار آن را تغییر دهند. به جای دسترسی مستقیم، کلاس میتواند متدهایی مانند deposit() و withdraw() را در اختیار کاربران قرار دهد تا افزایش یا کاهش موجودی به شکل کنترلشده انجام شود.
زمانی که یک ویژگی را با دو خط زیر تعریف میکنید، پایتون نام آن را در پشت صحنه تغییر میدهد تا از دسترسی تصادفی جلوگیری شود. برای مثال، اگر کلاس زیر را داشته باشیم:
class Student:
def __init__(self):
self.__score = 20پایتون در پشت صحنه نام متغیر را تقریباً به این شکل تغییر میدهد:
_Student__scoreبه همین دلیل، عبارت زیر خطا میدهد:
student.__scoreاما در واقع مقدار همچنان داخل شیء وجود دارد و فقط نام آن تغییر کرده است.
اعضای Private کاملاً مخفی نیستند و در صورت نیاز میتوان از طریق نام تغییریافته به آنها دسترسی پیدا کرد. بنابراین Private در پایتون بیشتر برای محافظت منطقی از دادهها استفاده میشود، نه ایجاد امنیت غیرقابل نفوذ.
| ویژگی | Protected | Private |
|---|---|---|
| نحوه نامگذاری | _name |
__name |
| دسترسی مستقیم از خارج کلاس | امکانپذیر است. | امکانپذیر نیست. |
| هدف استفاده | نشان دادن اینکه عضو برای استفاده داخلی کلاس یا کلاسهای فرزند در نظر گرفته شده است. | محافظت بیشتر از اطلاعات حساس و جلوگیری از دسترسی مستقیم. |
| محدودیت واقعی دسترسی | ندارد. | دسترسی مستقیم را محدود میکند. |
| تغییر نام توسط پایتون (Name Mangling) | خیر | بله |
| مناسب برای اطلاعات حساس | تا حدی (بهعنوان یک قرارداد) | بله |
تا اینجا یاد گرفتیم چگونه با استفاده از __ متغیرهای Private ایجاد کنیم. اما یک سؤال مهم وجود دارد: اگر یک متغیر Private باشد، چگونه میتوان مقدار آن را خواند یا تغییر داد؟ برای حل این مشکل از Getter و Setter استفاده میکنیم.
Getter یک متد داخل کلاس است که برای خواندن مقدار یک ویژگی Private استفاده میشود. به عبارت ساده متغیر Private را مستقیم نمیخوانیم؛ بلکه یک متد مخصوص ایجاد میکنیم تا مقدار آن را برگرداند.
فرض کنید یک کلاس برای دانشجو داریم:
class Student:
def __init__(self):
self.__score = 18
student = Student()
print(student.__score)خروجی:
AttributeError: 'Student' object has no attribute '__score'چون score یک ویژگی Private است، نمیتوانیم مستقیماً به آن دسترسی داشته باشیم.
class Student:
def __init__(self):
self.__score = 18
def get_score(self):
return self.__score
student = Student()
print(student.get_score())خروجی:
18در این مثال، متد get_score() نقش Getter را دارد و مقدار متغیر Private را در اختیار ما قرار میدهد.
شاید در نگاه اول به نظر برسد که Getter فقط یک مقدار را برمیگرداند و کار خاصی انجام نمیدهد؛ اما در پروژههای واقعی اهمیت زیادی دارد. با استفاده از Getter میتوانیم:
برای مثال:
def get_score(self):
return f"نمره دانشجو: {self.__score}"خروجی:
نمره دانشجو: 18Setter یک متد داخل کلاس است که برای تغییر مقدار یک ویژگی Private استفاده میشود. به جای اینکه مقدار متغیر را مستقیماً تغییر دهیم، از یک متد استفاده میکنیم تا بتوانیم مقدار جدید را کنترل کنیم.
فرض کنید نمره دانشجو را مستقیماً تغییر دهیم:
student.__score = -10این مقدار منطقی نیست، زیرا نمره نباید منفی باشد. پس بهتر است قبل از تغییر مقدار، آن را بررسی کنیم.
class Student:
def __init__(self):
self.__score = 18
def get_score(self):
return self.__score
def set_score(self, score):
if 0 <= score <= 20:
self.__score = score
else:
print("نمره نامعتبر است")
student = Student()
student.set_score(19)
print(student.get_score())خروجی:
19اگر مقدار نامعتبر وارد کنیم:
student.set_score(-5)خروجی:
نمره نامعتبر استدر اینجا Setter اجازه نمیدهد مقدار اشتباه وارد ویژگی Private شود.
ترکیب Private + Getter + Setter باعث میشود:
در برنامههای واقعی مانند سیستم بانکی، فروشگاه اینترنتی و سامانههای آموزشی، این روش بسیار پرکاربرد است.
در بخش قبل یاد گرفتیم که برای دسترسی کنترلشده به متغیرهای Private از متدهای Getter و Setter استفاده کنیم. روش قبلی کاملاً درست است، اما در پایتون یک روش حرفهایتر و خواناتر نیز وجود دارد که با استفاده از دکوراتور @property انجام میشود.
با استفاده از @property میتوانیم کاری کنیم که یک ویژگی Private مانند یک ویژگی معمولی خوانده یا تغییر داده شود، در حالی که همچنان کنترلهای لازم روی آن وجود دارد.
در روش قبلی برای خواندن مقدار باید یک متد را صدا میزدیم:
student.get_score()و برای تغییر مقدار نیز از یک متد دیگر استفاده میکردیم:
student.set_score(19)اما در پایتون میتوانیم این کار را سادهتر کنیم:
student.scoreو:
student.score = 19در ظاهر مانند یک متغیر معمولی رفتار میکند، اما در پشت صحنه Getter و Setter اجرا میشوند.
@propertyبرای تبدیل یک متد به Getter کافی است قبل از آن از دکوراتور @property استفاده کنیم.
مثال:
class Student:
def __init__(self):
self.__score = 18
@property
def score(self):
return self.__score
student = Student()
print(student.score)خروجی:
18دقت کنید که دیگر از پرانتز استفاده نکردیم:
student.scoreنه:
student.score()زیرا @property باعث میشود متد مانند یک ویژگی معمولی رفتار کند.
@score.setterبرای تغییر مقدار ویژگی، از یک Setter استفاده میکنیم.
Setter با استفاده از همان نام Getter و دکوراتور زیر ساخته میشود:
@score.setter@propertyclass Student:
def __init__(self):
self.__score = 18
@property
def score(self):
return self.__score
@score.setter
def score(self, value):
if 0 <= value <= 20:
self.__score = value
else:
print("نمره نامعتبر است")
student = Student()
print(student.score)
student.score = 20
print(student.score)خروجی:
18
20حالا اگر مقدار نامعتبر وارد کنیم:
student.score = 30خروجی:
نمره نامعتبر استSetter اجازه نمیدهد مقدار غیرمجاز وارد متغیر Private شود.
@property چند مزیت مهم دارد:
Student ایجاد کنید.
ویژگیهای زیر را برای کلاس در نظر بگیرید:
BankAccount طراحی کنید.
ویژگیها:
User ایجاد کنید.
ویژگیهای کلاس:
Product ایجاد کنید.
ویژگیها:
تا اینجا با مفاهیم اصلی برنامهنویسی شیءگرا مانند کلاس، وراثت و کپسولهسازی آشنا شدیم. اما در پروژههای واقعی، معمولاً تمام کدها در یک فایل نوشته نمیشوند و برای مدیریت بهتر برنامهها نیاز داریم با فایلها، ماژولها و کتابخانههای مختلف کار کنیم. در بخش بعدی یاد میگیریم چگونه اطلاعات را در فایلها ذخیره کنیم، کدهای خود را به ماژولهای جداگانه تقسیم کنیم و از پکیجها و کتابخانههای آماده پایتون استفاده کنیم.
گام بعدی : فایل و کتابخانه در پایتوندیتابیس Database و مدل Model در جنگو از درس قبل به خاطر دارید که آطلاعات دورهها به صورت ثابت داخل
طراحی قالب سایت با HTML، CSS و Tailwind CSS تا اینجا با ساختار اصلی Django، URL، View و Template آشنا
Template و رابط کاربری در Django در سه درس قبلی، با ساخت پروژه، ساختار Django، URL و View آشنا شدیم.
URL و View در جنگو در درسهای قبل با Django آشنا شدیم، محیط مجازی را ساختیم، Django را نصب کردیم
ساختار Project و App در Django در درس قبل با Django آشنا شدیم، محیط مجازی ساختیم، Django را نصب کردیم
شروع کار با Django در دوره آموزش جامع پایتون با مفاهیمی مانند متغیرها، شرطها، حلقهها، توابع، کلاسها، فایلها و کار
عملیات CRUD درSQLite در بخش قبل با مفهوم پایگاه داده، SQLite و نحوه اتصال پایتون به پایگاه داده آشنا شدیم.
اتصال به پایگاه داده (Database) در پایتون وقتی یک برنامه اطلاعاتی را از کاربر دریافت میکند، معمولاً لازم است این
مدیریت خطا (Error Handling) در پایتون در هنگام اجرای برنامه، ممکن است کاربر ورودی نامناسبی وارد کند یا برنامه با
کار با فایل، ماژول، پکیج و محیط مجازی در پایتون در پروژههای واقعی، معمولاً همهی کدها را در یک فایل
کپسولهسازی (Encapsulation) در پایتون فرض کنید کلاسی برای حساب بانکی نوشتهاید. اگر هر کسی بتواند موجودی حساب را مستقیماً تغییر
وراثت و مفاهیم پیشرفته شی گرایی تا اینجا یاد گرفتهاید که چگونه با استفاده از کلاس (Class) و شی (Object)
کلاس و شیء در پایتون (Object-Oriented Programming) تا اینجا با متغیرها، شرطها، حلقهها، توابع و ساختارهای داده در پایتون آشنا
تابع لامبدا (Lambda Function) در پایتون گاهی اوقات فقط به یک تابع خیلی کوچک نیاز داریم؛ تابعی که قرار است
توابع در پایتون اگر هنگام برنامهنویسی مجبور شوید یک قطعه کد را بارها تکرار کنید، برنامه شما طولانی، شلوغ و
مجموعه (Set) در پایتون به زبان ساده، Set مجموعهای از عناصر منحصربهفرد (Unique) است که ترتیب مشخصی ندارد و اجازه
دیکشنری در پایتون تا اینجا با لیست (List) و تاپل (Tuple) آشنا شدیم که هر دو مجموعهای از دادهها را
تاپل (Tuple) در پایتون بعد از آشنایی با لیست (List)، نوبت به یکی دیگر از ساختارهای داده در پایتون یعنی
لیست (List) در پایتون پرکاربردترین ساختار داده تا اینجا یاد گرفتید که هر متغیر فقط یک مقدار را در خود
ساختارهای داده در پایتون در برنامههای واقعی معمولاً با یک داده سروکار نداریم، بلکه باید تعداد زیادی اطلاعات را ذخیره
حلقههای تکرار در پایتون (Python Loops) فرض کنید معلم میخواهد نمرات ۳۰ دانشآموز را از کاربر دریافت کند. اگر حلقه
عملگرهای مقایسهای (Comparison Operators) تا اینجا یاد گرفتیم که با عملگرهای محاسباتی میتوانیم اعداد را با هم جمع، تفریق و…
دریافت ورودی از کاربر در پایتون (Python Input) تا اینجا یاد گرفتیم که چگونه مقدار یک متغیر را خودمان داخل
عملگرهای محاسباتی در پایتون (Arithmetic Operators) تقریباً تمام برنامهها به انجام محاسبات نیاز دارند؛ از جمع و تفریق ساده گرفته
کار با رشتهها در پایتون (Python Strings) مدیریت و پردازش متنها در برنامهها در دنیای برنامهنویسی، اطلاعات همیشه عدد و
متغیرها در پایتون (Python Variables) اولین قدم برای ذخیره و پردازش اطلاعات تصور کنید یک برنامه مینویسید که قرار است
شروع برنامه نویسی با پایتون ساخت اولین پروژه (Hello World) فهرست مطالب بعد از نصب Python چه کاری انجام دهیم؟
آموزش نصب پایتون و ابزارهای موردنیاز (راهنمای کامل برای ویندوز) اگر تصمیم گرفتهاید برنامهنویسی را یاد بگیرید، احتمالاً نام زبان
الگوهای کندل استیک پیشرفته: راهنمای جامع برای معاملهگران حرفهای الگو های کندل استیک پیشرفته (یا به بیان دیگر الگوهای شمعی
آیلتس جنرال یا آکادمیک؟ کدام را باید انتخاب کنیم؟ آیا میدانید که انتخاب اشتباه بین آیلتس آکادمیک و جنرال میتواند
دانلود رایگان نمونه سوالات آزمون PTE جنرال اگر تصمیم گرفتهاید با هدف مهاجرت به یک کشور انگلیسی زبان، در آزمون
معرفی آزمون های زبان انگلیسی معتبر در ایران| کدام یک بهتر است؟ اگه قصد ادامه تحصیل یا مهاجرت داشته باشید،
بهترین روشهای آمادگی برای آزمون تافل چگونه برای آزمون تافل آماده شویم؟ آیا شما هم قصد دارید برای کسب نمره
چگونه در خارج از کشور برای آزمون آیلتس ثبت نام کنیم؟ اگر قصد مهاجرت تحصیلی یا کاری دارید، احتمالاً نام
آزمون GRE مناسب چه رشتههایی است؟ اگر قصد ادامه تحصیل در مقاطع کارشناسی ارشد یا دکترا در دانشگاههای بینالمللی را
بهترین نمونه سوالات اسپیکینگ تافل هوم ادیشن آزمون تافل هوم ادیشن این روزها یکی از پرطرفدارترین گزینهها برای سنجش مهارت
نحوه ثبت نام در آزمون دولینگو در ایران به صورت کامل نحوه ثبت نام در آزمون دولینگو در ایران چگونه
هزینه آزمون GRE در ایران چقدر است؟ اگر قصد مهاجرت تحصیلی دارید، احتمالاً نام آزمون GRE به گوشتان خورده است.
راهنمای کامل ثبتنام و پرداخت هزینه آزمون PTE در ترکیه برای متقاضیان ایرانی آزمون PTE (Pearson Test of English) یکی از
ووچر آزمون چیست و چگونه میتوان آن را تهیه کرد؟ ثبتنام در آزمونهای بینالمللی مانند TOEFL، GRE، PTE، GMAT، IELTS
بهترین تکنیک های لیسنینگ آیلتس برای کسب نمره بالا آزمون آیلتس (IELTS) یکی از معتبرترین آزمونهای ارزیابی مهارت زبان انگلیسی
آزمون پلاس مرجع آموزش برنامهنویسی، هوش مصنوعی، شبکه، نمونه سؤالات کنکورهای کامپیوتر، آزمونهای زبان دکتری و مدارک بینالمللی فناوری اطلاعات است. با ارائه آموزشهای تخصصی، منابع آموزشی و راهنمای آزمونها، به دانشجویان و متخصصان کمک میکنیم تا مهارتهای خود را توسعه داده و در مسیر موفقیت تحصیلی و شغلی گام بردارند.