- Check if your app follows Unix philosophy: "Do one thing, and do it well".
- Check if your app's description fits a few words. Examples:
- django-taggit: django-taggit a simpler approach to tagging with Django.
- django-js-reverse: Javascript URL handling for Django that doesn't hurt.
- django-impersonate: Simple application to allow superusers to "impersonate" other non-superuser accounts.
- Check if your app's description has the word "and", if so, try to break it in more apps.
- Add a LICENSE file.
- Distribute on PyPI:
- Check for name clashes to avoid problems like django-filter vs django-filters.
- Use Wheels.
- Publish on Django Packages.
- Install dependencies automatically:
- Add dependencies on
install_requires
on setup.py. - Don't add Django to
install_requires
. - Don't pin versions with
==
oninstall_requires
. Use>=
.
- Add dependencies on
- Check if you need a Django app or a regular Python package:
- Django apps need to be added to
INSTALLED_APPS
. Regular Python packages do not. - Examples of regular Python packages:
- Django apps need to be added to
- Have sane and smart defaults:
- Make it work by default.
- Don't require copy and pasting of code snippets.
- Don't do anything dangerous by default, like caching.
- Require unsafe behavior to be explicit:
- Don't show all if something isn't set, e.g.,
fields = None
shouldn't mean all fields.
- Don't show all if something isn't set, e.g.,
- Have declarative settings to allow easy configuration:
- Add a prefix to all settings of the app, like
MYAPP_SETTING_KEY
. - Convert hardcoded internal parameters to settings:
- For example,
AVATAR_MAX_SIZE
of django-avatar could be hardcoded, but it's a setting.
- For example,
- If needed frequently by developers, allow behavior to be changed with just a change of settings.
- If needed frequently by developers, accept custom classes and functions on settings via dotted path:
- For example, django-taggit supports custom tag parsers via settings.
- Add a prefix to all settings of the app, like
- Support declarative pipelines for configurable workflows:
- Check a implementation at python-social-auth.
- Provide default views with templates and URLs to allow the app to be easily included.
- Have a friendly upgrade policy:
- Deprecate before removing. Raise deprecation warnings, use Python warnings built-in module.
- Don't rewrite migrations:
- Users might depend on your old migration files because they ran it against their data in the past.
- Keep a CHANGELOG.
- Follow Semantic Versioning.
- Give credit, have a AUTHORS file:
- Check this script to generate AUTHORS file from git history.
- Provide documentation:
- Write docs first.
- Have a README.
- Provide a quick start tutorial describing the most common use case.
- Separate high level from low-level docs.
- Use gender neutral pronouns.
- Host it in Read the Docs.
- Write tests:
- Test with a custom user model.
- Provide coverage.
- Have Continuous Integration:
- Use tox to test against various Python and Django versions.
- Check tox.ini of popular projects like django-filter and django-taggit.
- Respect PEP 8, use flake8.
- Use tox to test against various Python and Django versions.
- Ship with an example project:
- Examples of implementations:
- Separate Django abstractions into commonly used filenames like views.py, forms.py, fields.py, etc.
- Follow the pattern
resource_action
in URLs names, likepassword_reset
orproduct_detail
. - Never rely on Django default user model, support custom user models:
- Check a implementation at django-registration.
- Provide declarative usage:
- Examples of implementations:
- Don't connect code implicitly by name or module. Have a registry:
- Examples of implementations:
- Have management commands for common developer needs:
- Examples of implementations:
- Use
_default_manager
, notobjects
, when interacting with models of the host project. - Be Pythonic:
- Use generators for lazy evaluation.
- Use
with
statement contexts to deal with unmanaged resources.
- Prevent errors:
- Provide checks with Django System check framework.
- Fail-fast:
- Raise
ImproperlyConfigured
if the developer makes a mistake on the config:- For example, django-filter raises
ImproperlyConfigured
when the developer forgets to specifyfilterset_class
ormodel
in aFilterView
.
- For example, django-filter raises
- Raise
TypeError
orValueError
when the app gets an invalid argument.
- Raise
- Internationalize (I18N) your strings.
- Reduce integration discontinuities:
- Break class behaviors into methods.
- Separate class behaviors into mixins.
- Isolate logic into helper modules with business functions and classes.
- Use
AppConfig
:- Make sure app doesn't break when AppConfig is extended.
- Provide default templates:
- Don't put them directly into
templates/
, put intotemplates/app_name/
. - Guarantee they can be changed by loading a custom one with the same path.
- Don't put them directly into
- Provide template tags for presenting complex data:
- Leave only presentation logic into template tags, break the rest of logic into helpers.
- For example, django-avatar has a
avatar
template tag to generate HTMLimg
tags, but the logic to generate avatar URLs is isolated atproviders.py
.
- For example, django-avatar has a
- Leave only presentation logic into template tags, break the rest of logic into helpers.
- Provide default views:
- Don't break the configurability of class-based views, allow existing Django views attrs and methods to be overridden.
- Break views common logic into mixins.
- Avoid built-in models if possible:
- If you need to have them, provide an abstract model and allow your app to work with a concrete custom variety. Examples of implementations:
- Break models common parts into abstract models.
- Don't use model mixins, use abstract models:
- Check the reason on this StackOverflow answer.
- When using Generic Foreign Keys, allow them to be overridden by direct FKs. Examples of implementations:
- Isolate form field logic into form fields and widgets:
- Check a implementation at django-recaptcha.
- Isolate model field logic into model fields:
- Check a implementation at django-hashid-field.
- Isolate query logic into queryset methods, like filter, update and delete logic.
- Isolate table-level behavior logic into managers methods, like create logic.
- Isolate validation logic into validators.
- Use context processors only for global logic.
- Use middlewares only for global logic related to request-response cycle or current user.
- Avoid signals spaghetti code.
- Be transparent about bugs, especially security issues:
- Add security warnings to CHANGELOG, make sure they're parseable by safety tool.
- Don't abandon the project, give it away.