Development Guide¶
This guide is for developers who want to contribute to Django IncludeContents or understand its internals.
Quick Start for Contributors¶
Setting Up Development Environment¶
-
Clone the repository:
-
Install development dependencies:
-
Run tests to verify setup:
Development Workflow¶
Making Changes¶
-
Create a feature branch:
-
Make your changes following the project's coding standards
-
Write tests for new functionality
-
Run the test suite:
-
Check code formatting (if applicable):
Testing Guidelines¶
- Write tests for all new features
- Ensure existing tests pass
- Test both template tag and HTML component syntaxes
- Include edge cases and error conditions
Test Structure:
tests/
├── settings.py # Test Django settings
├── templates/ # Test templates
│ └── components/ # Test component templates
├── test_tag.py # Template tag functionality
├── test_component.py # HTML component syntax
├── test_csrf.py # CSRF token propagation
└── test_multiline.py # Multi-line tag support
Creating Documentation¶
Running Documentation Locally¶
-
Install documentation dependencies:
-
Serve documentation locally:
-
Build documentation:
Documentation Guidelines¶
- Update relevant documentation for any user-facing changes
- Include code examples in documentation
- Test documentation examples to ensure they work
- Follow the existing documentation structure
Changelog Management¶
This project uses towncrier for changelog management.
Adding Changelog Entries¶
Create news fragments for your changes in the changes/
directory:
# Create a news fragment for a new feature
# Format: changes/+description.feature.md
echo "Description of the feature" > changes/+my-feature.feature.md
# Other fragment types:
# changes/+fix-name.bugfix.md # Bug fixes
# changes/+docs.doc.md # Documentation improvements
# changes/+remove-name.removal.md # Removals
# changes/+misc-name.misc.md # Miscellaneous
Fragment Naming Conventions¶
- For new features:
+descriptive-name.feature.md
- For GitHub issue fixes:
123.bugfix.md
(where 123 is the issue number) - For other bug fixes:
+fix-description.bugfix.md
- For documentation:
+docs-description.doc.md
- For removals:
+remove-description.removal.md
- For miscellaneous:
+misc-description.misc.md
Examples¶
# New feature (use + prefix with description):
echo "Add support for Django template tags in component attributes" > changes/+template-tags-in-attributes.feature.md
# GitHub issue fix (use issue number):
echo "Fix component rendering with special characters" > changes/42.bugfix.md
# Other bug fix (use + prefix):
echo "Fix memory leak in template caching" > changes/+fix-memory-leak.bugfix.md
Important: Never edit CHANGES.md
directly - it's generated automatically by towncrier during releases.
Architecture Overview¶
Package Structure¶
includecontents/
├── __init__.py # Package initialization
├── templatetags/
│ └── includecontents.py # Core template tag implementation
├── django/
│ ├── __init__.py
│ ├── base.py # Custom template engine base
│ ├── engine.py # Custom Django template engine
│ └── loaders.py # Template loaders
└── next_version.py # Version management
Key Components¶
1. Template Tag (templatetags/includecontents.py
)¶
- Core
{% includecontents %}
tag implementation - Context isolation logic
- Content block processing
- Props validation
2. Custom Template Engine (django/
)¶
- HTML component syntax parsing (
base.py
) - Template engine integration (
engine.py
) - Custom template loaders (
loaders.py
)
3. Testing Framework (tests/
)¶
- Comprehensive test suite
- Test templates and components
- Integration and unit tests
Design Principles¶
- Context Isolation: Components run in isolated contexts for predictability
- Backward Compatibility: Template tag syntax always supported
- HTML-like Syntax: Modern component syntax feels familiar
- Django Integration: Works seamlessly with Django's template system
Contributing Guidelines¶
Code Standards¶
- Follow Django coding conventions
- Write comprehensive tests
- Document new features
- Maintain backward compatibility
Pull Request Process¶
- Fork the repository
- Create a feature branch
- Make your changes with tests
- Create changelog fragment
- Submit pull request
Getting Help¶
- GitHub Issues: Bug reports and feature requests
- Discussions: Questions and community help
- Documentation: Complete feature documentation
Troubleshooting Development Issues¶
Common Setup Issues¶
Tests not running:
# Ensure you're in the project directory
cd django-includecontents
# Install in development mode
pip install -e ".[test]"
# Run tests with verbose output
pytest -v
Documentation not building:
# Install docs dependencies
pip install -e ".[docs]"
# Check for missing dependencies
mkdocs build --verbose
Debugging Tips¶
- Use
uv run
for consistent environments - Enable Django template debugging
- Run specific test files for faster feedback
- Use print statements in template tags for debugging
Release Process¶
The release process for Django IncludeContents uses manual GitHub Actions workflows for complete control over releases.
Creating a Release¶
1. Ensure there are changelog fragments for changes (see Changelog Management above)
2. Run the Release workflow:
- Go to the GitHub repository Actions tab
- Select "Release new version" workflow
- Click "Run workflow"
- Choose the version bump type:
patch
,minor
, ormajor
The release workflow will automatically:
- Calculate the next version number
- Generate changelog from fragments using towncrier
- Commit the updated CHANGES.md
- Create and push a git tag
- Create a GitHub release with release notes
3. Deploy to PyPI:
- Go to the GitHub repository Actions tab
- Select "Publish to PyPI" workflow
- Click "Run workflow"
- Confirm the deployment
Deploy Manually (Alternative)¶
If you need to deploy without using the GitHub Actions workflow:
1. Install dependencies:
2. Get next version number:
# Replace 'patch' with 'minor' or 'major' as needed
export VERSION=$(python -m includecontents.next_version patch)
echo "Next version: $VERSION"
3. Generate release notes:
4. Build full changelog:
5. Commit changelog and create tag:
git config user.name "Your Name"
git config user.email "your.email@example.com"
git commit -am "Update CHANGES for $VERSION"
git tag "v$VERSION" --file=/tmp/changes.txt --cleanup=whitespace
git push --follow-tags
6. Create GitHub release:
7. Deploy to PyPI:
# Ensure you're on the release version
python -m includecontents.next_version
# Publish to PyPI
pdm publish
Manual Deployment
Manual deployment bypasses the automated checks and should only be used in exceptional circumstances. The GitHub Actions workflow is the preferred method.
Release Checklist¶
- [ ] All tests pass
- [ ] Documentation is updated
- [ ] Changelog fragment created in
changes/
directory - [ ] "Release new version" workflow completed successfully
- [ ] GitHub release created with correct version and notes
- [ ] "Publish to PyPI" workflow completed successfully
- [ ] Package available on PyPI
- [ ] Release announcement (if applicable)
Changelog¶
This page shows the complete changelog for Django IncludeContents.
The full changelog is maintained in CHANGES.md and is automatically generated using towncrier.
Latest Changes¶
Change Log¶
This log shows interesting changes that happen for each release of django-includecontents
.
Version 2.4.1 (2025-07-24)¶
Bugfixes¶
- Fix object passing in component attributes to preserve actual objects instead of string representations when using pure variable syntax like
deck="{{ deck }}"
.
Version 2.4 (2025-07-24)¶
Features¶
- Add support for JavaScript framework event attributes like
@click
,v-on:
,x-on:
, and:
(binding shorthand) in component attributes - Add support for mixed content in component attributes, allowing combinations of static text and Django template syntax (e.g.,
class="btn {{ variant }}"
,href="/products/{{ id }}/"
, and even template tags likeclass="{% if active %}active{% endif %}"
).
Version 2.3 (2025-07-23)¶
Features¶
- HTML-based components now have access to all context variables provided by context processors, not just the request object and CSRF token
This ensures consistent behavior between HTML components and regular Django templates.
Version 2.2 (2025-07-22)¶
Features¶
- Support multiple space-separated values in enum props (e.g.,
variant="primary icon"
) to enable combining visual modifiers.
Bugfixes¶
- Fix parsing of multiline closing tags (e.g.,
</include:item\n>
) in HTML component syntax.
Version 2.1.1 (2025-07-02)¶
Bugfixes¶
- Fixed self-closing component tags within nested components incorrectly incrementing the nesting level, causing "Unclosed tag" errors.
Version 2.1 (2025-07-02)¶
Features¶
- Add Django template tag support in component attributes. Component attributes now fully support Django template syntax including
{% url %}
,{{ variables }}
,{% if %}
conditionals, and all other template tags.
<include:ui-button
variant="primary"
href="{% url 'settings' %}"
class="btn {% if large %}btn-lg{% endif %}"
>
Save Settings
</include:ui-button>
Bugfixes¶
- Fix duplicate content block names error when nesting components with same named content blocks
Version 2.0 (2025-07-01)¶
Features¶
- Add HTML-style
<content:name>
syntax for named content blocks in components. This provides a more HTML-consistent alternative to{% contents %}
tags while maintaining full backwards compatibility. - Add class prepend syntax for component attrs.
Classes can now be prepended with {% attrs class="card &" %}
syntax.
- Append
" &"
to prepend component classes before user-provided classes - Complements existing
"& "
syntax which appends after user classes - Useful when CSS specificity or utility class ordering matters
- Add enum validation for component props.
Props can now be defined with allowed values: {# props variant=primary,secondary,accent #}
- Validates prop values against the allowed list
- Sets both the prop value and a camelCased boolean (e.g.,
variant="primary"
andvariantPrimary=True
) - Optional enums start with empty:
size=,small,medium,large
- Hyphens are camelCased:
dark-mode
→variantDarkMode
- Add {% wrapif %} template tag for conditional wrapping.
The new {% wrapif %}
tag provides a clean way to conditionally wrap content with HTML elements:
- Shorthand syntax:
{% wrapif condition then "tag" attr=value %}content{% endwrapif %}
- Full template syntax: Supports
{% contents %}
blocks for complex wrappers - Multiple conditions:
{% wrapelif %}
and{% wrapelse %}
for if/elif/else patterns - Complex conditions: Inherits all Django template operators (and, or, not, comparisons, in)
- Multiple named contents: Support for multiple content blocks in full syntax
- Attribute handling: Proper escaping and boolean attribute support
This reduces template boilerplate and improves readability when conditionally wrapping content.
- Added |not
template filter for negating boolean values in conditional class attributes
Version 1.2.1 (2024-11-19)¶
Bugfixes¶
- Make csrf_token work from within components
Version 1.2 (2024-11-12)¶
Features¶
- Added support for Django-style template variables in component attributes:
title="{{ myTitle }}"
. The old styletitle={myTitle}
is still supported but will be deprecated in a future version.
Bugfixes¶
- Short-hand syntax props weren't being taken into account by the required attrs check.
Version 1.1.1 (2024-07-25)¶
Bugfixes¶
- Fix a bug where the component context wasn't being set correctly, especially noticeable inside of a loop. (5)
Version 1.1 (2024-06-03)¶
Bugfixes¶
- Allow attributes with dashes which don't have values. For example,
<include:foo x-data />
. (1)
Version 1.0 (2024-05-16)¶
Features¶
- Update the template engine location so that it will be picked up as the standard Django engine when replaced.
Improved Documentation¶
- Fix some grammar.
- Add a note about how to workaround Prettier stripping AlpineJS'
x-data
quotes.
Deprecations and Removals¶
- Since the template engine location has changed, any users of pre 1.0 versions will need to update their Django settings to point to the new location:
Version 0.8 (2024-05-09)¶
Features¶
- Add shorthand attribute syntax (
<include:foo {title}>
).
Bugfixes¶
- Fix component context isolation.
Version 0.7 (2024-05-01)¶
Features¶
- Allow self-closing tags. For example,
<include:foo />
. - Handle > inside
<include:
tags. - Allow kebab-case attributes. For example,
<include:foo x-data="bar" />
.
Improved Documentation¶
- Add a note about
pretier-plugin-jinja-template
. - Readme improvements.