如何在Django中創(chuàng)建自定義命令?

例如:
1、清理錯(cuò)誤的數(shù)據(jù)列
2、導(dǎo)入初始數(shù)據(jù)庫(kù)數(shù)據(jù)
我們可以通過(guò)兩種方式在django中運(yùn)行這些類(lèi)型的命令。第一是編寫(xiě)一個(gè)普通的python腳本,然后可以通過(guò)運(yùn)行python file_name.py來(lái)調(diào)用它,而另一個(gè)方法是使用django-admin命令。這些是通過(guò)調(diào)用python manage.py command_name運(yùn)行的。
對(duì)于這篇文章,我將通過(guò)一個(gè)博客應(yīng)用程序進(jìn)行演示,該應(yīng)用程序只有3個(gè)數(shù)據(jù)庫(kù)表:User,Category和Post。
對(duì)于第一個(gè)示例,我們將嘗試使用以下腳本列出所有系統(tǒng)用戶(hù):
from django.contrib.auth import get_user_modelUser = get_user_model()# retrieve all usersusers = User.objects.all()# loop through all usersfor user in users:print(f'user is {user.get_full_name()} and their username is {user.get_username()}')
django.core.exceptions.ImproperlyConfigured: Requested setting AUTH_USER_MODEL, but settings are not configured. You must either define the environment variable DJANGO_SETTINGS_MODULE or call settings.configure() before accessing settings
我們將通過(guò)稍微修改腳本來(lái)做到這一點(diǎn)。
import osos.environ.setdefault('DJANGO_SETTINGS_MODULE', 'projectname.settings')import djangodjango.setup()from django.contrib.auth import get_user_modelUser = get_user_model()users = User.objects.all()for user in users:print(f'user is {user.get_full_name()} and their username is {user.get_username()}')
請(qǐng)注意,導(dǎo)入順序很重要,不要調(diào)整,這里有坑。
如果再次運(yùn)行腳本,則所有用戶(hù)都會(huì)正常打印到終端,沒(méi)有報(bào)錯(cuò)了。
接下來(lái),我們將通過(guò)運(yùn)行django-admin startapp posts來(lái)創(chuàng)建一個(gè)名為posts的app應(yīng)用。
該應(yīng)用程序?qū)覀兊牟┛臀恼履P?/span>
from django.db import modelsfrom django.contrib.auth import get_user_modelUser = get_user_model()# Create your models here.class CommonInfo(models.Model):created_at = models.DateTimeField(auto_now_add=True)updated_at = models.DateTimeField(auto_now=True)class Meta:abstract = Trueordering = ('-created_at',)# blog post categoryclass Category(CommonInfo):name = models.CharField(max_length=255)def __str__(self):return self.name# blog post instanceclass Post(CommonInfo):title = models.CharField(max_length=255)category = models.ForeignKey(Category,related_name='posts',on_delete=models.PROTECT)author = models.ForeignKey(User,related_name='posts',on_delete=models.PROTECT)content = models.TextField()published = models.BooleanField(default=False)def __str__(self):return f'{self.title} by {self.author.get_full_name()}'
import osos.environ.setdefault('DJANGO_SETTINGS_MODULE', 'commands.settings')import djangodjango.setup()from django.contrib.auth import get_user_modelfrom posts.models import Category, PostUser = get_user_model()def select_category():# retrieve categories. (You can create some examples from the django admin)categories = Category.objects.all().order_by('created_at')print('Please select a category for your post: ')for category in categories:print(f'{category.id}: {category}')category_id = input()category = Category.objects.get(id=category_id)return categorydef select_author():# retrieve all usersusers = User.objects.all()print('Please select an author for your post: ')for user in users:print(f'{user.id}: {user}')user_id = input()user = User.objects.get(id=user_id)return userdef create_post():title = input("Title of your post: ")content = input("Long post content: ")category = select_category()author = select_author()Post(**locals()).save()print('Post created successfully!')if __name__ == "__main__":create_post()
通過(guò)運(yùn)行python create_post.py,然后提示我們進(jìn)行一些輸入。
編寫(xiě)自定義django管理命令方法
文章剛看開(kāi)始也提到了,django-admin命令是通過(guò)運(yùn)行python manage.py command_name來(lái)執(zhí)行的,我們平時(shí)用的有runserver,migrate和collectstatic。如果要獲取可用命令的列表,可以運(yùn)行python manage.py help。這將顯示可用命令以及它們所在的django app文件夾的列表。
要注冊(cè)自定義管理命令,需要在django應(yīng)用程序文件夾中添加一個(gè)management \ commands目錄。在我們的例子中,它將位于posts \ management \ commands中。
設(shè)置完成后,我們便可以在命令文件夾中初始化自定義腳本。對(duì)于第一個(gè)示例,我們將編寫(xiě)一個(gè)命令,將之前創(chuàng)建的博客文章標(biāo)記為已發(fā)布。
請(qǐng)創(chuàng)建一個(gè)文件并將其命名為publish_post.py
from django.core.management.base import BaseCommand, CommandErrorfrom posts.models import Category, Postclass Command(BaseCommand):help = 'Marks the specified blog post as published.'# allows for command line argsdef add_arguments(self, parser):parser.add_argument('post_id', type=int)def handle(self, *args, **options):try:post = Post.objects.get(id=options['post_id'])except Post.DoesNotExist:raise CommandError(f'Post with id {options["post_id"]} does not exist')if post.published:self.stdout.write(self.style.ERROR(f'Post: {post.title} was already published'))else:post.published = Truepost.save()self.stdout.write(self.style.SUCCESS(f'Post: {post.title} successfully published'))
為了接收參數(shù),該類(lèi)利用argparse。方法add_arguments允許我們的函數(shù)接收參數(shù)。
在我們的例子中,該函數(shù)期望一個(gè)參數(shù),該參數(shù)將被分配鍵post_id
然后,handle()函數(shù)評(píng)估輸入并執(zhí)行我們的邏輯。
在上面的示例中,期望的參數(shù)類(lèi)型稱(chēng)為位置參數(shù),必須提供該參數(shù)才能運(yùn)行該函數(shù)。為此,我們運(yùn)行python manage.py publish_post 1(或任何發(fā)布主鍵)
顧名思義,可以將另一種類(lèi)型的參數(shù)稱(chēng)為可選參數(shù)應(yīng)用于方法,缺少這些參數(shù)不會(huì)影響函數(shù)的執(zhí)行。
下面提供了一個(gè)示例。我們將初始化一個(gè)文件并將其命名為edit_post.py。代碼如下:
from django.core.management.base import BaseCommand, CommandErrorfrom posts.models import Category, Postclass Command(BaseCommand):help = 'Edits the specified blog post.'def add_arguments(self, parser):parser.add_argument('post_id', type=int)# optional argumentsparser.add_argument('-t', '--title',type=str, help='Indicate new name of the blog post.')parser.add_argument('-c', '--content',type=str, help='Indicate new blog post content.')def handle(self, *args, **options):title = options['title']content = options['content']try:post = Post.objects.get(id=options['post_id'])except Post.DoesNotExist:raise CommandError(f'Post with id {options["post_id"]} does not exist')if title or content:if title:old_title = post.titlepost.title = titlepost.save()self.stdout.write(self.style.SUCCESS(f'Post: {old_title} has been update with a new title, {post.title}'))if content:post.content = contentpost.save()self.stdout.write(self.style.SUCCESS('Post: has been update with new text content.'))else:self.stdout.write(self.style.NOTICE('Post content remains the same as no arguments were given.'))
或python manage.py edit_post -c “new content ”僅編輯內(nèi)容。如果我們希望通過(guò)`python manage.py edit_post 2 -t “new title again” -c “new title again”編輯標(biāo)題和內(nèi)容,則可以提供兩個(gè)參數(shù)。
(版權(quán)歸原作者所有,侵刪)
![]()

點(diǎn)擊下方“閱讀原文”查看更多
評(píng)論
圖片
表情
