همه چی از uber شروع شد. ایدهی خوبی که رانندگان را به مسافران وصل میکرد و هر کسی هر جایی بود به سرعت میتوانست برای خودش تاکسی درخواست دهد. مدتی نگذشت که برنامهنویسهای داخل کشور عزیزمان هم از این سرویس ایده گرفتند و شروع به پیادهسازی مشابه آن در ایران کردند. در حال حاضر چندین سرویس درخواست آنلاین تاکسی وجود دارد که در تهران و چند شهر دیگر مشغول سرویسدهی به مسافرین هستند و روز به روز هم گسترش بیشتری مییابند و اشتغالزایی زیادی را نیز به وجود آوردهاند. حالا با توجه به بازار داغ این سرویس ما نیز میخواهیم یک سرویس مشابه ایجاد کنیم. اسمش را هم `cabin` گذاشتهایم.
## پروژه اولیه
پروژه اولیه را از [این لینک](/problemset/assignments/4367/download_problem_initial_project/16401/) دانلود کنید. ساختار این پروژه به شرح زیر است:
```
cabin
├─── manage.py
├─── requirements.txt
│
├─── cabin
│ ├─── admin.py
│ ├─── apps.py
│ ├─── models.py
│ ├─── <mark class="yellow" title="شما تنها مجاز به تغییر این فایل هستید."> > queries.py < </mark>
│ ├─── tests.py
│ ├─── urls.py
│ ├─── views.py
│ ├─── __init__.py
│ │
│ ├─── fixtures
│ │ └─── sample_test_fixture.json
│ │
│ └─── migrations
│ ├── 0001_initial.py
│ └─── __init__.py
│
├───challenge
│ ├─── settings.py
│ ├─── urls.py
│ ├─── wsgi.py
│ └─── __init__.py
│
└───tests
├─── testsample.py
└─── __init__.py
```
همانطور که در فایلها میبینید یک app به نام cabin وجود دارد. در فایل `models.py` هشت مدل به شرح زیر وجود دارند:
<details class="blue">
<summary> **مدل** `Account` (**حساب کاربری**) </summary>
حساب کاربریای که به یک مدل دیگر اعم از راننده یا مسافر یا مدیر سیستم وصل است و شامل فیلد های زیر است:
+ `first_name`: نام شخص
+ `last_name`: نام خانوادگی شخص
+ `email`: ایمیل شخص
+ `phone`: شماره تلفن شخص
+ `password`: پسورد شخص
</details>
<details class="blue">
<summary> **مدل** `Admin` (**مدیر**) </summary>
مدیر سیستم که دسترسیهای خاصی به سیستم دارد و شامل فیلد زیر است:
+ `account`: اکانت ادمین که اطلاعات او را نگه میدارد.
</details>
<details class="blue">
<summary> **مدل** `Rider` (**مسافر**) </summary>
شامل فیلدهای زیر است:
+ `account`: اکانت مسافر که اطلاعات او را نگه میدارد.
+ `x`: طول جغرافیایی موقعیت مسافر
+ `y`: عرض جغرافیایی موقعیت مسافر
+ `rating`: امتیاز مسافر
</details>
<details class="blue">
<summary> **مدل** `Driver` (**راننده**) </summary>
شامل فیلدهای زیر است:
+ `account`: اکانت راننده که اطلاعات او را نگه میدارد.
+ `x`: طول جغرافیایی موقعیت راننده
+ `y`: عرض جغرافیایی موقعیت راننده
+ `rating`: امتیاز راننده
+ `active`: آماده به کار بودن یا نبودن راننده را نشان میدهد.
</details>
<details class="blue">
<summary> **مدل** `Car` (**خودرو**) </summary>
شامل فیلدهای زیر است:
+ `owner`: صاحب خودرو که یک راننده (از جنس مدل `Driver`) است.
+ `car_type`: نوع کلاس خودرو
+ `model`: سال تولید خودرو
+ `color`: رنگ خودرو
</details>
<details class="blue">
<summary> **مدل** `RideRequest` (**درخواست سفر**) </summary>
شامل فیلدهای زیر است:
+ `rider`: مسافر درخواستدهنده
+ `x`: طول جغرافیایی نقطه درخواست
+ `y`: عرض جغرافیایی نقطه درخواست
+ `car_type`: کلاس خودرو درخواستشده
</details>
<details class="blue">
<summary> **مدل** `Ride` (**سفر**) </summary>
شامل فیلدهای زیر است:
+ `pickup_time:` (زمان شروع سفر(سوار کردن مسافر
+ `dropoff_time`: زمان پایان سفر
+ *دو زمان بالا از نوع عدد صحیح و نشاندهنده تعداد ثانیه های گذشته از زمان تاسیس شرکت می باشند.*
+ `request`: درخواست سفری که این سفر به آن مربوط میشود
+ `car`: خودرویی که این سفر با آن انجام شده است
+ `rider_rating`: امتیازی که راننده به مسافر داده است
+ `driver_rating`: امتیازی که مسافر به راننده داده است
</details>
<details class="blue">
<summary> **مدل** `Payment` (**پرداخت**) </summary>
شامل فیلدهای زیر است:
+ `ride`: سفری که پرداخت برای آن انجام شده است.
+ `amount`: مبلغ پرداختشده برحسب تومان
+ `status`: وضعیت پرداخت
</details>
حال از شما میخواهیم پرسوجو (query) های زیر را روی مدلهای بالا بنویسید.
**حتما قبل شروع نوشتن کد، تذکرات انتهای سوال را بخوانید!**
<details class="green">
<summary> **۱. ورودی کل شرکت کابین (پولی که از طریق پرداخت وارد شرکت میشود)**</summary>
+ در اینجا status تاثیری ندارد و نتیجه را میتوانید به صورت dict برگردانید.
```json
{'income': value }
```
</details>
<details class="green">
<summary> **۲. کل مبلغ پرداختشده توسط مشتری با** `id` **برابر با** `x` </summary>
```json
{'payment_sum': value }
```
</details>
<details class="green">
<summary> **۳. تعداد رانندههایی که حداقل یک ماشین کلاس** `A` **دارند.** </summary>
+ در این سوال باید `.count()` از QuerySet مربوطه را بازگرانید که نتیجه یک عدد خواهد بود.
</details>
<details class="green">
<summary> **۴. لیست درخواستهای سفرِ در انتظار (یعنی درخواستهایی که به هیچ سفری وصل نباشد)** </summary>
+ ترتیب این لیست اهمیت ندارد.
</details>
<details class="green">
<summary> **۵. لیست مسافرانی که مجموع مبلغ سفرهایشان بیشتر یا مساوی با** `t` **تومان است.** </summary>
+ ترتیب این لیست اهمیت ندارد.
</details>
<details class="green">
<summary> **۶. اکانتِ رانندهای که بیشترین تعداد ماشین را دارد. اگر تعداد ماشینها یکسان بود، رانندهای را بدهید که نام خانوادگیاش از نظر الفبایی کوچکتر است.**</summary>
+ در این سوال باید یک شیء از نوع Account بازگرانید که نتیجه مانند زیر خواهد بود:
```json
<Account: Account object>
```
</details>
<details class="green">
<summary> **۷. لیست همه مسافرانی که حداقل یک سفر با ماشین کلاس** `A` **داشتهاند به همراه یک ستون اضافه با نام** `n` **که تعداد سفرهایی که هر مسافر با ماشین کلاس** `A` **داشته است را نشان میدهد.** </summary>
+ ترتیب این لیست اهمیت ندارد.
</details>
<details class="green">
<summary> **۸. لیست ایمیل رانندگانی که حداقل یک ماشین با مدل** `x` **(توجه کنید که مدل با نوع متفاوت است!) یا به بالا دارند.**</summary>
+ ترتیب این لیست اهمیت ندارد.
+ خروجی نمونه:
```
<QuerySet [{'account__email': 'linda180@gmail.com'}, {'account__email': 'jacqueline859@gmail.com'}, {'account__email': 'benjamin780@gmail.com'},.....]>
```
</details>
<details class="green">
<summary> **۹. لیست همه رانندهها و یک ستون اضافه شده به آن به نام** `n` **که نشاندهنده تعداد سفرهای هر راننده است.**</summary>
+ ترتیب این لیست اهمیت ندارد.
</details>
<details class="green">
<summary> **۱۰. لیست اسمهای کوچک همه رانندهها و تعداد سفرهایی** (`n`) **که راننده با آن آسم انجام داده است.** </summary>
+ بعضی رانندهها اسمهای یکسانی دارند.
+ برای مثال اگر دو راننده مختلف با اسم jack وجود داشته باشند که هر کدام ۵ سفر انجام دادهباشند، در لیست زیر فقط یک بار اسم jack با ۱۰ سفر میآید.
+ ترتیب این لیست اهمیت ندارد.
+ خروجی نمونه:
```
<QuerySet [{'n': 41, 'account__first_name': 'aaron'}, {'n': 44, 'account__first_name': 'adam'}, {'n': 19, 'account__first_name': 'alan'},.....]>
```
</details>
<details class="green">
<summary> **۱۱. لیست رانندگانی که حداقل یک ماشین با رنگ** `c` **(مثلا White) که مدلِ همان ماشین،** `n` **(مثلا ۹۰) یا به بالا باشد (توجه کنید که مدل با نوع متفاوت است!)، دارند.**</summary>
+ در این لیست نباید رانندهی تکراری وجود داشته باشد.
+ ترتیب این لیست اهمیت ندارد.
</details>
<details class="green">
<summary> **۱۲. لیست رانندگانی که حداقل یک ماشین با رنگ** `c` **و یک ماشین مدل** `n` **یا به بالا (توجه کنید که مدل با نوع متفاوت است!) دارند.**</summary>
+ در این لیست نباید رانندهی تکراری وجود داشته باشد.
+ لزوما این دو ماشین یکسان نیست. ولی برای رنگ و مدل باید حداقل یک ماشین با شرایط گفتهشده برای هر کدام وجود داشته باشد.
+ ترتیب این لیست اهمیت ندارد.
</details>
<details class="green">
<summary> **۱۳. مجموع طول سفرهایی که در آن اسم راننده** `n` **(مثلا jack) و اسم مسافر** `m` **بوده است.** </summary>
```json
{'sum_duration': value }
```
</details>
## زیرمسئلهها
| امتیاز | بخش |
|:------------------:|:------------------:|
| ۵ | query_1 |
| ۵ | query_2 |
| ۵ | query_3 |
| ۵ | query_4 |
| ۵ | query_5 |
| ۵ | query_6 |
| ۱۰ | query_7 |
| ۱۰ | query_8 |
| ۱۰ | query_9 |
| ۱۰ | query_10 |
| ۱۰ | query_11 |
| ۱۰ | query_12 |
| ۱۰ | query_13 |
## امکانات اضافه
در صورتی که علاقمندید که خودتان به صورت دستی کوئریهای خود را امتحان کنید و از درستی آنها اطمینان حاصل کنید، یا اینکه به بررسی بیشتر از این تمرین بپردازید، برای راحتی بیشتر شما، فایلهای مایگریشنها ساخته شدهاند و شما کافیست جهت ایجاد پایگاهداده، یک بار دستور `migrate` را اجرا کنید.
علاوهبر این، یک سری دادهی از پیش آماده شده، فراهم شده که بعد از اجرای دستور `migrate`، میتوانید آنها را وارد پایگاهدادهی پروژهی خود کنید. به این منظور، دستور زیر را اجرا کنید. میتوانید از این دادهها به جهت تست کردن کوئریهای خود استفاده کنید.
**۱. ایجاد پایگاهداده**
```shell terminal terminal
python manage.py migrate
```
**۲. وارد کردن دادههای از پیش آماده شده (fixture)**
```shell terminal terminal
python manage.py loaddata cabin/fixtures/sample_test_fixture.json
```
در صورتی که علاقمند به تست نیستید، نیازی به ایجاد پایگاهداده و وارد کردن دادههای آزمایشی نیست، و تنها کافیست که در فایل `queries.py` کوئریهای خود را بنویسید و از کوئرا جهت امتحان کردن درستی کوئریهایتان استفاده کنید.
## تست نمونه
در فایلهای اولیهای که دانلود کردید یکسری داده اولیه به عنوان نمونه قرار داده شده است. همچنین ۳ تست نمونه برای ۳ پرسوجو اول بر اساس دادههای اولیه قرار داده شده است که میتوانید قبل از فرستادن سوال در سایت، این تستها را ببینید تا با نحوه داوری ما آشنا شوید و از پاسخ خود اطمینان حاصل نمایید.
تستها را میتوانید با دستور زیر اجرا کنید:
```shell terminal terminal
python manage.py test
```
## نکات
+ یک فایل به نام `queries.py` وجود دارد که برای هر سوال یک تابع در نظر گرفته شده است. شما باید کدهای خود را در این فایل بنویسید و *QuerySet* مربوطه را بازگردانید.
+ برای نمونه تابع `query_0` در پاسخ به پرس و جویِ «لیست همهی رانندگانی که رتبهی آنها بیشتر از x است.» کامل شده است که شما نیز باید مشابه همین تابع بقیه توابع را کامل کنید.
```python queries.py
def query_0(x):
q = Driver.objects.filter(rating__gt=x)
return q
```
+ در سوالاتی که در صورت سوال مقداری به صورت متغیر ذکر شده است (مانند x در مثال بالا)، متغیر مورد نظر در آرگومانهای ورودی تابع درنظر گرفته شده است. شما خود نباید آرگومانهای ورودی تابع را تغییر دهید.
+ در تمام سوالات به جز سوالاتی که خروجی نمونه برای آنها مشخص شده است، همانطور که ذکر شد، خروجی شما یک شئ از نوع `QuerySet` با المانهایی از جنس گفتهشده در اول سوال باید باشد. یعنی در واقع خود query را return کنید.
+ برای مثال اگر سوال گفته باشد «لیست ماشین هایی که....» خروجی شما به شکل زیر باید باشد:
```
<QuerySet [<Car: Car object>, <Car: Car object>,.....]>
```
+ در سوالات دیگر نیز که خروجی مشخص شده است، باز نتیجه یک `QuerySet` است ولی شامل همه فیلدهای مدل مورد نظر نمیشود و فقط فیلدهای خواستهشده با نام خواستهشده باید در آن قرار داشته باشد.
+ شما تنها مجوز ایجاد تغییرات در فایل `cabin/queries.py` را دارید و **تمامی تغییرات دیگر شما** در فایلهای پروژه **نادیده گرفته خواهند شد.**
+ فراموش نکنید که میتوانید با مطالعهی `testsample.py` با روش تست کردن کوئریها آشنا شوید.
## نحوه ارسال
یک فایل _ZIP_ حاوی همهی فایلهای پروژه، آپلود کنید. نام فایل _ZIP_ اهمیتی ندارد.