- 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:
- Check if your app's description has the word "and", if so, try to break it in more apps.
2. Easy to install
- Add a LICENSE file.
- Distribute on PyPI:
- Publish on Django Packages.
Install dependencies automatically:
Add dependencies on
Don't add Django to
Don't pin versions with
- Add dependencies on
- Check if you need a Django app or a regular Python package:
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 = Noneshouldn'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
Convert hardcoded internal parameters to settings:
AVATAR_MAX_SIZEof 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:
Give credit, have a
- Check this script to generate AUTHORS file from git history.
3. Easy to use
- 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:
- Have Continuous Integration:
- Ship with an example project:
- Separate Django abstractions into commonly used filenames like views.py, forms.py, fields.py, etc.
Follow the pattern
resource_actionin URLs names, like
Never rely on Django default user model, support
custom user models:
- Check a implementation at django-registration.
- Provide declarative usage:
- Don't connect code implicitly by name or module. Have a registry:
- Have management commands for common developer needs:
objects, when interacting with models of the host project.
- Use generators for lazy evaluation.
withstatement contexts to deal with unmanaged resources.
- Provide checks with Django System check framework.
ImproperlyConfiguredif the developer makes a mistake on the config:
ImproperlyConfiguredwhen the developer forgets to specify
- For example, django-filter raises
ValueErrorwhen the app gets an invalid argument.
- Internationalize (I18N) your strings.
4. Easy to integrate
Reduce integration discontinuities:
- Break class behaviors into methods.
- Separate class behaviors into mixins.
- Isolate logic into helper modules with business functions and classes.
- Make sure app doesn't break when AppConfig is extended.
Provide default templates:
Don't put them directly into
templates/, put into
- 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
avatartemplate tag to generate HTML
imgtags, but the logic to generate avatar URLs is isolated at
- 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:
- 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.