Save Time by Writing and Using Reusable Python Django Apps
It’s not trivial to design, develop and maintain a web application. Lots of features and aspects have to be handled properly in order for a web application to succeed. To name a few, the features that are common to almost every web application are user management, third-party oauth sign in / sign up and admin site. Since so many common problems have to be solved in any web application over and over again, it makes sense to make them reusable components / packages so that a new web application can simply leverage the existing code to save time during development.
Fortunately, the Python Package Index (pypi
) provides numerous packages you can use in your own application. More specifically, the Django Packages list all the reusables Django apps you can integrate into your own project. Finding and using a proper Django package is often better and more time-efficient than writing one yourself.
In this article, we are going to learn how to make our current myblog
Django application become a reusable Django package so that you or someone else can use it in his or her own project.
- Python’s Django vs Ruby on Rails
- How to Install Django on Windows, Mac and Linux
- Using Python Django’s ModelForm in Your First Django Application
Package and App
Before we start, we should clarify a critical point about packages and apps. A Python package is a logical group of Python code that’s easy to re-use. A package often contains multiple Python files that are called modules.
Usually, we use a module or a package by importing it like import myblog.views
or from myblog import views
. To make a Python directory such as myblog
become a package, we put a special file __init__.py
into it even if the directory is empty.
A Django app is just a Python package designed to be used inside a Django project. Usually, a Django app follows common Django conventions such as including models.py
, urls.py
and views.py
.
The term packaging means wrapping the Django app into a deployable Python package so that others can easily integrate it into their own project.
Extract the App Code
After our previous tutorial, the current structure of our application myblog
should look like this:
myblog/ manage.py myblog/ __init__.py admin.py models.py settings.py static/ myblog/ background.jpg style.css templates/ index.html post/ detail.html upload.html tests.py urls.py views.py wsgi.py
First, let’s create a parent directory for myblog
, outside of the root myblog
directory. Let’s call it django-myblog
:
django-myblog/ myblog/ manage.py ...
Second, let’s move the myblog
directory into django-myblog
:
django-myblog/ myblog/ __init__.py ... myblog/ manage.py
Third, create a file django-myblog/README.rst
with the following content:
===== Myblog ===== Myblog is a simple demo of Django's basic usage. Quick start ----------- 1. Add "myblog" to INSTALLED_APPS: INSTALLED_APPS = { ... 'myblog' } 2. Include the myblog URLconf in urls.py: url(r'^myblog/', include('myblog.urls')) 3. Run `python manage.py syncdb` to create myblog's models. 4. Run the development server and access http://127.0.0.1:8000/admin/ to manage blog posts. 5. Access http://127.0.0.1:8000/myblog/ to view a list of most recent posts.
Fourth, create a license file django-myblog/LICENSE
for your reusable app. Usually Django apps are distributed under the BSD license but you’re free to choose any one.
Fifth, create django-myblog/setup.py
to specify instruction about how to install the app which is used by Distribute.
import os from setuptools import setup README = open(os.path.join(os.path.dirname(__file__), 'README.rst')).read() # Allow setup.py to be run from any path os.chdir(os.path.normpath(os.path.join(os.path.abspath(__file__), os.pardir))) setup( name = 'django-myblog', version = '0.1', packages = ['myblog'], include_package_data = True, license = 'BSD License', description = 'A simple Django app demo.', long_description = README, url = 'http://www.example.com/', author = 'Your Name', author_email = 'yourname@example.com', classifiers =[ 'Environment :: Web Environment', 'Framework :: Django', 'Intended Audience :: Developers', 'License :: OSI Approved :: BSD License', # example license 'Operating System :: OS Independent', 'Programming Language :: Python', 'Programming Language :: Python :: 2.6', 'Programming Language :: Python :: 2.7', 'Topic :: Internet :: WWW/HTTP', 'Topic :: Internet :: WWW/HTTP :: Dynamic Content' ] )
Sixth, create django-myblog/MANIFEST.in
to include the text files and static files in our package:
include LICENSE include README.rst recursive-include myblog/static * recursive-include myblog/templates * recursive-include docs *
Notice we also included a directory docs
in MANIFEST.in
. This directory will contain documentation for our reusable app in the future. For now, let’s create an empty directory django-myblog/docs
.
Finally, we build our Python package:
$ python setup.py build running build running build_py creating build creating build/lib creating build/lib/myblog copying myblog/__init__.py -> build/lib/myblog copying myblog/admin.py -> build/lib/myblog copying myblog/models.py -> build/lib/myblog copying myblog/settings.py -> build/lib/myblog copying myblog/tests.py -> build/lib/myblog copying myblog/urls.py -> build/lib/myblog copying myblog/views.py -> build/lib/myblog copying myblog/wsgi.py -> build/lib/myblog running egg_info writing django_myblog.egg-info/PKG-INFO writing top-level names to django_myblog.egg-info/top_level.txt writing dependency_links to django_myblog.egg-info/dependency_links.txt reading manifest file 'django_myblog.egg-info/SOURCES.txt' writing manifest file 'django_myblog.egg-info/SOURCES.txt'
Use django-myblog in a New Django Web Application
Suppose you are going to start a new Django project and it’s going to use the functionality in myblog
. You can simply reuse django-myblog
we just built in your new project.
First, let’s create a new Django project:
$ django-admin.py startproject mysite
Second, let’s modify mysite/settings.py
:
INSTALLED_APPS = ( 'django.contrib.auth', 'django.contrib.contenttypes', 'django.contrib.sessions', 'django.contrib.sites', 'django.contrib.messages', 'django.contrib.staticfiles', 'myblog', # Include 'myblog' into mysite 'django.contrib.admin', # Enable the admin site 'django.contrib.admindocs', # Enable the documentation for admin site )
Third, let’s modify mysite/urls.py
to put myblog
‘s URLconf under /blog
:
urlpatterns = patterns('', ... url(r'^blog/', include('myblog.urls')), )
Fourth, we run `python manage.py syncdb` to create models for myblog
and run `python manage.py runserver` to start the server:
$ python manage.py syncdb Creating tables ... Creating table auth_permission Creating table auth_group_permissions Creating table auth_group Creating table auth_user_groups Creating table auth_user_user_permissions Creating table auth_user Creating table django_content_type Creating table django_session Creating table django_site Creating table myblog_post Creating table myblog_comment You just installed Django's auth system, which means you don't have any superusers defined. Would you like to create one now? (yes/no): yes Username (leave blank to use 'xiaonuogantan'): root Email address: Password: Password (again): Superuser created successfully. Installing custom SQL ... Installing indexes ... Installed 0 object(s) from 0 fixture(s) $ python manage.py runserver Validating models... 0 errors found August 21, 2013 - 12:03:10 Django version 1.5.1, using settings 'mysite.settings' Development server is running at http://127.0.0.1:8000/ Quit the server with CONTROL-C.
Finally, we can access http://127.0.0.1:8000/blog/ to take a look at our blog’s home page:
Summary and Tips
In this article, we learned how to package our myblog
app into a reusable component and how to use it in a new django project. It’s always a good idea to write reusable Django apps since you can reuse the same code in new projects, thus saving a significant amount of time. Since Python Package Index (pypi
) and Django Packages provide comprehensive lists of reusable Python and Django apps, you should check them out before starting any new project.