> اشتباهات برنامهنویسها معمولاً **بخشودنی** هستند. آنهادر طول کار روزانه **باگهای زیادی** ایجاد میکنند یا در طراحی نرمافزار دچار **خطا** میشوند؛ خطاهایی که اغلب در **بازبینی کد** *(Code Review)* توسط افراد باتجربهتر **شناسایی** و **برطرف** میشوند. با این حال، برخی اشتباهات به دلیل پیامدهای جدی و هزینههای بالایی که به همراه دارند نابخشودنی هستند...
پس از استقبالات فراوان از [سری اول رویداد **#المپیکفناوری پردیس**](https://quera.org/events/techolympics-0307)، دستاندرکاران مجموعه **پارک علموفناوری پردیس** به فکر بازگشایی یک **فروشگاه جدید** و مجهز برای برطرف کردن **نیازهای زندگی برنامهنویسانه**ی اهالی این پارک فناوری و به ویژه شرکتکنندگان [سری جدید مسابقات **#المپیکفناوری پردیس**](https://quera.org/events/techolympics-0407) افتادند. این فروشگاه که پس از راهاندازی، بعدها توسط **پردیسیون** *(Pardision)* به **پردیس شاپ** *(Pardis Shop)* معروف شد هرآنچه که یک برنامهنویس در زندگیاش به آن نیاز داشت، از **انواع و اقسام تنقلات** تا **کیبوردهای مکانیکال** به آنها ارائه میکرد.
**پردیس شاپ،** که به مرور زمان به یکی از **معروفترین فروشگاههای ناحیه فناوری پردیس** تبدیل شد، همواره از نبود یک **فروشگاه آنلاین** برای ارائه **تجربهای بهتر** و **خدماتی بیشتر** به مشتریانش رنج برده است. **علی میو** *(Ali Meow)* یکی از **پردیسیونی** است که به واسطه **علاقهاش به گربهها** *(که محبوبترین حیوانات خانگی نزد برنامهنویسها هستند)* طرفداران زیادی دارد، به عنوان **مسئول طراحی وبسایت پردیس شاپ** انتخاب شده و کارش را از مدتها قبل از برگزاری **سری دوم المپیکفناوری پردیس** شروع کرده است.

**علی میو** برای **مدیریت کاربران** پردیس شاپ **سه مدل جداگانه** طراحی کرده است: *یکی برای مدیران، یکی برای مشتریان و دیگری برای فروشندگان.* در ابتدا همهچیز برای علی و دستاندرکاران پردیس شاپ **ساده** و **قابلمدیریت** بهنظر میرسید، اما با رشد این فروشگاه و افزایش نیازها، کمکم **مشکلات بزرگی** نمایان شد. هر تغییری در سیستم این آنلاین شاپ به **سه جای مختلف** سرایت میکرد و نگهداری کدها به **کابوسی واقعی** تبدیل شده بود! **اشتباه علی** که دیگر تنها یک اشتباه ساده در طراحی نرمافزار نبود، حال به یک **اشتباه بسیار بزرگ** و **نابخشودنی** تبدیل شده است...
# **پروژهی اولیه**
برای دانلود **پروژهی اولیه** روی [این لینک](/contest/assignments/84123/download_problem_initial_project/305475/) کلیک کنید.
<details class="yellow">
<summary>**ساختار فایلها**</summary>
```
pardis_shop
├── users_app
│ ├── <mark class="yellow" title="این پوشه را تغییر دهید"> > migrations < </mark>
│ │ ├── 0001_initial.py
│ │ └── utils
│ │ └── user_migration.py
│ ├── __init__.py
│ ├── <mark class="yellow" title="این فایل را تغییر دهید"> > models.py < </mark>
│ └── ...
├── manage.py
└── ...
```
</details>
<details class="grey">
<summary>**راهاندازی پروژه**</summary>
برای اجرای پروژه، باید **پایتون و ابزار** _pip_ را از قبل نصب کرده باشید.
- ابتدا **پروژهی اولیه** را دانلود و از حالت فشرده خارج کنید.
- در پوشهی اصلی پروژه، یک **محیط مجازی پایتون** _(venv)_ ایجاد و فعال کنید:
```bash terminal terminal
python -m venv venv
source venv/bin/activate # در ویندوز: venv\Scripts\activate
```
- دستور زیر را برای **نصب نیازمندیها** در پوشهی اصلی پروژه اجرا کنید:
```bash terminal terminal
pip install -r requirements.txt
```
- برای **اجرای پروژه** *Django* دستور زیر را در مسیر پوشهی اصلی پروژه اجرا کنید:
```bash terminal terminal
python manage.py runserver
```
در صورت اجرای موفق، **یک لینک** در خروجی نمایش داده میشود که میتوانید **آن را در مرورگر باز کنید.**
- برای **اجرای مایگریشنها** و ایجاد جداول پایگاه داده، دستور زیر را اجرا کنید:
```bash terminal terminal
python manage.py migrate
```
- برای **بارگذاری دادههای نمونه** از **فایل** *fixture،* دستور زیر را اجرا کنید:
```bash terminal terminal
python manage.py loaddata users_fixture.json
```
</details>
# **جزئیات پروژه**
اکنون وقت **بازطراحی مدلهای پردیس شاپ** رسیده است. شما باید **ساختار دادهای** طراحی شده توسط **علی میو** که در **قالب پروژه اولیه** در دسترس شما قرار گرفته را **اصلاح کنید** و آنرا **بهبود ببخشید.** در طراحی اولیهی پروژه، **اپلیکیشنی** با نام `users_app` مسئولیت **مدیریت انواع کاربران** را بر عهده دارد. در این پیادهسازی، **سه مدل مجزا برای کاربران** با نقشهای متفاوت تعریف شده است:
- **مدل** `AdminUser`
- **مدل** `CustomerUser`
- **مدل** `VendorUser`
[**طراحی دیاگرام** *(ER Diagram)*](https://en.wikipedia.org/wiki/Entity%E2%80%93relationship_model) این مدلها به صورت زیر است:

هر یک از این مدلها اطلاعات خاص خود را ذخیره میکنند. با وجود برطرف کردن نیازهای ابتدایی، اکنون مشخص شده که این ساختار از لحاظ طراحی پایگاهداده و اصول مهندسی نرمافزار با **نقصهای جدی** همراه است. وجود **چندین مدل** برای انواع کاربران منجر به **افزونگی، دشواری در توسعه و مشکلات نگهداری** شده است.
**علی میو** پس از مواجهه با مشکلات نگهداری و توسعه در ساختار قبلی، تصمیم به بازطراحی کامل سیستم کاربری گرفته است. شما در این پروژه قرار است بخشهای زیر از **سیستم مدیریت کاربران** را طراحی کنید.
<details class="red">
<summary>**پیادهسازی مدلهای جدید**</summary>
شما باید با استفاده از تصویر زیر که نشان دهنده **ساختار مدلهای جدید** است، **مدلهای جدید کاربران** را پیادهسازی کنید:

**مدلهایی که باید پیادهسازی کنید:**
- **مدل مشترک** `CustomUser`.
- **سه مدل دیگر به نامهای** `AdminProfile`، `CustomerProfile`و `VendorProfile` .
**رابطههای مدلها:**
**مدل** `CustomUser` به عنوان **مدل اصلی کاربر** عمل میکند و شامل فیلدهای مشترک تمام کاربران است. هر یک از **مدلهای پروفایل** (`AdminProfile`، `CustomerProfile`، `VendorProfile`) با **مدل** `CustomUser` **رابطه یکبهیک** دارد، به این معنی که:
- هر کاربر **فقط یک پروفایل** از هر نوع میتواند داشته باشد.
- هر پروفایل **فقط به یک کاربر** متصل است.
- با حذف کاربر، **پروفایل مرتبط نیز حذف میشود.**
- **هر پروفایل** دارای `related_name` **منحصر به فرد** است تا بتوان به راحتی از کاربر به پروفایل دسترسی داشت.
- شما باید این مدلها را **در کنار مدلهای قبلی** (`AdminUser`، `CustomerUser`، `VendorUser`) و در **همان فایل** `models.py` تعریف کنید.
- به عنوان `username` در مدل `CustomUser` میتوانید از **ایمیل کاربران** استفاده کنید.
- برای **کاربران ادمین** در مدل `CustomUser` باید **ویژگیهای** `is_staff` و `is_superuser` مقداردهی شوند.
- توجه داشته باشید که **مدلهای دیگر** موجود در عکس بالا که ربطی هم به مدل یوزر ندارند را **نیازی نیست** در پیادهسازی درنظر بگیرید، **برای این مدلها امتیازی درنظر گرفته نخواهد شد.**
</details>
<details class="blue">
<summary>**ایجاد فایل مایگریشن**</summary>
پس از **پیادهسازی مدلهای جدید،** با استفاده از دستور زیر، **فایل مایگریشن** را بسازید:
```bash terminal terminal
python manage.py makemigrations
```
در نتیجه این عملیات، **فایلی مشابه فایل زیر** ساخته خواهد شد:
```
0002_user_adminprofile_..._.py
```
</details>
<details class="green">
<summary>**پیادهسازی تابع انتقال دادهها**</summary>
در **فایل** `users_app/migrations/utils/user_migration.py` **تابعی با نام** **`migrate_users_forward`** وجود دارد. این تابع وظیفه دارد تا **اطلاعات کاربران** را از **مدلهای قبلی** (`AdminUser`, `CustomerUser`, `VendorUser`) به **مدلهای جدید** منتقل کند و دادهها را بهدرستی در `User` و پروفایلهای مرتبط ذخیره کند.
شما باید **این تابع را تکمیل کرده** و در فایل مایگریشنی که ساختهاید (`0002_...`) با استفاده از `migrations.RunPython(...)` این تابع را اجرا کنید. برای این کار، در بخش `operations` این فایل، دستور زیر را اضافه کنید:
```python 0002_user_adminprofile_..._.py python
from users_app.migrations.utils.user_migration import migrate_users_forward
...
migrations.RunPython(migrate_users_forward, reverse_code=migrations.RunPython.noop)
```
- **توجه:** نیازی به برگشتپذیر بودن این مایگریشن **نیست.**
</details>
# **آنچه باید آپلود کنید**
- **توجه**: پس از پیادهسازی موارد خواسته شده، **کل فایلهای پروژه** بهجز پوشهی `venv` و **فایل** `db.sqlite3` را زیپ کرده و ارسال کنید.
- **توجه**: شما **مجاز به افزودن فایل جدید** به جز **فایل مایگرشن** خواسته شده در این ساختار **نیستید** و تنها باید تغییرات را در فایلهای موجود اعمال کنید.
- **توجه**: که نام فایل _Zip_ اهمیتی **ندارد**.
- **توجه:** در پایان فراموش نکنید که مدل `CustomUser` را در فایل `settings.py` با `AUTH_USER_MODEL = 'users_app.CustomUser'` اضافه کنید.