{"id":34062967,"url":"https://github.com/bmampaey/django-boundfield-renderer","last_synced_at":"2026-05-25T20:37:20.145Z","repository":{"id":57419161,"uuid":"173953283","full_name":"bmampaey/django-boundfield-renderer","owner":"bmampaey","description":"A rendering engine for Django forms using templatetags","archived":false,"fork":false,"pushed_at":"2019-06-24T14:38:17.000Z","size":89,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"master","last_synced_at":"2026-02-27T04:12:50.235Z","etag":null,"topics":["django","form","template-library"],"latest_commit_sha":null,"homepage":"","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/bmampaey.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2019-03-05T13:37:53.000Z","updated_at":"2023-12-11T15:01:51.000Z","dependencies_parsed_at":"2022-09-03T09:51:12.848Z","dependency_job_id":null,"html_url":"https://github.com/bmampaey/django-boundfield-renderer","commit_stats":null,"previous_names":[],"tags_count":4,"template":false,"template_full_name":null,"purl":"pkg:github/bmampaey/django-boundfield-renderer","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bmampaey%2Fdjango-boundfield-renderer","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bmampaey%2Fdjango-boundfield-renderer/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bmampaey%2Fdjango-boundfield-renderer/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bmampaey%2Fdjango-boundfield-renderer/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/bmampaey","download_url":"https://codeload.github.com/bmampaey/django-boundfield-renderer/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bmampaey%2Fdjango-boundfield-renderer/sbom","scorecard":{"id":245288,"data":{"date":"2025-08-11","repo":{"name":"github.com/bmampaey/django-boundfield-renderer","commit":"b56eecb16bb8f7a47667aec8baf1ffcc0cd5b776"},"scorecard":{"version":"v5.2.1-40-gf6ed084d","commit":"f6ed084d17c9236477efd66e5b258b9d4cc7b389"},"score":3,"checks":[{"name":"Code-Review","score":0,"reason":"Found 0/30 approved changesets -- score normalized to 0","details":null,"documentation":{"short":"Determines if the project requires human code review before pull requests (aka merge requests) are merged.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#code-review"}},{"name":"Maintained","score":0,"reason":"0 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 0","details":null,"documentation":{"short":"Determines if the project is \"actively maintained\".","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#maintained"}},{"name":"Token-Permissions","score":-1,"reason":"No tokens found","details":null,"documentation":{"short":"Determines if the project's workflows follow the principle of least privilege.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#token-permissions"}},{"name":"Packaging","score":-1,"reason":"packaging workflow not detected","details":["Warn: no GitHub/GitLab publishing workflow detected."],"documentation":{"short":"Determines if the project is published as a package that others can easily download, install, easily update, and uninstall.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#packaging"}},{"name":"Pinned-Dependencies","score":-1,"reason":"no dependencies found","details":null,"documentation":{"short":"Determines if the project has declared and pinned the dependencies of its build process.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#pinned-dependencies"}},{"name":"SAST","score":0,"reason":"no SAST tool detected","details":["Warn: no pull requests merged into dev branch"],"documentation":{"short":"Determines if the project uses static code analysis.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#sast"}},{"name":"Dangerous-Workflow","score":-1,"reason":"no workflows found","details":null,"documentation":{"short":"Determines if the project's GitHub Action workflows avoid dangerous patterns.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#dangerous-workflow"}},{"name":"Binary-Artifacts","score":10,"reason":"no binaries found in the repo","details":null,"documentation":{"short":"Determines if the project has generated executable (binary) artifacts in the source repository.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#binary-artifacts"}},{"name":"CII-Best-Practices","score":0,"reason":"no effort to earn an OpenSSF best practices badge detected","details":null,"documentation":{"short":"Determines if the project has an OpenSSF (formerly CII) Best Practices Badge.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#cii-best-practices"}},{"name":"Security-Policy","score":0,"reason":"security policy file not detected","details":["Warn: no security policy file detected","Warn: no security file to analyze","Warn: no security file to analyze","Warn: no security file to analyze"],"documentation":{"short":"Determines if the project has published a security policy.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#security-policy"}},{"name":"Vulnerabilities","score":10,"reason":"0 existing vulnerabilities detected","details":null,"documentation":{"short":"Determines if the project has open, known unfixed vulnerabilities.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#vulnerabilities"}},{"name":"Fuzzing","score":0,"reason":"project is not fuzzed","details":["Warn: no fuzzer integrations found"],"documentation":{"short":"Determines if the project uses fuzzing.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#fuzzing"}},{"name":"License","score":10,"reason":"license file detected","details":["Info: project has a license file: LICENSE:0","Info: FSF or OSI recognized license: MIT License: LICENSE:0"],"documentation":{"short":"Determines if the project has defined a license.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#license"}},{"name":"Signed-Releases","score":-1,"reason":"no releases found","details":null,"documentation":{"short":"Determines if the project cryptographically signs release artifacts.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#signed-releases"}},{"name":"Branch-Protection","score":0,"reason":"branch protection not enabled on development/release branches","details":["Warn: branch protection not enabled for branch 'master'"],"documentation":{"short":"Determines if the default and release branches are protected with GitHub's branch protection settings.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#branch-protection"}}]},"last_synced_at":"2025-08-17T07:29:56.876Z","repository_id":57419161,"created_at":"2025-08-17T07:29:56.876Z","updated_at":"2025-08-17T07:29:56.876Z"},"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":33492976,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-25T14:31:05.219Z","status":"ssl_error","status_checked_at":"2026-05-25T14:31:02.878Z","response_time":57,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["django","form","template-library"],"created_at":"2025-12-14T05:02:13.042Z","updated_at":"2026-05-25T20:37:20.139Z","avatar_url":"https://github.com/bmampaey.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"# django-boundfield-renderer\nA rendering engine for Django forms using templatetags\n\n## Preamble\nThere are already many libraries to render Django forms in templates, including the default Form methods as_p(), as_ul(), as_table(). Unfortunately, none of them (that I have encountered at least) apply strictly the concept of separation of form and function, or business logic from presentation, etc. Django has made a step into the right direction by using templates for the widgets, but the entirety of a field rendering is still partially done in python code. For example, if the developer wishes to put the label after the checkbox, he still has to write python, instead of redefining a template.\n\nThis library defines one or more registry, that associate a rendering function (called renderer) for each form field class. That rendering function is made available through the templatetag `renderer`.\n\n## Installation\nAdd `'boundfield_renderer'` to your INSTALLED_APPS setting so Django can find the templatetag `renderer`.\n\n## Basic steps to render a Django Form\n### Create a registry and register the renderers for the field classes\nFor example, in the file *path/to/my_registry.py*\n```python\nfrom django import forms\nfrom django.template.loader import get_template\nfrom boundfield_renderer import RendererRegistry\n\n# Create the registry\nregistry = RendererRegistry()\n\n# Define a renderer function for a field class, for example the CharField\n# This can be as simple as the render method of a template\ntemplate_render = get_template('mytemplates/char_field.html').render\n\n# Register the renderer for the field class in the registry\n# Either by setting it directly on the registry\nregistry[forms.CharField] = template_render\n\n# Or by using the register method as a decorator on a field class definition\n@registry.register(get_template('mytemplates/my_field.html').render)\nclass MyField(forms.Field):\n\tpass\n\n```\n\nThe file *mytemplates/char_field.html* could be as simple as this:\n```html\n\u003clabel for=\"{{ id }}\"\u003e{{label}}\n\u003cinput type=\"text\" id=\"{{ id }}\" name=\"{{ name }}\" value=\"{{ value }}\"\u003e\n\u003c/label\u003e\n\u003cp\u003e{{ help_text }}\u003c/p\u003e\n\u003cul\u003e\n{% for error in errors %}\u003cli\u003e{{ error }}\u003c/li\u003e{% endfor %}\n\u003c/ul\u003e\n```\n\n### Write a template that renders the form using the `renderer` template tag\nFor example, in the file *mytemplates/my_form.html*\n```html\n{% load boundfield_renderer %}\n\u003chtml\u003e\n\t\u003cbody\u003e\n\t\t\u003cform\u003e\n\t\t\t{% for boundfield in form %}\n\t\t\t{% renderer boundfield 'path.to.my_registry.registry' %}\n\t\t\t{% endfor %}\n\t\t\t\u003cinput type=\"submit\" value=\"Send\"\u003e\n\t\t\u003c/form\u003e\n\t\u003c/body\u003e\n\u003c/html\u003e\n```\n\n## Renderer function\nA renderer function does not have to be a template render method, it can be any method that returns a string. (Must it be marked safe?) It is passed a single parameter that is a dict (called context) with the following key/values:\n\n  * __form__: The form the field belongs to\n  * __boundfield__: The bound field itself\n  * __html_name__: The HTML name attribute for the field\n  * __value__: The current value of the field\n  * __label__: The label of the field\n  * __id__: The id for the label of the field\n  * __help_text__: The help_text of the field\n  * __errors__: The list of Validation errors for the field\n  * __disabled__: True if the field is disabled\n  * __is_hidden__: True if the field is hidden\n  * __required__: True if the field is required\n\n\n## Resolution of renderer\nTo find a renderer for a field class, we follow the MRO order of the field class until we find a renderer registered for that subclass. For example:\n\n```python\nfrom django.core.exceptions import ValidationError\n\n# Override CharField to add some extra clean, BUT DO NOT register a new renderer\nclass MyCharField(forms.CharField):\n\tdef clean(self, value):\n\t\tif value == 'Spanish Inquisition':\n\t\t\traise ValidationError('I was not expecting the Spanish Inquisition!')\n\t\telse:\n\t\t\treturn super().clean(value)\n\n# Override MyCharField AND register a new renderer\n@registry.register(get_template('mytemplates/my_other_char_field.html').render)\nclass MyOtherCharField(MyCharField):\n\tpass\n\n```\n\nIn the first case, the renderer used will be the one we registered for the CharField earlier (template *mytemplates/char_field.html*). In the second, the renderer used will be the one we registered for MyOtherCharField (template *mytemplates/my_other_char_field.html*)\n\nIf no renderer is found, a ValueError is raised.\n\n## *renderer* templatetag\nThe renderer templatetag takes a boundfield as the first parameter. It can also take as a second optional parameter a registry object or the full dotted path to a registry object.\n\nIf no registry is specified, it will use the default registry as defined in the settings as DEFAULT_BOUNDFIELD_RENDERER_REGISTRY.\n\n\nFor our example this would be:\n```python\nDEFAULT_BOUNDFIELD_RENDERER_REGISTRY = 'path.to.my_registry.registry'\n```\n\nFinally, the renderer tag can take optional keyword parameters that will be added to the context.\n\nIf we reuse our previous example form template *mytemplates/my_form.html*, we could change the context for a particular field \"starwberry\" to add a context variable \"css_classes\" with a value of \"forever\":\n\n```html\n{% load boundfield_renderer %}\n\u003chtml\u003e\n\t\u003cbody\u003e\n\t\t\u003cform\u003e\n\t\t\t{% for boundfield in form %}\n\t\t\t{% if boundfield.name == 'strawberry' %}\n\t\t\t{% renderer boundfield 'path.to.my_registry.registry' css_classes='forever' %}\n\t\t\t{% else %}\n\t\t\t{% renderer boundfield 'path.to.my_registry.registry' %}\n\t\t\t{% endif %}\n\t\t\t{% endfor %}\n\t\t\t\u003cinput type=\"submit\" value=\"Send\"\u003e\n\t\t\u003c/form\u003e\n\t\u003c/body\u003e\n\u003c/html\u003e\n```\n\n## Note on renderer registration\nThe code that registers the renderer for a form field class must be executed by Django before the `renderer` templatetag is called.\n\nPractically, this can be achieved by registering the renderers in the same file where the registry is defined, or in the files where the form field class are defined (for example using the *register* decorator)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbmampaey%2Fdjango-boundfield-renderer","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fbmampaey%2Fdjango-boundfield-renderer","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbmampaey%2Fdjango-boundfield-renderer/lists"}