همه چی از uber شروع شد. ایدهی خوبی که رانندگان را به مسافران وصل میکرد و هر کسی هر جایی بود به سرعت میتوانست برای خودش تاکسی درخواست دهد. مدتی نگذشت که برنامهنویسهای داخل کشور عزیزمان هم از این سرویس ایده گرفتند و شروع به پیادهسازی مشابه آن در ایران کردند. در حال حاضر چندین سرویس درخواست آنلاین تاکسی وجود دارد که در تهران و چند شهر دیگر مشغول سرویسدهی به مسافرین هستند و روز به روز هم گسترش بیشتری مییابند و اشتغالزایی زیادی را نیز به وجود آوردهاند. حالا با توجه به بازار داغ این سرویس ما نیز میخواهیم یک سرویس مشابه ایجاد کنیم. اسمش را هم `cabin` گذاشتهایم.
## پروژه اولیه
پروژه اولیه را از [این لینک](/problemset/assignments/4367/download_problem_initial_project/21214/) دانلود کنید. ساختار این پروژه به شرح زیر است:
```
cabin 2
├─── manage.py
├─── requirements.txt
│
├─── cabin
│ ├─── admin.py
│ ├─── apps.py
│ ├─── models.py
│ ├─── <mark class="yellow" title="شما تنها مجاز به تغییر این فایل هستید."> > queries.py < </mark>
│ ├─── 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>**۱. کل مبلغ دریافتی توسط رانندهای با شناسهای برابر با x** </summary>
+ در این سوال status اهمیتی ندارد و نتیجه را میتوانید به شکل یک *dict* برگردانید.
```json
{'payment_sum': value }
```
</details>
<details class="green">
<summary> **۲. لیست همه سفرهای یک مسافر با شناسه x** </summary>
+ ترتیب این لیست اهمیت ندارد.
</details>
<details class="green">
<summary> **۳. تعداد سفرهایی که طول آنها (از نظر زمانی) بیشتر از t بوده است.** </summary>
+ نتیجه این پرسوجو یک عدد است.
</details>
<details class="green">
<summary> **۴. لیست همه رانندههایی که در فاصله کمتر یا مساوی از r حول نقطه (x,y) قرار دارند و فعال (آماده به کار) نیز هستند.** </summary>
+ ترتیب این لیست اهمیت ندارد.
</details>
<details class="green">
<summary> **۵. لیست رانندگانی که یک ماشین کلاس A یا یک ماشین با رنگ c دارند و حداقل n سفر انجام دادهاند.** </summary>
+ ترتیب این لیست اهمیت ندارد.
</details>
<details class="green">
<summary> **۶. لیست مسافرانی که x سفر یا بیشتر داشتهاند و در مجموع بیشتر از t تومان پرداخت کردهاند.** </summary>
+ ترتیب این لیست اهمیت ندارد.
</details>
<details class="green">
<summary> **۷. لیست رانندگانی که حداقل یک سفر داشتهاند که در آن سفر اسم راننده با اسم مسافر یکسان بوده است.** </summary>
+ ترتیب این لیست اهمیت ندارد.
+ در این لیست نباید رانندهی تکراری وجود داشته باشد.
</details>
<details class="green">
<summary> **۸. لیست همه رانندهها و یک ستون دیگر با نام `n` که نشاندهندهی تعداد سفرهایی است که در آنها نام خانوادگی راننده با نام خانوادگی مسافر یکسان بوده است.** </summary>
+ ترتیب این لیست اهمیت ندارد.
</details>
<details class="green">
<summary> **۹. لیست همه رانندهها به همراه یک ستون دیگر به نام `n` که تعداد سفرهاییست که در آن سفرها ماشین، مدل x یا به بالا (توجه کنید که مدل با نوع متفاوت است!) بوده است **و** طول سفر بیشتر از t ثانیه بوده است.** </summary>
خروجی نمونه:
```
<QuerySet [{'id': 1, 'n': 8}, {'id': 2, 'n': 1},....]>
```
+ ترتیب این لیست اهمیت ندارد.
+ طول این لیست به تعداد همه رانندهها است که در هر عنصر آن id راننده و n (با تعریف بالا) قرار دارد.
</details>
<details class="green">
<summary> **۱۰. لیست همه ماشینها و یک ستون اضافه شده به آن به نام `extra`** </summary>
مقدار `extra` از نوع عدد صحیح است و با توجه به نوع ماشین (`car_type`) به شرح زیر تعریف میشود:
+ اگر نوع ماشین `A` بود تعداد سفرهای انجامشده با آن ماشین در ستون `extra` قرار میگیرد.
+ اگر نوع ماشین `B` بود مجموع طول سفرهای انجامشده با آن ماشین در ستون `extra` قرار میگیرد.
+ اگر نوع ماشین `C` بود مجموع مبلغ سفرهای انجامشده با آن ماشین در ستون `extra` قرار میگیرد.
</details>
## زیرمسئلهها
| امتیاز | بخش |
|:------------------:|:------------------:|
| ۱۰ | query_1 |
| ۱۰ | query_2 |
| ۱۰ | query_3 |
| ۱۰ | query_4 |
| ۱۰ | query_5 |
| ۱۰ | query_6 |
| ۱۰ | query_7 |
| ۱۰ | query_8 |
| ۱۰ | query_9 |
| ۱۰ | query_10 |
## امکانات اضافه
در صورتی که علاقمندید که خودتان به صورت دستی کوئریهای خود را امتحان کنید و از درستی آنها اطمینان حاصل کنید، یا اینکه به بررسی بیشتر از این تمرین بپردازید، برای راحتی بیشتر شما، فایلهای مایگریشنها ساخته شدهاند و شما کافیست جهت ایجاد پایگاهداده، یک بار دستور `migrate` را اجرا کنید.
علاوهبر این، یک سری دادهی از پیش آماده شده، فراهم شده که بعد از اجرای دستور `migrate`، میتوانید آنها را وارد پایگاهدادهی پروژهی خود کنید. به این منظور، دستور زیر را اجرا کنید. میتوانید از این دادهها به جهت تست کردن کوئریهای خود استفاده کنید.
**۱. ایجاد پایگاهداده**
```shell terminal terminal
python manage.py migrate
```
**۲. وارد کردن دادههای از پیش آماده شده (fixture)**
```shell terminal terminal
python manage.py loaddata cabin/fixtures/sample_test_fixture.json
python manage.py loaddata cabin/fixtures/test_fixtures.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_ اهمیتی ندارد.