تغییرات اخیر

در اینجا اطلاعیه‌ها، نسخه‌ها و تغییرات جدید لیارا فهرست می‌شوند.

    نحوه ایجاد دستورات مدیریتی جدید در Django


    ۲۴ تیر ۱۳۹۹
    نحوه ایجاد دستورات مدیریتی جدید در Django

    جنگو، ابزارها و دستورات خط فرمان گوناگون و زیادی را فراهم می‌کند که می‌توان آن‌ها را توسط django-admin.py و یا manage.py در هر پروژه، اجرا کرد. اما یک نکته مثبت این است که می‌توانید دستورات خود را نیز به آن‌ها اضافه کنید. این دستورات مدیریتی می‌تواند برای تعامل با برنامه‌تان از طریق خط فرمان، بسیار مناسب باشد، همچنین می‌تواند به عنوان واسطی برای اجرای corn jobها نیز ظاهر شود. در این مقاله آموزشی نحوه ایجاد دستورات خودتان در جنگو را خواهید آموخت.

    مقدمه

    قبل از اینکه شروع کنیم، بیایید لحظاتی را صرف آشنایی با رابط خط فرمان جنگو کنیم. به احتمال زیاد با دستوراتی نظیر startproject، runserver و یا collectstatic آشنا هستید. برای مشاهده تمام دستوراتی که می‌توانید در یک پروژه جنگو ایجاد کنید، از دستور زیر در پروژه‌تان (در واقع جایی که فایل manage.py قرار دارد) استفاده کنید:

    python manage.py help

    خروجی:

    Type 'manage.py help <subcommand>' for help on a specific subcommand.
    
    Available subcommands:
    
    [auth]
        changepassword
        createsuperuser
    
    [contenttypes]
        remove_stale_contenttypes
    
    [django]
        check
        compilemessages
        createcachetable
        dbshell
        diffsettings
        dumpdata
        flush
        inspectdb
        loaddata
        makemessages
        makemigrations
        migrate
        sendtestemail
        shell
        showmigrations
        sqlflush
        sqlmigrate
        sqlsequencereset
        squashmigrations
        startapp
        startproject
        test
        testserver
    
    [sessions]
        clearsessions
    
    [staticfiles]
        collectstatic
        findstatic
        runserver

    می‌توانیم دستورات خود را ایجاد کنیم و آن‌ها را به این لیست اضافه کنیم. این کار را با ایجاد پوشه management/commands در پوشه برنامه، همانند مثال زیر انجام می‌دهیم:

    mysite/                                   <-- project directory
     |-- core/                                <-- app directory
     |    |-- management/
     |    |    +-- commands/
     |    |         +-- my_custom_command.py  <-- module where command is going to live
     |    |-- migrations/
     |    |    +-- __init__.py
     |    |-- __init__.py
     |    |-- admin.py
     |    |-- apps.py
     |    |-- models.py
     |    |-- tests.py
     |    +-- views.py
     |-- mysite/
     |    |-- __init__.py
     |    |-- settings.py
     |    |-- urls.py
     |    |-- wsgi.py
     +-- manage.py

    نام این فایل برای ایجاد دستور استفاده خواهد شد. برای مثال اگر اسم فایل my_custom_command.py باشد، از طریق دستور زیر می‌توانیم آن را اجرا کنیم:

    python manage.py my_custom_command

    بیایید سراغ مثال‌های بعدی برویم.

    مثال‌های پایه‌ای

    مثال زیر، نمونه‌ای از شیوه صحیح ایجاد یک دستور است:

    management/commands/what_time_is_it.py

    from django.core.management.base import BaseCommand
    from django.utils import timezone
    
    class Command(BaseCommand):
        help = 'Displays current time'
    
        def handle(self, *args, **kwargs):
            time = timezone.now().strftime('%X')
            self.stdout.write("It's now %s" % time)

    اساسا دستورات مدیریتی جنگو با کلاسی به نام Command، که از BaseCommand ارث‌بری می‌کند، ساخته شده‌اند. به این نکته توجه کنید که دستور را باید در داخل متد handle() تعریف کنید.

    در این مثال اسم فایل what_time_is_it.py است، در نتیجه برای استفاده از آن، از دستور زیر استفاده می‌کنیم:

    python manage.py what_time_is_it

    خروجی:

    It's now 18:35:31

    شاید از خودتان بپرسید که تفاوت این روش با استفاده از یک اسکریپت ساده پایتونی چیست؟ و یا مزایای این روش چیست؟ مزیت اصلی این است که جنگو به طور کامل لود شده است و آماده استفاده است، این یعنی می‌توانید مدل‌ها را وارد کنید و کوئری‌هایی که نیاز دارید بر دیتابیس اجرا کنید را توسط ORM جنگو، بر روی دیتابیس پیاده کنید. در ضمن این اجازه را به شما می‌دهد که با تمام منابع پروژه‌تان نیز کار کنید.

    مدیریت ورودی‌ها

    جنگو امکان استفاده از argparse (که جزو کتابخانه‌های استاندارد پایتون است) را فراهم می‌کند. برای مدیریت ورودی‌ها در دستورات‌مان، باید متدی با نام add_arguments ایجاد کنیم.

    ورودی‌های اجباری

    در مثال بعد دستوری را ایجاد می‌کنیم که به صورت رندوم کاربر می‌سازد (در واقع آبجکتی از کلاس User بوجود می‌آورد و آن را در دیتابیس ذخیره می‌کند). این دستور یک ورودی اجباری، به نام total می‌گیرد، که این ورودی مشخص کننده تعداد کاربرهایی است که می‌خواهیم ایجاد کنیم:

    management/commands/create_users.py

    from django.contrib.auth.models import User
    from django.core.management.base import BaseCommand
    from django.utils.crypto import get_random_string
    
    class Command(BaseCommand):
        help = 'Create random users'
    
        def add_arguments(self, parser):
            parser.add_argument('total', type=int, help='Indicates the number of users to be created')
    
        def handle(self, *args, **kwargs):
            total = kwargs['total']
            for i in range(total):
                User.objects.create_user(username=get_random_string(), email='', password='123')

    با روش زیر از این دستور استفاده می‌کنیم:

    python manage.py create_users 10

    ورودی‌های اختیاری

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

    management/commands/create_users.py

    from django.contrib.auth.models import User
    from django.core.management.base import BaseCommand
    from django.utils.crypto import get_random_string
    
    class Command(BaseCommand):
        help = 'Create random users'
    
        def add_arguments(self, parser):
            parser.add_argument('total', type=int, help='Indicates the number of users to be created')
    
            # Optional argument
            parser.add_argument('-p', '--prefix', type=str, help='Define a username prefix', )
    
        def handle(self, *args, **kwargs):
            total = kwargs['total']
            prefix = kwargs['prefix']
    
            for i in range(total):
                if prefix:
                    username = '{prefix}_{random_string}'.format(prefix=prefix, random_string=get_random_string())
                else:
                    username = get_random_string()
                User.objects.create_user(username=username, email='', password='123')

    نحوه استفاده از این دستور:

    python manage.py create_users 10 --prefix custom_user

    و یا:

    python manage.py create_users 10 -p custom_user

    اگر prefix تعیین شده باشد، نام‌کاربری مثل custom_user_oYwoxtt4vNHR ایجاد خواهد شد، اما اگر prefix تعیین نشود، نام کاربری oYwoxtt4vNHR خواهد بود، یعنی مقدار رندومی که ایجاد شده است.

    سوییچ‌ها

    مدل دیگری از ورودی‌های اختیاری، سوییچ‌ها و یا flagها هستند، که برای کنترل و تعیین مقادیر صحیح و غلط استفاده می‌شود. در نظر بگیرید که می‌خواهیم سوییچ --admin را اضافه کنیم، تا بتوانیم به هنگام اجرای دستور، کاربری با دسترسی ادمین و یا کاربری با دسترسی معمولی، ایجاد کنیم:

    management/commands/create_users.py

    from django.contrib.auth.models import User
    from django.core.management.base import BaseCommand
    from django.utils.crypto import get_random_string
    
    class Command(BaseCommand):
        help = 'Create random users'
    
        def add_arguments(self, parser):
            parser.add_argument('total', type=int, help='Indicates the number of users to be created')
            parser.add_argument('-p', '--prefix', type=str, help='Define a username prefix')
            parser.add_argument('-a', '--admin', action='store_true', help='Create an admin account')
    
        def handle(self, *args, **kwargs):
            total = kwargs['total']
            prefix = kwargs['prefix']
            admin = kwargs['admin']
    
            for i in range(total):
                if prefix:
                    username = '{prefix}_{random_string}'.format(prefix=prefix, random_string=get_random_string())
                else:
                    username = get_random_string()
    
                if admin:
                    User.objects.create_superuser(username=username, email='', password='123')
                else:
                    User.objects.create_user(username=username, email='', password='123')

    نحوه استفاده:

    python manage.py create_users 2 --admin

    و یا:

    python manage.py create_users 2 -a

    لیستی دلخواه از ورودی‌ها

    بیایید دستور جدیدی با نام delete_users ایجاد کنیم. در این دستور می‌توانیم لیستی از id کاربران را وارد کنیم، در نتیجه این دستور باید این کاربران را از دیتابیس حذف کند:

    management/commands/delete_users.py

    from django.contrib.auth.models import User
    from django.core.management.base import BaseCommand
    
    class Command(BaseCommand):
        help = 'Delete users'
    
        def add_arguments(self, parser):
            parser.add_argument('user_id', nargs='+', type=int, help='User ID')
    
        def handle(self, *args, **kwargs):
            users_ids = kwargs['user_id']
    
            for user_id in users_ids:
                try:
                    user = User.objects.get(pk=user_id)
                    user.delete()
                    self.stdout.write('User "%s (%s)" deleted with success!' % (user.username, user_id))
                except User.DoesNotExist:
                    self.stdout.write('User with id "%s" does not exist.' % user_id)

    نحوه استفاده:

    python manage.py delete_users 1

    خروجی:

    User "SMl5ISqAsIS8 (1)" deleted with success!

    همچنین می‌توانیم لیستی از اعداد که با فاصله از هم جدا شده‌اند را نیز به این دستور بدهیم تا کاربران با این idهای مشخص، توسط تنها یک دستور از دیتابیس حذف شوند:

    python manage.py delete_users 1 2 3 4

    خروجی:

    User with id "1" does not exist.
    User "9teHR4Y7Bz4q (2)" deleted with success!
    User "ABdSgmBtfO2t (3)" deleted with success!
    User "BsDxOO8Uxgvo (4)" deleted with success!

    استایل‌دهی

    می‌توانیم مثال‌های قبلی را با دادن رنگ مناسب به خروجی، بهبود ببخشیم:

    management/commands/delete_users.py

    from django.contrib.auth.models import User
    from django.core.management.base import BaseCommand
    
    class Command(BaseCommand):
        help = 'Delete users'
    
        def add_arguments(self, parser):
            parser.add_argument('user_id', nargs='+', type=int, help='User ID')
    
        def handle(self, *args, **kwargs):
            users_ids = kwargs['user_id']
    
            for user_id in users_ids:
                try:
                    user = User.objects.get(pk=user_id)
                    user.delete()
                    self.stdout.write(self.style.SUCCESS('User "%s (%s)" deleted with success!' % (user.username, user_id)))
                except User.DoesNotExist:
                    self.stdout.write(self.style.WARNING('User with id "%s" does not exist.' % user_id))

    نحوه استفاده همانند مثال‌های قبل است، اما تفاوت تنها در خروجی است:

    python manage.py delete_users 3 4 5 6

    خروجی:

    خروجی دستور python manage.py delete_users

    لیست زیر تمامی استایل‌های موجود برای دستورات مدیریتی را نشان می‌دهد:

    from django.core.management.base import BaseCommand
    
    class Command(BaseCommand):
        help = 'Show all available styles'
    
        def handle(self, *args, **kwargs):
            self.stdout.write(self.style.ERROR('error - A major error.'))
            self.stdout.write(self.style.NOTICE('notice - A minor error.'))
            self.stdout.write(self.style.SUCCESS('success - A success.'))
            self.stdout.write(self.style.WARNING('warning - A warning.'))
            self.stdout.write(self.style.SQL_FIELD('sql_field - The name of a model field in SQL.'))
            self.stdout.write(self.style.SQL_COLTYPE('sql_coltype - The type of a model field in SQL.'))
            self.stdout.write(self.style.SQL_KEYWORD('sql_keyword - An SQL keyword.'))
            self.stdout.write(self.style.SQL_TABLE('sql_table - The name of a model in SQL.'))
            self.stdout.write(self.style.HTTP_INFO('http_info - A 1XX HTTP Informational server response.'))
            self.stdout.write(self.style.HTTP_SUCCESS('http_success - A 2XX HTTP Success server response.'))
            self.stdout.write(self.style.HTTP_NOT_MODIFIED('http_not_modified - A 304 HTTP Not Modified server response.'))
            self.stdout.write(self.style.HTTP_REDIRECT('http_redirect - A 3XX HTTP Redirect server response other than 304.'))
            self.stdout.write(self.style.HTTP_NOT_FOUND('http_not_found - A 404 HTTP Not Found server response.'))
            self.stdout.write(self.style.HTTP_BAD_REQUEST('http_bad_request - A 4XX HTTP Bad Request server response other than 404.'))
            self.stdout.write(self.style.HTTP_SERVER_ERROR('http_server_error - A 5XX HTTP Server Error response.'))
            self.stdout.write(self.style.MIGRATE_HEADING('migrate_heading - A heading in a migrations management command.'))
            self.stdout.write(self.style.MIGRATE_LABEL('migrate_label - A migration name.'))
    خروجی تمامی استایل‌های موجود برای دستورات جنگو

    Cron Job

    اگر تسکی (task) داشته باشید که بخواهید آن را به صورت دوره‌ای اجرا کنید، مثل ایجاد گزارش در هر دوشنبه و یا یک scrapper دارید که می‌خواهید برخی از داده‌ها را از چند صفحه وب مشخص، در هر ۱۰ دقیقه، ذخیره کند. می‌توانید این کد را به عنوان یک دستور مدیریتی ایجاد کنید و آن را به فایل crontab سرورتان اضافه کنید:

    # m h  dom mon dow   command
    0 4 * * * /home/mysite/venv/bin/python /home/mysite/mysite/manage.py my_custom_command

    مثال بالا، دستور my_custom_command را هر روز ساعت ۴ صبح، اجرا می‌کند.

    اطلاعات بیشتر

    مثال‌های بالا برای شروع کار کافی است. برای استفاده‌های بیشتر باید با قابلیت‌های argparse بیشتر آشنا شوید، همچنین مستندات رسمی دستورات مدیریتی جنگو نیز بهترین منبع در این زمینه است.

    منبع:https://simpleisbetterthancomplex.com/tutorial/2018/08/27/how-to-create-custom-django-management-commands.html

    برچسب‌ها:

    ســــــــــــــــــــــال‌هاست که هستیم

    ۶ سال در کنار شما تجربه جمع کردیم. تازه در ابتدای مسیر هستیم، مسیر ساخت آینده.

    جمع‌مـــــــــــان، جمع است

    بیش از ۴۰ هزار توسعه‌دهنده و صاحبان کسب و کار در جمع ما هستند. جای شما خالی‌ست...

    خدمات رایگان لیارا

    ۲.۵ گیگابایت فضای ذخیره‌سازی ابری رایگان

    ۲.۵ گیگابایت Object Storage سازگار با پروتکل S3 با دیسک‌های SSD به‌صورت رایگان دریافت کنید.

    هاست رایگان برای دیتابیس‌

    دیتابیس‌های MariaDB، PostgreSQL و Redis را فقط با یک کلیک و به‌صورت رایگان تهیه کنید.

    سرویس DNS رایگان

    به سادگی دامنه‌تان را اضافه کنید و به صورت رایگان رکورد‌های آن را مدیریت کنید.

    ۱۰۰ هزار تومان اعتبار اولیه

    بعد از ثبت نام در لیارا مبلغ ۱۰۰ هزار تومان اعتبار هدیه دریافت می‌کنید که با توجه به ساعتی بودن هزینه سرویس‌ها، می‌توانید تمامی خدمات پولی را برای چندین هفته رایگان استفاده کنید.

    ارسال ۱۰۰ ایمیل تراکنشی رایگان در هر ماه

    در سرویس ایمیل لیارا شما می‌توانید تا ۱۰۰ ایمیل رایگان در هر ماه ارسال کنید. (به‌همراه دسترسی SMTP)

    هاست رایگان برای انواع وبسایت

    تفاوتی ندارد برای وبسایت خود از Node استفاده می‌کنید یا Laravel و Django، در لیارا می‌توانید به صورت کاملا رایگان آن را میزبانی کنید.

    همراه شما هستیم

    در خصوص سفارش یا استفاده از سرویس‌ها سوالی دارید؟
    تلفن واحد فروش:
    ۰۲۵-۳۳۵۵۷۶۱۹ (روزهای کاری ۹ الی ۱۷)
    تلفن واحد فروش: ۳۳۵۵۷۶۱۹-۰۲۵ (روزهای کاری ۹ الی ۱۷)