پیدایِش!


عَلی و مِلی و سَلیب و سَمیرا که با یکدیگر همکار هستند؛ به صرف شام به منزل عَلی دعوت‌ شده‌اند. ولی از آن‌جایی که حوصله‌‌شان سر رفته، به دنبال بازی هیجان‌انگیزی برای افزایش آدرنالین خون‌شان هستند!

بازی از این قرار است که مِلی ، سَلیب و سَمیرا ، هر کدام از بین اعداد ۱، ۲، ۳ و ۴، یک عدد انتخاب می‌کنند (اعداد انتخابی متمایز هستند)؛ سپس عَلی باید عددی که از بین این ۴ عدد، انتخاب نشده است را حدس بزند! اگر عددی که عَلی حدس زد درست نبود؛ باید برای مهمان‌هایش پیتزا بخرد، درغیر این‌صورت آن‌ها را با نان و پنیر و سبزی، سیر می‌کند! عَلی از شما می‌خواهد که به او کمک کنید تا بتواند برنده‌ی این بازی شود.

حال شما باید تابعی به نام find(num1, num2, num3) پیاده‌سازی کنید که با گرفتن سه عدد ورودی (num1 عدد انتخابی مِلی ، num2 عدد انتخابی سَلیب و num3 عدد انتخابی سَمیرا است.)، عددی که در بین این اعداد وجود ندارد را بازگرداند.

def find(num1, num2, num3):
    pass
Python

نمونه ۱🔗

>>> find(1, 2, 3)
4
Python

نمونه ۲🔗

>>> find(1, 4, 3)
2
Python

نکات🔗

  • می‌توانید فایل اولیه این سوال را از این لینک دریافت کنید.
  • شما باید تابع find موجود در فایل peydayesh.py را تکمیل و سپس این فایل را ارسال کنید.
  • تضمین می‌شود که اعداد ورودی، از بین اعداد ۱، ۲، ۳ و ۴ هستند.

مقایسه‌گر


عَلی و سَلیب که با یکدیگر برادر هستند، تصمیم گرفتند یک بازی هیجان‌انگیز دو نفره‌ای را انجام دهند تا شاید آدرنالین خون‌شان افزایش پیدا کند.

بازی از این قرار است که عَلی و سَلیب، هر کدام یک رشته انتخاب می‌کنند. سپس حرف اول رشته‌ای که حرف اولش از لحاظ لغت‌نامه‌ای کوچک‌تر است را حذف (اگر حرف اول دو رشته برابر بودند،‌ حرف اول هر دو رشته را حذف می‌کنند.) و هر دو رشته را معکوس می‌کنند. این کار را تا جایی انجام می‌دهند که یکی از دو رشته یا هر دو رشته، خالی شوند.

حال شما باید تابع compare(string1, string2) (که string1 رشته‌ی انتخابی عَلی و string2 رشته‌ی انتخابی سَلیب است.) را به گونه‌ای تکمیل کنید که:

  • اگر در نهایت یکی از دو رشته خالی شده بود، محتویات رشته‌ی دیگر را بازگرداند.
  • اگر در نهایت هر دو رشته خالی شده بودند؛ عبارت Both strings are empty! را بازگرداند.

توجه کنید که اگر یکی از رشته‌ها خالی شد؛ رشته‌ی دیگر، نباید مجدداً معکوس شود.

def compare(string1, string2):
    pass
Python

نمونه ۱🔗

>>> compare('ali', 'salib')
'las'
Python
توضیحات نمونه ۱

ابتدا حرف اول هر دو رشته بررسی می‌شود. چون a از s کوچک‌تر است، پس a از ali حذف شده و ali به li تبدیل می‌شود. سپس هر دو رشته معکوس (li به il و salib به bilas) می‌شوند.

حال از بین دو رشته‌ی جدید، چون b از i کوچک‌تر است، پس b از bilas حذف شده و bilas به ilas تبدیل می‌شود. سپس هر دو رشته معکوس (il به li و ilas به sali) می‌شوند.

حال مجددا از بین دو رشته‌ی جدید، چون l از s کوچک‌تر است، پس ‍l از li حذف شده و li به i تبدیل می‌شود. سپس هر دو رشته معکوس (i به i و sali به ilas ) می‌شوند.

در نهایت، از بین ۲ رشته‌ی جدید، چون i و i با یکدیگر برابر هستند، پس هر دو i حذف می‌شود و i به یک رشته‌ی خالی و ilas به las تبدیل می‌شوند و چون یکی از رشته‌ها، خالی شده‌اند، محتوای رشته‌ی دیگر (که برابر las است.) بازگردانده می‌شود.

نمونه ۲🔗

>>> compare('amin', 'nima')
'Both strings are empty!'
Python
توضیحات نمونه ۲

ابتدا حرف اول هر دو رشته بررسی می‌شود. چون a از n کوچک‌تر است، پس a از amin حذف شده و amin به min تبدیل می‌شود. سپس هر دو رشته معکوس (min به nim و nima به amin) می‌شوند.

حال از بین دو رشته‌ی جدید، چون a از n کوچک‌تر است، پس a از amin حذف شده و amin به min تبدیل می‌شود. سپس هر دو رشته معکوس (nim به min و min به nim) می‌شوند.

حال مجددا از بین دو رشته‌ی جدید، چون m از n کوچک‌تر است، پس ‍m از min حذف شده و min به in تبدیل می‌شود. سپس هر دو رشته معکوس (in به ni و nim به min ) می‌شوند.

دوباره از بین دو رشته‌ی جدید، چون m از n کوچک‌تر است، پس m از min حذف شده و min به in تبدیل می‌شود. سپس هر دو رشته معکوس (ni به in و in به ni) می‌شوند.

سپس از بین دو رشته‌ی جدید، چون i از n کوچک‌تر است، پس i از in حذف شده و in به n تبدیل می‌شود. سپس هر دو رشته معکوس (n به n و ni به in) می‌شوند.

مجددا از بین دو رشته‌ی جدید، چون i از n کوچک‌تر است، پس i از in حذف شده و in به n تبدیل می‌شود. سپس هر دو رشته معکوس (n به n و n به n) می‌شوند.

در نهایت، از بین ۲ رشته‌ی جدید، چون n و n با یکدیگر برابر هستند، پس هر دو n حذف می‌شود و n به یک رشته‌ی خالی و n دوم نیز به یک رشته‌ی خالی تبدیل می‌شوند و چون هر دو رشته‌، خالی شده‌اند، عبارت Both strings are empty! بازگردانده می‌شود.

نکات🔗

  • می‌توانید فایل اولیه این سوال را از این لینک دریافت کنید.
  • شما باید تابع compare موجود در فایل moghayeseGar.py را تکمیل و سپس این فایل را ارسال کنید.
  • تضمین می‌شود که رشته‌های ورودی، تنها از حروف کوچک انگلیسی تشکیل شده‌اند و شامل کاراکترهای Whitespace نیستند.

قَطار یا قاطِر؟


عَلی که با کمک شما توانست از مخمصه‌ی خرید ۳ پیتزا نجات پیدا کند؛ حال می‌خواهد بعنوان تشکر، پیتزایی که برای شما بفرستد. ولی از آن‌جایی که شما در شهر دیگری زندگی می‌کنید؛ دو راه برای فرستادن پیتزا به شما پیشنهاد می‌کند:

  1. ارسال پیتزا با قَطار
  2. ارسال پیتزا با قاطِر

از آن‌جایی که شما برای حل کردن این سوال و رفتن به سوال بعدی، عجله‌ی بسیاری دارید؛ گزینه‌ی اول را انتخاب می‌کنید. ولی امان از دل غافل! شما باید دو کلاس خواسته شده را پیاده‌سازی کنید تا شرکت راه‌آهن، این پیتزا را برای شما بفرستد.

کلاس Train از پیش پیاده‌سازی شده است ولی دو کلاس Trip و Passenger را شما باید پیاده‌سازی کنید.

کلاس قطار Train

متد سازنده __init__🔗

این متد در فایل اولیه مقداردهی شده است و نباید آن را دستکاری کنید. ویژگی‌هایی که در این متد به شیء اختصاص داده می‌شوند، عبارت‌اند از:

  • آخرین شهر بازدید شده last_visited_city : از نوع str می‌باشد.
  • ظرفیت بار weight_capacity: از نوع float می‌باشد.
  • وضعیت is_on_trip: از نوع bool است؛ در صورتی که True باشد، قطار در حال سفر است و اگر False باشد یعنی در ایستگاه راه آهن مستقر است.
کلاس سفر Trip

ویژگی‌های کلاس (Class Attributes)🔗

  • ویژگی all_cities: این ویژگی برابر با یک تاپل از همه شهرهایی است که امکان ساخت راه آهن در آن‌ها وجود دارد. این ویژگی در فایل اولیه مقداردهی شده است و نباید آن را دستکاری کنید.

متد سازنده __init__🔗

این متد در فایل اولیه مقداردهی شده است و نباید آن را دستکاری کنید. ویژگی‌هایی که در این متد به شیء اختصاص داده می‌شوند، عبارت‌اند از:

  • قطار train: از نوع Train می‌باشد.
  • شهر مبدا origin_city: از نوع str می‌باشد.
  • شهر مقصد destination_city: از نوع str می‌باشد.
  • مسافران passengers : از نوع list می‌باشد.

جزئیات🔗

متد origin_city_validation

این متد یک ورودی به نام origin_city می‌گیرد:

  • اگر این ورودی در لیست all_cities موجود نباشد، یک Exception با پیغام This input is not a verified city! پرتاب می‌کند.
  • اگر این ورودی با شهر مقصد برابر باشد، یک Exception با پیغام Origin and destination cities can't be the same! پرتاب می‌کند.
  • اگر این ورودی با آخرین شهر بازدید شده قطار برابر نباشد، یک Exception با پیغام The train of the trip is not available in the origin city! پرتاب می‌کند.

در نهایت اگر هیچ‎کدام از حالت‌های فوق صادق نبود باید origin_city برگردانده شود.

متد train_validation

این متد یک ورودی به نام train می‌گیرد:

  • اگر این ورودی از جنس قطار (کلاس Train) نباشد، یک Exception با پیغام This input is not a train! پرتاب می‌کند.
  • در صورتی که قطار در حال سفر باشد، یک Exception با پیغام This train is not available! پرتاب می‌کند.

در نهایت اگر هیچ‎کدام از حالت‌های فوق صادق نبود باید train برگردانده شود.

متد جادویی

داندرمتدی را برای این کلاس بازنویسی کنید که هنگام صدا زدن شیء سفر، «ظرفیتِ وزنِ بارِ باقی‌مانده از قطارِ سفر» برگردانده شود.

مثلا اگر یک سفر قطاری با ظرفیت وزن 1000 کیلوگرم و دو مسافر با وزن بار 60 و 70 کیلوگرم داشته باشد، هنگام صدا زدن این سفر، عدد 870 برگردانده می‌شود.

کلاس مسافر Passenger

متد سازنده __init__🔗

این متد در فایل اولیه مقداردهی شده است و نباید آن را دستکاری کنید. ویژگی‌هایی که در این متد به شیء اختصاص داده می‌شوند، عبارت‌اند از:

  • نام fullname: از نوع str می‌باشد.
  • وزن بار load_weight: از نوع float می‌باشد.

جزئیات🔗

متد attend_trip

این متد در ورودی یک سفر می‌گیرد و در صورتی که بار مسافر از «ظرفیتِ وزنِ بارِ باقی‌مانده از قطارِ سفر» کمتر یا مساوی باشد، مسافر را به لیست مسافران سفر اضافه می‌کند. در غیر این صورت یک Exception با پیغام Heavy load! پرتاب می‌کند.

متد cancel_trip

این متد در ورودی یک سفر می‌گیرد و در صورتی که مسافر در لیست مسافران آن سفر موجود باشد، مسافر را از لیست مسافران سفر حذف می‌کند. در غیر این صورت یک Exception با پیغام This passenger is not attended to this trip! پرتاب می‌کند.

متد جادویی

داندرمتدی را برای این کلاس بازنویسی کنید که اگر یک شیء مسافر print شود، به جای آدرس آن شیء در حافظه، نام مسافر چاپ شود.

نکات🔗

  • می‌توانید فایل اولیه این سوال را از این لینک دریافت کنید.
  • برای ارسال باید یک فایل پایتون ارسال کنید که در آن فقط کلاس‌های Passenger، Train و Trip به شکل گفته شده وجود داشته باشند.

کوئرا کانتست


برای سَلیب و اِبلیس سوال شده بود که چه کسی در کدنویسی مهارت بیشتری دارد. بنابراین آن‌ها تصمیم گرفتند تا پروژه ای شبیه به بخش مسابقات کوئرا پیاده‌سازی کنند. سپس در آن به مسابقه بپردازند تا مشخص شود که کدام‌یک، کُدزن قَهارتری است!

اما در پیاده‌سازی بخش‌هایی از پروژه به مشکل خورده‌اند و از شما می‌خواهند تا این بخش‌ها را تکمیل کنید تا هر چه سریع‌تر بتوانند به مسابقه‌ی خود بپردازند.

پروژه اولیه🔗

پروژه اولیه را از این لینک دانلود کنید. ساختار فایل‌های این پروژه به صورت زیر است.

ساختار درختی پروژه
quera_contest
├── accounts
│   ├── migrations
│   │   ├── 0001_initial.py
│   │   └── __init__.py
│   ├── __init__.py
│   ├── admin.py
│   ├── apps.py
│   ├── models.py
│   ├── permissions.py
│   ├── serializers.py
│   ├── tests.py
│   ├── urls.py
│   ├── validators.py
│   └── views.py
├── contests
│   ├── migrations
│   │   ├── 0001_initial.py
│   │   └── __init__.py
│   ├── __init__.py
│   ├── admin.py
│   ├── apps.py
│   ├── models.py
│   ├──  > query.py < 
│   ├── tests.py
│   └── views.py
├── fixtures
│   ├── sample_contest.json
│   └── sample_data.json
├── problems
│   ├── migrations
│   │   ├── 0001_initial.py
│   │   └── __init__.py
│   ├── __init__.py
│   ├── admin.py
│   ├── apps.py
│   ├──  > models.py < 
│   ├── tests.py
│   └── views.py
├── tests
│   ├── __init__.py
│   └── testsample.py
├── manage.py
└── requirements.txt
Plain text

مدل‌هایی که شما باید پیاده‌سازی کنید🔗

مدل Problem

هر شئ این مدل معادل یک مسئله (problem) در کوئراست.

این مدل دارای ویژٰگی‌های زیر است:

  • فیلد name: نشان‌دهنده نام مسئله می‌باشد و از نوع CharField است. باید حداکثر طولی برابر با 50 کاراکتر داشته باشد.
  • فیلد description: نشان‌دهنده توضیحات مسئله می‌باشد و از نوع CharField است. باید حداکثر طولی برابر با 1000 کاراکتر داشته باشد.
  • فیلد writer: نشان دهنده طراح و نویسنده مسئله می‌باشد و از طریق رابطه‌ی many-to-one به مدل User وصل می‌شود. توجه داشته باشید مدل User درون اپ accounts در پروژه اولیه پیاده‌سازی شده و شما نیازی به ایجاد هیچ تغییری در آن ندارید.
  • فیلد score: نشان‌دهنده نمره مسئله می‌باشد و از نوع PositiveIntegerField است. باید مقدار پیش‌فرضی برابر با 100 داشته باشد.
مدل Submission

هر شئ این مدل معادل یک پاسخ ارسال شده برای سیستم داوری کوئراست.

این مدل دارای ویژگی‌های زیر است:

  • فیلد submitted_time: نشان‌دهنده زمان پاسخ ارسالی می‌باشد و از نوع DateTimeField است.
  • فیلد participant: نشان دهنده فرستنده پاسخ ارسالی می‌باشد و از طریق رابطه‌ی many-to-one به مدل User وصل می‌شود و دارای آرگومان related_name="submissions" است. توجه داشته باشید مدل User درون اپ accounts در پروژه اولیه پیاده‌سازی شده و شما نیازی به ایجاد هیچ تغییری در آن ندارید.
  • فیلد problem: نشان دهنده مسئله پاسخ ارسالی می‌باشد و از طریق رابطه‌ی many-to-one به مدل Problem وصل می‌شود و دارای آرگومان related_name="submissions" است.
  • فیلد code: نشان‌دهنده آدرس ذخیره پاسخ ارسالی می‌باشد و از نوع URLField است. باید حداکثر طولی برابر با 200 کاراکتر داشته باشد.
  • فیلد score: نشان‌دهنده نمره مسئله می‌باشد و از نوع PositiveIntegerField است. باید مقدار پیش‌فرضی برابر با 0 داشته باشد.

کوئری‌هایی که شما باید پیاده‌سازی کنید🔗

اکیداً توصیه می‌شود پیش از حل این بخش مدل Contest موجود در اپ contests را مطالعه کنید و با این مدل به خوبی آشنا شوید.

کوئری list_problems

این کوئری id یک Contest را ورودی گرفته و تمامی مسائل آن Contest را در قالب یک کوئری‌ست بازمی‌گرداند.

مثالِ خروجی این تابع به صورت زیر است:

<QuerySet [<Problem: Problem object (1)>, <Problem: Problem object (2)>, <Problem: Problem object (3)>]>
Python
کوئری list_users

این کوئری id یک Contest را ورودی گرفته و تمامی کاربرانی که در آن Contest شرکت داشته‌اند را در قالب یک کوئری‌ست بازمی‌گرداند.

مثال خروجی این تابع به صورت زیر است:

<QuerySet [<User: SAliB>, <User: Saeid>, <User: Ali>]>
Python
کوئری list_submissions

این کوئری id یک Contest را ورودی گرفته و تمامی ارسال‌های آن Contest را به ترتیب زمان ارسال (submitted_time در مدل Submission) از آخرین به اولین ارسال در قالب یک کوئری‌ست بازمی‌گرداند.

مثال خروجی این تابع به صورت زیر است:

<QuerySet [<Submission: Submission object (12)>, <Submission: Submission object (6)>, <Submission: Submission object (16)>, <Submission: Submission object (5)>, <Submission: Submission object (11)>, <Submission: Submission object (15)>, <Submission: Submission object (14)>, <Submission: Submission object (4)>, <Submission: Submission object (10)>, <Submission: Submission object (9)>, <Submission: Submission object (3)>, <Submission: Submission object (8)>, <Submission: Submission object (2)>, <Submission: Submission object (13)>, <Submission: Submission object (1)>, <Submission: Submission object (7)>]>
Python
کوئری list_problem_submissions

این کوئری id یک Contest و id یک مسئله را ورودی گرفته و تمامی ارسال‌های آن مسئله در Contest را به ترتیب زمان ارسال (submitted_time در مدل Submission) از آخرین به اولین ارسال در قالب یک کوئری‌ست بازمی‌گرداند.

مثال خروجی این تابع به صورت زیر است:

<QuerySet [<Submission: Submission object (9)>, <Submission: Submission object (8)>, <Submission: Submission object (2)>, <Submission: Submission object (13)>, <Submission: Submission object (1)>, <Submission: Submission object (7)>]>
Python
کوئری list_user_submissions

این کوئری id یک ‍Contest و id یک کاربر را ورودی گرفته و تمامی ارسال‌های آن کاربر در Contest را به ترتیب زمان ارسال (submitted_time در مدل Submission) از آخرین ارسال به اولین ارسال در قالب یک کوئری‌ست بازمی‌گرداند.

مثال خروجی این تابع به صورت زیر است:

<QuerySet [<Submission: Submission object (6)>, <Submission: Submission object (5)>, <Submission: Submission object (4)>, <Submission: Submission object (3)>, <Submission: Submission object (2)>, <Submission: Submission object (1)>]>
Python
کوئری list_problem_user_submissions

این کوئری id یک Contest، id یک کاربر و id یک مسئله را ورودی گرفته و تمامی ارسال‌های آن کاربر در Contest برای آن مسئله را به ترتیب زمان ارسال (submitted_time در مدل Submission) از آخرین به اولین ارسال در قالب یک کوئری‌ست بازمی‌گرداند.

مثال خروجی این تابع به صورت زیر است:

<QuerySet [<Submission: Submission object (2)>, <Submission: Submission object (1)>]>
Python
کوئری list_users_solved_problem

این کوئری id یک Contest و id یک مسئله را ورودی گرفته و تمامی کاربرانی که آن مسئله را در Contest حل کرده‌اند به ترتیب زمان ارسال (submitted_time در مدل Submission) از آخرین به اولین ارسال در قالب یک کوئری‌ست بازمی‌گرداند.

توجه کنید تنها در صورتی یک پاسخ ارسالی درست است که نمره آن برابر با نمره اصلی مسئله باشد.

مثال خروجی این تابع به صورت زیر است:

<QuerySet [<User: SAliB>]>
Python
کوئری user_score

خروجی این کوئری از جنس عدد است. این کوئری id یک Contest و id یک کاربر را ورودی گرفته و مجموع امتیاز آن کاربر در Contest را خروجی می‌دهد.

توجه داشته باشید امتیاز هر کاربر در یک Contest برابر با جمع بیشترین امتیازات آن کاربر برای هر سوال است. مثلاً اگر یک کاربر برای سوال اول، امتیازات ۱۰۰، ۱۵۰ و ۲۰۰ را کسب کرده و برای سوال دوم، امتیازات ۵۰ و ۱۰۰ را کسب کرده باشد؛ امتیاز او برابر با بیشترین امتیاز کسب شده در سوال اول (۲۰۰) بعلاوه بیشترین امتیاز کسب شده در سوال دوم (۱۰۰) است (یعنی ۳۰۰).

مثال خروجی این تابع به صورت زیر است:

600
Python
کوئری list_final_submissions

این کوئری id یک Contest را ورودی گرفته و ارسال‌های نهایی آن Contest را به ترتیب زمان ارسال (submitted_time در مدل Submission) از آخرین به اولین ارسال، در قالب یک کوئری‌ست بازمی‌گرداند.

مثال خروجی این تابع به صورت زیر است:

<QuerySet [{'participant_id': 1, 'problem_id': 1, 'score__max': 100}, {'participant_id': 1, 'problem_id': 2, 'score__max': 200}, {'participant_id': 1, 'problem_id': 3, 'score__max': 300}, {'participant_id': 2, 'problem_id': 1, 'score__max': 100}, {'participant_id': 2, 'problem_id': 2, 'score__max': 120}, {'participant_id': 3, 'problem_id': 1, 'score__max': 100}, {'participant_id': 3, 'problem_id': 2, 'score__max': 200}, {'participant_id': 3, 'problem_id': 3, 'score__max': 240}]>
Python

زیرمسئله‌ها🔗

امتیاز بخش
۱۰ Problem Model
۱۰ Submission Model
۱۵ Query List Problem
۱۵ Query List Users
۱۵ Query List Submissions
۲۰ Query List Problem Submissions
۲۰ Query List User Submissions
۲۵ Query List Problem User Submissions
۳۰ Query List User Solved Problem
۴۰ Query User Score
۴۰ Query List Final Submissions

امکانات اضافه🔗

در صورتی که علاقمندید که خودتان به صورت دستی کوئری‌های خود را امتحان کنید و از درستی آن‌ها اطمینان حاصل کنید، یا اینکه به بررسی بیشتر از این تمرین بپردازید، برای راحتی بیشتر شما، فایل‌های مایگریشن‌ها ساخته شده‌اند و شما کافیست پس از پیاده‌سازی فایل‌ problems/models.py جهت ایجاد پایگاه‌داده، یک بار دستور migrate را اجرا کنید.

علاوه‌بر این، یک سری داده‌ی از پیش آماده شده، فراهم شده که بعد از اجرای دستور migrate، می‌توانید آن‌ها را وارد پایگاه‌داده‌ی پروژه‌ی خود کنید. به این منظور، دستور زیر را اجرا کنید. می‌توانید از این داده‌ها به جهت تست کردن کوئری‌های خود استفاده کنید.

۱. ایجاد پایگاه‌داده

python manage.py migrate
Bash

۲. وارد کردن داده‌های از پیش آماده شده (fixture)

python manage.py loaddata fixtures/sample_data.json
python manage.py loaddata fixtures/sample_contest.json
Bash

در صورتی که علاقمند به تست نیستید، نیازی به ایجاد پایگاه‌داده و وارد کردن داده‌های آزمایشی نیست، و تنها کافیست که در فایل query.py کوئری‌های خود را بنویسید و از کوئرا جهت امتحان کردن درستی کوئری‌هایتان استفاده کنید.

نکات🔗

  • شما تنها مجوز ایجاد تغییرات در فایل‌های زیر را دارید و تمامی تغییرات دیگر شما در فایل‌های پروژه نادیده گرفته خواهند شد.
    • فایل contests/query.py
    • فایل problems/models.py
  • فراموش نکنید که می‌توانید با مطالعه‌ی testsample.py با روش تست کردن مدل‌ها آشنا شوید.

آن‌چه باید آپلود کنید🔗

این سوال از نوع سوالات چندفایلی است. برای حل سوال می‌توانید پروژه را در قالب یک فایل ZIP که شامل کلیه فایل‌های موجود در پروژه است، ارسال کنید.

خطِ فرمان


فرهاد که به تازگی در کوئرا استخدام شده، تصمیم گرفته برای کمک به بخش Careers کوئرا تعدادی دستور طراحی کند. او که تسلط کمی به خط فرمان دارد و فقط توانسته مدل شرکت را تکمیل کند و به علت هم‌زمان شدن امتحاناتش با زمان تحویل، به کمک شما برای تکمیل دستورات نیاز دارد.

پروژه اولیه🔗

پروژه اولیه را از این لینک دریافت کنید. ساختار فایل‌های این پروژه به صورت زیر است.

ساختار درختی پروژه
CLI
├── career
│   ├── admin.py
│   ├── apps.py
│   ├── __init__.py
│   ├── management
│   │   ├── commands
│   │   │   ├──  > addCompany.py < 
│   │   │   ├──  > collectCompany.py < 
│   │   │   ├──  > editCompany.py < 
│   │   │   ├── __init__.py
│   │   │   └──  > rmCompany.py < 
│   │   └── __init__.py
│   ├── migrations
│   │   ├── 0001_initial.py
│   │   └── __init__.py
│   ├── models.py
│   ├── tests.py
│   ├── utils.py
│   └── views.py
├── config
│   ├── asgi.py
│   ├── __init__.py
│   ├── settings.py
│   ├── urls.py
│   └── wsgi.py
├── manage.py
├── requirements.txt
└── tests
    ├── __init__.py
    └── testssample.py
Plain text

برای کمک به فرهاد، دستورات خواسته شده را در فایل‌های خواسته شده پیاده‌سازی کنید.

دستور addCompany

می‌خواهیم درون فایل ‍addCompany.py، دستوری برای جنگو بنویسیم که با اجرای آن، به ترتیب مقادیر name, email, phone, description‍ (از چپ به راست) را از کاربر دریافت کند و با این مقادیر، یک نمونه از کلاس Company بسازد.

  • برای فیلدهايی که دارای ویژگی null=False هستند، کاربر حتما باید مقداری را وارد کند. در صورتی که کاربر بدون وارد کردن مقداری Enter زد باید خطای Error: This field cannot be blank. نمایش داده شود و برای فیلد‌هایی که دارای ویژگی null=True هستند، با زدن Enter به مرحله بعد رفته و مقدار آن فیلد None شود.

اعتبارسنجی مخصوص هر فیلد:🔗

name

فیلد name باید حداکثر ۵۰ کاراکتر باشد؛ در غیر این‌صورت، عبارت

Error: Ensure this value has at most 50 characters (it has COUNT).

نمایش داده شود که به جای کلمه‌ی COUNT، تعداد کاراکترهای عبارت شما قرار می‌گیرد.

همچنین این فیلد باید یکتا باشد؛ در غیر این‌صورت، عبارت

Error: That name is already taken.

نمایش داده شود.

email

آدرس وارد شده باید یک ایمیل معتبر باشد، در غیر این‌صورت باید عبارت

Error: Enter a valid email address.

نمایش داده شود.

phone

یک شماره موبایل در صورتی معتبر است که یکی از حالت‌های زیر را دارا باشد:

  • شامل ۱۱ رقم باشد و با 09 آغاز شود.
  • شامل ۱۳ رقم باشد و با ‍98+ آغاز شود.
  • شامل ۱۴ رقم باشد و با 0098 آغاز شود.

در غیر این صورت باید عبارت

Error: Phone number format is not valid.

نمایش داده شود.

description

این فیلد محدودیتی ندارد.

نکات مهم🔗

  • در صورت وارد شدن مقدار غیر قابل قبول برای هر فیلد، خط فرمان همچنان منتظر وارد شدن مقدار قابل قبول برای همان فیلد می‌ماند.
  • برای چاپ خطاها، حتماً از دستور self.stderr.write(error_msg) استفاده کنید.

نمونه🔗

توضیح تصویر

دستور editCompany

می‌خواهیم درون فایل ‍editCompany.py، دستوری برای جنگو بنویسیم که یک positional arguments به عنوان نام شرکت و همچنین چهار optional arguments (--description ,--phone ,--email ,--name) دریافت و فیلدهای مربوط به آن شرکت را بروز کند.

  • برای فیلدهايی که دارای ویژگی null=False هستند، اگر آرگومان آن‌ها برابر '' بود؛ استثنای CommandError با پیام ‍ Field cannot be blank. رخ دهد (به جای کلمه‌ی Field، نام فیلد با حرف ابتدای بزرگ قرار می‌گیرد.) اما برای فیلدهایی که دارای ویژگی null=True هستند، می‌تواند برابر '' باشد؛ ولی مقدار فیلد تغییری نمی‌کند.
  • در هر مرحله از اعتبار سنجی که در ادامه اشاره می‌شود، اگر مقادیر، معتبر نبودند باید استثنای CommandError با پیام خطای مربوط رخ دهد.
  • موارد، به ترتیب نوشته‌شده باید بررسی شوند.
positional arguments

در صورتی که شرکتی با این نام وجود نداشت؛ باید یک Exception با پیام

Company matching query does not exist.

رخ دهد.

optional arguments
name

آرگومان name باید حداکثر ۵۰ کاراکتر باشد؛ در غیر این‌صورت، یک Exception با پیام

Error: Ensure this value has at most 50 characters (it has NUM).

رخ دهد که به جای NUM تعداد کاراکترهای عبارت شما قرار می‌گیرد.

همچنین این فیلد باید یکتا باشد، در غیر این‌صورت، باید یک Exception با پیام

Error: That name is already taken.

رخ دهد.

email

آدرس وارد شده باید یک ایمیل معتبر باشد در غیر این صورت باید یک Exception با پیام

Error: Enter a valid email address.

رخ دهد.

phone

یک شماره موبایل در صورتی معتبر است که یکی از حالت‌های زیر را دارا باشد:

  • شامل ۱۱ رقم باشد و با 09 آغاز شود.
  • شامل ۱۳ رقم باشد و با ‍98+ آغاز شود.
  • شامل ۱۴ رقم باشد و با 0098 آغاز شود.

در غیر این صورت باید یک Exception با پیام

Error: Phone number format is not valid.

رخ دهد.

description

این آرگومان محدودیتی ندارد.

نمونه🔗

توضیح تصویر

دستور rmCompany

می‌خواهیم درون فایل rmCompany.py، برای جنگو بنویسیم که نام تعدادی (صفر یا بیشتر) شرکت را دریافت کند و درصورتی که شرکتی با آن نام‌ها وجود داشت آن را از پایگاه داده حذف کند.

positional argument

در صورتی که شرکتی با این نام‌ها وجود نداشت، به ازای هر نام غیرمعتبر باید عبارت

COMPANY matching query does not exist.

نمایش داده شود، که به جای COMPANY نام شرکت وارد شده قرار می‌گیرد.

optional argument

در صورت وجود --all در دستور، بدون توجه به نام شرکت‌های وارد شده (در صورت وجود)، تمام شرکت‌ها حذف می‌شوند.

نکات مهم🔗

  • برای چاپ خطا، حتماً از دستور self.stderr.write(error_msg) استفاده کنید.

نمونه🔗

توضیح تصویر

دستور collectCompany

می‌خواهیم درون فایل collectCompany.py، دستوری برای جنگو بنویسیم که با اجرای آن، یک فایل CSV به نام company.csv شامل اطلاعات تماس شرکت‌ها، در ریشه‌ی پروژه ایجاد شود.

  • ستون‌های فایل CSV به ترتیب (از چپ به راست) نام، ایمیل و تلفن شرکت است.

نکات🔗

  • توجه کنید که در قسمت‌هایی که گفته شده عبارت مورد نظر نمایش داده شود، باید از دستور self.stderr.write(error_msg) و در قسمت‌هایی که گفته شده یک Exception رخ دهد، از دستور raise استفاده کنید.
  • شما تنها مجوز ایجاد تغییرات در فایل‌های زیر را دارید و تمامی تغییرات دیگر شما در فایل‌های پروژه نادیده گرفته خواهند شد.
    • فایل career/management/commands/addCompany.py
    • فایل career/management/commands/collectCompany.py
    • فایل career/management/commands/editCompany.py
    • فایل career/management/commands/rmCompany.py

آن‌چه باید آپلود کنید🔗

این سوال از نوع سوالات چندفایلی است. برای حل سوال می‌توانید پروژه را در قالب یک فایل ZIP که شامل کلیه فایل‌های موجود در پروژه است، ارسال کنید.