未加星标

Build a blog with Django: Add a custom management command to seed posts

字体大小 | |
[开发(python) 所属分类 开发(python) | 发布者 店小二05 | 时间 2017 | 作者 红领巾 ] 0人收藏点击收藏

Let's make it really easy to generate seed data for posts by writing a custom management command to do the job for us.

Previously, we had to go into the shell and do the following:

>>> from posts.models import Post >>> Post.objects.all().delete() >>> from posts.seed import create_posts >>> create_posts(1, 5)

But, as I mentioned at the end of thatpost, it would be so much simpler if we could just do python manage.py createposts --unpublished 1 --published 5 instead.

In this post, I'll show you how.

Let's get started.

Add a createposts management command

As usual, Django has excellent documentation on writing custom commands . So I'll just give you a quick overview and refer you to the docs for further details.

Applications can create their own commands to use with manage.py . To do so simply add a management/commands directory to the application and Django will automatically register a manage.py command for each Python module in that directory whose name doesn't begin with an underscore.

Hence, for our createposts command we will have to create a createposts.py module in the management/commands directory like so:

posts ├── ... ├── management │ ├── commands │ │ ├── createposts.py │ │ └── __init__.py │ └── __init__.py │...

If you now do the following:

(venv) $ cd src && python manage.py

You'd see your new command listed among all the other possible commands:

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

Now we just need to put some code into the module for our specific needs.

Django only has one requirement when it comes to the contents of the module. It MUST have a class Command that extends BaseCommand or one of its subclasses .

Here's the structure of the module:

from django.core.management.base import BaseCommand # ... class Command(BaseCommand): help = '...' def add_arguments(self, parser): # ... def handle(self, *args, **options): # ...

The help class attribute should contain a short description of the command. It would be printed in the help message when the user runs the command python manage.py help createposts . (see docs )

You override the add_arguments method to add both positional and optional arguments that will be accepted by the command. (see docs )

Subclasses MUST implement the handle method in order to provide the actual logic of the command. (see docs )

Let's fill it all out.

Add a help message

This one is simple. Just add the following:

help = 'Seeds the database with a given number of unpublished and published posts.' Add optional arguments

The parser argument that's passed to the add_arguments method is an instance of CommandParser . But, CommandParser is just a subclass of ArgumentParser . Hence, to understand how to work with the parser argument it's helpful to read up on Python's argparse module.

We'll be needing to use the add_argument method of parser .

Here's what we want to do: We want to add two optional arguments called unpublished and published . They both take integer arguments and default to 0 when they aren't provided.

And, we say that as follows:

def add_arguments(self, parser): parser.add_argument('--unpublished', default=0, type=int, help='The number of unpublished posts to create.') parser.add_argument('--published', default=0, type=int, help='The number of published posts to create.') Add the actual logic of the command

Finally, we need to add the logic to do the actual work.

Here's what we want to happen: Firstly, ask the user if they do want to continue with the operation since we'd be deleting all posts before adding the new ones. If they say yes then we want to delete the posts and create the new posts. Otherwise, we ignore the operation.

And, here it is in code:

from django.db import transaction from posts.models import Post from posts.seed import create_posts # ... def handle(self, *args, **options): confirm = input("""This operation will IRREVERSIBLY DESTROY all posts currently in the database. Are you sure you want to do this? Type 'yes' to continue, or 'no' to cancel: """) if confirm == 'yes': with transaction.atomic(): Post.objects.all().delete() unpublished = max(0, options['unpublished']) published = max(0, options['published']) create_posts(unpublished, published) else: self.stdout.write('Operation cancelled.\n')

Pretty straightforward, except maybe for transaction.atomic .

You see, we want all the changes we're making to the database to happen in one transaction . A transaction is a sequence of operations performed as a single logical unit of work.

Suppose that after deleting all the posts from the database the program crashes due to a bug in create_posts , i.e. all the previous posts are gone but no new posts have been created. That sucks for the user (though it shouldn't be so bad in this case since it's probably all fake data anyway). With the operations wrapped in a transaction that will never happen since any database changes will be rolled back in the event of a failure, i.e. if create_posts crashes then the deleted posts are "restored" in the database. The user is notified of the error (in this case via a stack trace on the command-line) and the database looks as it did before running the command.

I suggest you try out the command and see for yourself how it all works.

Wrap up

We're almost done with the overall "add posts" feature.


Build a blog with Django: Add a custom management command to seed posts

Here's the commit that tracks what we did today.

See you next time when I show you how to handle the display of published posts. We'd be touching on managers , get_absolute_url , URL patterns , views and templates .

I hope you enjoy seeing how all the features of Django come together to provide a seamless web development experience.

P.S. Let me know in the comments below about your experience using custom management commands. Do you like them? Any tips? I'd love to get your feedback.

P.S.S. Subscribe to my newsletter if you're interested in getting exclusive Django content.

本文开发(python)相关术语:python基础教程 python多线程 web开发工程师 软件开发工程师 软件开发流程

主题: DjangoPython
分页:12
转载请注明
本文标题:Build a blog with Django: Add a custom management command to seed posts
本站链接:http://www.codesec.net/view/531548.html
分享请点击:


1.凡CodeSecTeam转载的文章,均出自其它媒体或其他官网介绍,目的在于传递更多的信息,并不代表本站赞同其观点和其真实性负责;
2.转载的文章仅代表原创作者观点,与本站无关。其原创性以及文中陈述文字和内容未经本站证实,本站对该文以及其中全部或者部分内容、文字的真实性、完整性、及时性,不作出任何保证或承若;
3.如本站转载稿涉及版权等问题,请作者及时联系本站,我们会及时处理。
登录后可拥有收藏文章、关注作者等权限...
技术大类 技术大类 | 开发(python) | 评论(0) | 阅读(95)