[](https://pypi.org/project/tbxforms/)
[](https://www.npmjs.com/package/tbxforms) [](https://pypi.org/project/tbxforms/) [](https://github.com/torchbox/tbxforms/actions/workflows/test.yml)
# Torchbox Forms
A Torchbox-flavoured template pack for [django-crispy-forms](https://github.com/django-crispy-forms/django-crispy-forms), adapted from [crispy-forms-gds](https://github.com/wildfish/crispy-forms-gds).
Out of the box, forms created with `tbxforms` will look like the
[GOV.UK Design System](https://design-system.service.gov.uk/), though many
variables can be customised.
## Requirements
- python `>=3.8.1,<4.0`
- Django `>=3.2`
- django-crispy-forms `>=2.1,<3.0`
- wagtail `>=2.15` if using `WagtailBaseForm`
- sass `>=1.33.0` if building the sass yourself
<!-- prettier-ignore-start -->
> [!NOTE]
> **[govuk-frontend](https://github.com/alphagov/govuk-frontend) will
> not, and does not need to, be installed to use this package.**
>
> All form-related styles from `govuk-frontend==5.4.1` have been
> copied into this project with the prepended "govuk-" replaced with
> "tbxforms-", e.g. `.govuk-button` to `.tbxforms-button` and
> `@mixin govuk-clearfix` to `@mixin tbxforms-clearfix`.
<!-- prettier-ignore-end -->
For non-government projects, installing the complete GOV.UK Frontend package
unnecessarily increases the bundle size as we only need form-related styles.
For government projects, this increases the bundle size as both `tbxforms` and
`govuk-frontend` must be installed. However, these projects are less common, so
they are not prioritised.
## Installation
You must install both the Python package and the NPM package.
### Install the Python package
Install using pip:
```bash
pip install tbxforms
```
Add `django-crispy-forms` and `tbxforms` to your installed apps:
```python
INSTALLED_APPS = [
# ...
'crispy_forms', # django-crispy-forms
'tbxforms',
]
```
Now add the following settings to tell `django-crispy-forms` to use `tbxforms`:
```python
CRISPY_ALLOWED_TEMPLATE_PACKS = ["tbxforms"]
CRISPY_TEMPLATE_PACK = "tbxforms"
```
### Install the NPM package
Install using NPM:
```bash
npm install tbxforms
```
Note: This package uses the `Element.closest`, `NodeList.forEach`, and
`Array.includes` APIs. You will need to install and configure polyfills for
legacy browser support if you need to.
Instantiate your forms:
```javascript
import TbxForms from 'tbxforms';
document.addEventListener('DOMContentLoaded', () => {
for (const form of document.querySelectorAll(TbxForms.selector())) {
new TbxForms(form);
}
});
```
Import the styles into your project...
...Either as CSS without any customisations:
```scss
@use 'node_modules/tbxforms/dist/style.css';
```
...Or as Sass to customise variables:
```scss
@use 'node_modules/tbxforms/tbxforms.scss' with (
$tbxforms-text-colour: #000,
$tbxforms-error-colour: #f00,
);
```
#### Add button styles
`tbxforms` provides out-of-the-box GOV.UK Design System styles for everything
except buttons, as styles for these probably exist within your project.
You will need to write button styles for the following classes:
1. `.tbxforms-button`
2. `.tbxforms-button.tbxforms-button--primary`
3. `.tbxforms-button.tbxforms-button--secondary`
4. `.tbxforms-button.tbxforms-button--warning`
## Usage
`tbxforms` can be used for coded Django forms and editor-controlled Wagtail forms.
### Django forms
All forms must inherit the `TbxFormsMixin` mixin, as well as specifying a Django base form class (e.g. `forms.Form` or `forms.ModelForm`)
```python
from django import forms
from tbxforms.forms import TbxFormsMixin
class ExampleForm(TbxFormsMixin, forms.Form):
...
class ExampleModelForm(TbxFormsMixin, forms.ModelForm):
...
```
### Wagtail forms
#### Create or update a Wagtail form
Wagtail forms must inherit from `TbxFormsMixin` and `WagtailBaseForm`.
```python
from wagtail.contrib.forms.forms import BaseForm as WagtailBaseForm
from tbxforms.forms import TbxFormsMixin
class ExampleWagtailForm(TbxFormsMixin, WagtailBaseForm):
...
```
#### Instruct a Wagtail Page model to use your form
**In your form definitions** (e.g. forms.py):
```python
from tbxforms.forms import BaseWagtailFormBuilder as TbxFormsBaseWagtailFormBuilder
from path.to.your.forms import ExampleWagtailForm
class WagtailFormBuilder(TbxFormsBaseWagtailFormBuilder):
def get_form_class(self):
return type(str("WagtailForm"), (ExampleWagtailForm,), self.formfields)
```
**And in your form page models** (e.g. models.py):
```python
from path.to.your.forms import WagtailFormBuilder
class ExampleFormPage(...):
...
form_builder = WagtailFormBuilder
...
```
### Render a form
Just like Django Crispy Forms, you need to pass your form object to the
`{% crispy ... %}` template tag, e.g.:
```html
{% load crispy_forms_tags %}
<html>
<body>
{% crispy your_sexy_form %}
</body>
</html>
```
### `FormHelper`s
A [FormHelper](https://django-crispy-forms.readthedocs.io/en/latest/form_helper.html)
allows you to alter the rendering behaviour of forms.
Every form that inherits from `TbxFormsMixin` (i.e. every form within `tbxforms`)
will have a `FormHelper` with the following default attributes:
- `html5_required = True`
- `label_size = Size.MEDIUM`
- `legend_size = Size.MEDIUM`
- `form_error_title = _("There is a problem with your submission")`
- Plus everything from [django-crispy-forms' default attributes](https://django-crispy-forms.readthedocs.io/en/latest/form_helper.html).
These can be changed during instantiation or [on the go](https://django-crispy-forms.readthedocs.io/en/latest/dynamic_layouts.html) - examples below.
#### Add a submit button
Submit buttons are not automatically added to forms. To add one, you can extend
the `form.helper.layout` (examples below).
Extend during instantiation:
```python
from django import forms
from tbxforms.forms import TbxFormsMixin
from tbxforms.layout import Button
class YourSexyForm(TbxFormsMixin, forms.Form):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.helper.layout.extend([
Button.primary(
name="submit",
type="submit",
value="Submit",
)
])
```
Or afterwards:
```python
from tbxforms.layout import Button
form = YourSexyForm()
form.helper.layout.extend([
Button.primary(
name="submit",
type="submit",
value="Submit",
)
])
```
### Conditionally show/hide fields
`tbxforms` can show/hide parts of the `layout` depending on a given value. For
example, you could show an email address field only when the user
chooses to sign up to a newsletter (examples below).
You can apply this logic to `field`, `div`, and `fieldset` elements.
**Field example:**
```python
from django import forms
from django.core.exceptions import ValidationError
from tbxforms.choices import Choice
from tbxforms.forms import TbxFormsMixin
from tbxforms.layout import Field, Layout
class ExampleForm(TbxFormsMixin, forms.Form):
NEWSLETTER_CHOICES = (
Choice("yes", "Yes please", hint="Receive occasional email newsletters."),
Choice("no", "No thanks"),
)
newsletter_signup = forms.ChoiceField(
choices=NEWSLETTER_CHOICES
)
email = forms.EmailField(
widget=forms.EmailInput(required=False)
)
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.helper.layout = Layout(
# Add our newsletter sign-up field.
Field.text("newsletter_signup"),
# Add our email field and define the conditional logic.
Field.text(
"email",
data_conditional={
"field_name": "newsletter_signup", # Field to inspect.
"values": ["yes"], # Value(s) to cause this field to show.
},
),
)
```
**Container example:**
When you have multiple fields/elements that you want to show/hide together, you
can use the exact same `data_conditional` definition as above but on a `div` or
`fieldset` element, e.g.:
```python
from tbxforms.layout import HTML, Div, Field, Layout
Layout(
Div(
HTML("<p>Some relevant text.</p>"),
Field.text("some_other_field"),
Field.text("email"),
data_conditional={
"field_name": "newsletter_signup",
"values": ["yes"],
},
),
)
```
#### Show conditional fields as required
Conditional fields must be optional (`required=False`) as they are not always
visible, but it can be useful to show them as required to the user.
To do this, use the `conditional_fields_to_show_as_required()` method:
```python
from django import forms
from django.core.exceptions import ValidationError
from tbxforms.choices import Choice
from tbxforms.forms import TbxFormsMixin
from tbxforms.layout import Field, Layout
class ExampleForm(TbxFormsMixin, forms.Form):
NEWSLETTER_CHOICES = (
Choice("yes", "Yes please", hint="Receive occasional email newsletters."),
Choice("no", "No thanks"),
)
newsletter_signup = forms.ChoiceField(
choices=NEWSLETTER_CHOICES
)
email = forms.EmailField(
widget=forms.EmailInput(required=False)
)
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.helper.layout = Layout(
# Add our newsletter sign-up field.
Field.text("newsletter_signup"),
# Add our email field and define the conditional logic.
Field.text(
"email",
data_conditional={
"field_name": "newsletter_signup", # Field to inspect.
"values": ["yes"], # Value(s) to cause this field to show.
},
),
)
@staticmethod
def conditional_fields_to_show_as_required() -> [str]:
# Non-required fields that should show as required to the user.
return [
"email",
]
def clean(self):
cleaned_data = super().clean()
newsletter_signup = cleaned_data.get("newsletter_signup")
email = cleaned_data.get("email")
# Fields included within `conditional_fields_to_show_as_required()` will
# be shown as required but not marked as required. Therefore, we need to
# write our own check to enforce the value exists.
if newsletter_signup == "yes" and not email:
raise ValidationError(
{
"email": "This field is required.",
}
)
return cleaned_data
```
## Customising behaviour
### Highlight required fields instead of optional ones
If `TBXFORMS_HIGHLIGHT_REQUIRED_FIELDS=False` (or unset), optional fields will
have "(optional)" appended to their labels. This is the default behaviour and
recommended by GDS.
If `TBXFORMS_HIGHLIGHT_REQUIRED_FIELDS=True`, required fields will have an
asterisk appended to their labels and optional fields will not be highlighted.
You can also style these markers by targeting these CSS classes:
- `.tbxforms-field_marker--required`
- `.tbxforms-field_marker--optional`
### Change the default label and legend classes
Possible values for the `label_size` and `legend_size`:
1. `SMALL`
2. `MEDIUM` (default)
3. `LARGE`
4. `EXTRA_LARGE`
# Further reading
- Download the [PyPI package](http://pypi.python.org/pypi/tbxforms)
- Download the [NPM package](https://www.npmjs.com/package/tbxforms)
- Learn more about [Django Crispy Forms](https://django-crispy-forms.readthedocs.io/en/latest/)
- Learn more about [Crispy Forms GDS](https://github.com/wildfish/crispy-forms-gds)
- Learn more about [GOV.UK Design System](https://design-system.service.gov.uk/)
Raw data
{
"_id": null,
"home_page": "https://github.com/torchbox/tbxforms/",
"name": "tbxforms",
"maintainer": null,
"docs_url": null,
"requires_python": "<4.0,>=3.8.1",
"maintainer_email": null,
"keywords": "crispy, django, django crispy forms, django crispy form, forms, gds, tbxforms, wagtail, wagtail forms, wagtail form",
"author": "Kyle Bayliss",
"author_email": "kyle.bayliss@torchbox.com",
"download_url": "https://files.pythonhosted.org/packages/20/62/de5cb046f3b8fc08270f58167843692da200a9e0abb695a7b43d619334cf/tbxforms-4.0.0.tar.gz",
"platform": null,
"description": "[](https://pypi.org/project/tbxforms/)\n[](https://www.npmjs.com/package/tbxforms) [](https://pypi.org/project/tbxforms/) [](https://github.com/torchbox/tbxforms/actions/workflows/test.yml)\n\n# Torchbox Forms\n\nA Torchbox-flavoured template pack for [django-crispy-forms](https://github.com/django-crispy-forms/django-crispy-forms), adapted from [crispy-forms-gds](https://github.com/wildfish/crispy-forms-gds).\n\nOut of the box, forms created with `tbxforms` will look like the\n[GOV.UK Design System](https://design-system.service.gov.uk/), though many\nvariables can be customised.\n\n## Requirements\n\n- python `>=3.8.1,<4.0`\n- Django `>=3.2`\n- django-crispy-forms `>=2.1,<3.0`\n- wagtail `>=2.15` if using `WagtailBaseForm`\n- sass `>=1.33.0` if building the sass yourself\n\n<!-- prettier-ignore-start -->\n> [!NOTE]\n> **[govuk-frontend](https://github.com/alphagov/govuk-frontend) will\n> not, and does not need to, be installed to use this package.**\n>\n> All form-related styles from `govuk-frontend==5.4.1` have been\n> copied into this project with the prepended \"govuk-\" replaced with\n> \"tbxforms-\", e.g. `.govuk-button` to `.tbxforms-button` and\n> `@mixin govuk-clearfix` to `@mixin tbxforms-clearfix`.\n<!-- prettier-ignore-end -->\n\nFor non-government projects, installing the complete GOV.UK Frontend package\nunnecessarily increases the bundle size as we only need form-related styles.\n\nFor government projects, this increases the bundle size as both `tbxforms` and\n`govuk-frontend` must be installed. However, these projects are less common, so\nthey are not prioritised.\n\n## Installation\n\nYou must install both the Python package and the NPM package.\n\n### Install the Python package\n\nInstall using pip:\n\n```bash\npip install tbxforms\n```\n\nAdd `django-crispy-forms` and `tbxforms` to your installed apps:\n\n```python\nINSTALLED_APPS = [\n # ...\n 'crispy_forms', # django-crispy-forms\n 'tbxforms',\n]\n```\n\nNow add the following settings to tell `django-crispy-forms` to use `tbxforms`:\n\n```python\nCRISPY_ALLOWED_TEMPLATE_PACKS = [\"tbxforms\"]\nCRISPY_TEMPLATE_PACK = \"tbxforms\"\n```\n\n### Install the NPM package\n\nInstall using NPM:\n\n```bash\nnpm install tbxforms\n```\n\nNote: This package uses the `Element.closest`, `NodeList.forEach`, and\n`Array.includes` APIs. You will need to install and configure polyfills for\nlegacy browser support if you need to.\n\nInstantiate your forms:\n\n```javascript\nimport TbxForms from 'tbxforms';\n\ndocument.addEventListener('DOMContentLoaded', () => {\n for (const form of document.querySelectorAll(TbxForms.selector())) {\n new TbxForms(form);\n }\n});\n```\n\nImport the styles into your project...\n\n...Either as CSS without any customisations:\n\n```scss\n@use 'node_modules/tbxforms/dist/style.css';\n```\n\n...Or as Sass to customise variables:\n\n```scss\n@use 'node_modules/tbxforms/tbxforms.scss' with (\n $tbxforms-text-colour: #000,\n $tbxforms-error-colour: #f00,\n);\n```\n\n#### Add button styles\n\n`tbxforms` provides out-of-the-box GOV.UK Design System styles for everything\nexcept buttons, as styles for these probably exist within your project.\n\nYou will need to write button styles for the following classes:\n\n1. `.tbxforms-button`\n2. `.tbxforms-button.tbxforms-button--primary`\n3. `.tbxforms-button.tbxforms-button--secondary`\n4. `.tbxforms-button.tbxforms-button--warning`\n\n## Usage\n\n`tbxforms` can be used for coded Django forms and editor-controlled Wagtail forms.\n\n### Django forms\n\nAll forms must inherit the `TbxFormsMixin` mixin, as well as specifying a Django base form class (e.g. `forms.Form` or `forms.ModelForm`)\n\n```python\nfrom django import forms\nfrom tbxforms.forms import TbxFormsMixin\n\nclass ExampleForm(TbxFormsMixin, forms.Form):\n ...\n\nclass ExampleModelForm(TbxFormsMixin, forms.ModelForm):\n ...\n```\n\n### Wagtail forms\n\n#### Create or update a Wagtail form\n\nWagtail forms must inherit from `TbxFormsMixin` and `WagtailBaseForm`.\n\n```python\nfrom wagtail.contrib.forms.forms import BaseForm as WagtailBaseForm\nfrom tbxforms.forms import TbxFormsMixin\n\nclass ExampleWagtailForm(TbxFormsMixin, WagtailBaseForm):\n ...\n```\n\n#### Instruct a Wagtail Page model to use your form\n\n**In your form definitions** (e.g. forms.py):\n\n```python\nfrom tbxforms.forms import BaseWagtailFormBuilder as TbxFormsBaseWagtailFormBuilder\nfrom path.to.your.forms import ExampleWagtailForm\n\nclass WagtailFormBuilder(TbxFormsBaseWagtailFormBuilder):\n def get_form_class(self):\n return type(str(\"WagtailForm\"), (ExampleWagtailForm,), self.formfields)\n```\n\n**And in your form page models** (e.g. models.py):\n\n```python\nfrom path.to.your.forms import WagtailFormBuilder\n\nclass ExampleFormPage(...):\n ...\n form_builder = WagtailFormBuilder\n ...\n```\n\n### Render a form\n\nJust like Django Crispy Forms, you need to pass your form object to the\n`{% crispy ... %}` template tag, e.g.:\n\n```html\n{% load crispy_forms_tags %}\n\n<html>\n <body>\n {% crispy your_sexy_form %}\n </body>\n</html>\n```\n\n### `FormHelper`s\n\nA [FormHelper](https://django-crispy-forms.readthedocs.io/en/latest/form_helper.html)\nallows you to alter the rendering behaviour of forms.\n\nEvery form that inherits from `TbxFormsMixin` (i.e. every form within `tbxforms`)\nwill have a `FormHelper` with the following default attributes:\n\n- `html5_required = True`\n- `label_size = Size.MEDIUM`\n- `legend_size = Size.MEDIUM`\n- `form_error_title = _(\"There is a problem with your submission\")`\n- Plus everything from [django-crispy-forms' default attributes](https://django-crispy-forms.readthedocs.io/en/latest/form_helper.html).\n\nThese can be changed during instantiation or [on the go](https://django-crispy-forms.readthedocs.io/en/latest/dynamic_layouts.html) - examples below.\n\n#### Add a submit button\n\nSubmit buttons are not automatically added to forms. To add one, you can extend\nthe `form.helper.layout` (examples below).\n\nExtend during instantiation:\n\n```python\nfrom django import forms\nfrom tbxforms.forms import TbxFormsMixin\nfrom tbxforms.layout import Button\n\nclass YourSexyForm(TbxFormsMixin, forms.Form):\n\n def __init__(self, *args, **kwargs):\n super().__init__(*args, **kwargs)\n self.helper.layout.extend([\n Button.primary(\n name=\"submit\",\n type=\"submit\",\n value=\"Submit\",\n )\n ])\n```\n\nOr afterwards:\n\n```python\nfrom tbxforms.layout import Button\n\nform = YourSexyForm()\nform.helper.layout.extend([\n Button.primary(\n name=\"submit\",\n type=\"submit\",\n value=\"Submit\",\n )\n])\n```\n\n### Conditionally show/hide fields\n\n`tbxforms` can show/hide parts of the `layout` depending on a given value. For\nexample, you could show an email address field only when the user\nchooses to sign up to a newsletter (examples below).\n\nYou can apply this logic to `field`, `div`, and `fieldset` elements.\n\n**Field example:**\n\n```python\nfrom django import forms\nfrom django.core.exceptions import ValidationError\nfrom tbxforms.choices import Choice\nfrom tbxforms.forms import TbxFormsMixin\nfrom tbxforms.layout import Field, Layout\n\nclass ExampleForm(TbxFormsMixin, forms.Form):\n NEWSLETTER_CHOICES = (\n Choice(\"yes\", \"Yes please\", hint=\"Receive occasional email newsletters.\"),\n Choice(\"no\", \"No thanks\"),\n )\n\n newsletter_signup = forms.ChoiceField(\n choices=NEWSLETTER_CHOICES\n )\n\n email = forms.EmailField(\n widget=forms.EmailInput(required=False)\n )\n\n def __init__(self, *args, **kwargs):\n super().__init__(*args, **kwargs)\n self.helper.layout = Layout(\n # Add our newsletter sign-up field.\n Field.text(\"newsletter_signup\"),\n\n # Add our email field and define the conditional logic.\n Field.text(\n \"email\",\n data_conditional={\n \"field_name\": \"newsletter_signup\", # Field to inspect.\n \"values\": [\"yes\"], # Value(s) to cause this field to show.\n },\n ),\n )\n\n```\n\n**Container example:**\n\nWhen you have multiple fields/elements that you want to show/hide together, you\ncan use the exact same `data_conditional` definition as above but on a `div` or\n`fieldset` element, e.g.:\n\n```python\nfrom tbxforms.layout import HTML, Div, Field, Layout\n\nLayout(\n Div(\n HTML(\"<p>Some relevant text.</p>\"),\n Field.text(\"some_other_field\"),\n Field.text(\"email\"),\n data_conditional={\n \"field_name\": \"newsletter_signup\",\n \"values\": [\"yes\"],\n },\n ),\n)\n```\n\n#### Show conditional fields as required\n\nConditional fields must be optional (`required=False`) as they are not always\nvisible, but it can be useful to show them as required to the user.\n\nTo do this, use the `conditional_fields_to_show_as_required()` method:\n\n```python\nfrom django import forms\nfrom django.core.exceptions import ValidationError\nfrom tbxforms.choices import Choice\nfrom tbxforms.forms import TbxFormsMixin\nfrom tbxforms.layout import Field, Layout\n\nclass ExampleForm(TbxFormsMixin, forms.Form):\n NEWSLETTER_CHOICES = (\n Choice(\"yes\", \"Yes please\", hint=\"Receive occasional email newsletters.\"),\n Choice(\"no\", \"No thanks\"),\n )\n\n newsletter_signup = forms.ChoiceField(\n choices=NEWSLETTER_CHOICES\n )\n\n email = forms.EmailField(\n widget=forms.EmailInput(required=False)\n )\n\n def __init__(self, *args, **kwargs):\n super().__init__(*args, **kwargs)\n self.helper.layout = Layout(\n # Add our newsletter sign-up field.\n Field.text(\"newsletter_signup\"),\n\n # Add our email field and define the conditional logic.\n Field.text(\n \"email\",\n data_conditional={\n \"field_name\": \"newsletter_signup\", # Field to inspect.\n \"values\": [\"yes\"], # Value(s) to cause this field to show.\n },\n ),\n )\n\n @staticmethod\n def conditional_fields_to_show_as_required() -> [str]:\n # Non-required fields that should show as required to the user.\n return [\n \"email\",\n ]\n\n def clean(self):\n cleaned_data = super().clean()\n newsletter_signup = cleaned_data.get(\"newsletter_signup\")\n email = cleaned_data.get(\"email\")\n\n # Fields included within `conditional_fields_to_show_as_required()` will\n # be shown as required but not marked as required. Therefore, we need to\n # write our own check to enforce the value exists.\n if newsletter_signup == \"yes\" and not email:\n raise ValidationError(\n {\n \"email\": \"This field is required.\",\n }\n )\n\n return cleaned_data\n\n```\n\n## Customising behaviour\n\n### Highlight required fields instead of optional ones\n\nIf `TBXFORMS_HIGHLIGHT_REQUIRED_FIELDS=False` (or unset), optional fields will\nhave \"(optional)\" appended to their labels. This is the default behaviour and\nrecommended by GDS.\n\nIf `TBXFORMS_HIGHLIGHT_REQUIRED_FIELDS=True`, required fields will have an\nasterisk appended to their labels and optional fields will not be highlighted.\n\nYou can also style these markers by targeting these CSS classes:\n\n- `.tbxforms-field_marker--required`\n- `.tbxforms-field_marker--optional`\n\n### Change the default label and legend classes\n\nPossible values for the `label_size` and `legend_size`:\n\n1. `SMALL`\n2. `MEDIUM` (default)\n3. `LARGE`\n4. `EXTRA_LARGE`\n\n# Further reading\n\n- Download the [PyPI package](http://pypi.python.org/pypi/tbxforms)\n- Download the [NPM package](https://www.npmjs.com/package/tbxforms)\n- Learn more about [Django Crispy Forms](https://django-crispy-forms.readthedocs.io/en/latest/)\n- Learn more about [Crispy Forms GDS](https://github.com/wildfish/crispy-forms-gds)\n- Learn more about [GOV.UK Design System](https://design-system.service.gov.uk/)\n",
"bugtrack_url": null,
"license": "BSD-2-Clause",
"summary": "A Torchbox-flavoured template pack for django-crispy-forms, adapted from crispy-forms-gds",
"version": "4.0.0",
"project_urls": {
"Homepage": "https://github.com/torchbox/tbxforms/",
"Repository": "https://github.com/torchbox/tbxforms/"
},
"split_keywords": [
"crispy",
" django",
" django crispy forms",
" django crispy form",
" forms",
" gds",
" tbxforms",
" wagtail",
" wagtail forms",
" wagtail form"
],
"urls": [
{
"comment_text": "",
"digests": {
"blake2b_256": "65d52912966f9d8fc80e6eaa2bb947d4bafea9b4a6e7bb99d9a83e6b3575d4c4",
"md5": "125aa2b6775431fb568438c4cbaff5cc",
"sha256": "2547d769cddc16b916683570d8bf468d13512d4f2017ad113d5189b3fcb20397"
},
"downloads": -1,
"filename": "tbxforms-4.0.0-py3-none-any.whl",
"has_sig": false,
"md5_digest": "125aa2b6775431fb568438c4cbaff5cc",
"packagetype": "bdist_wheel",
"python_version": "py3",
"requires_python": "<4.0,>=3.8.1",
"size": 89362,
"upload_time": "2025-01-29T13:26:41",
"upload_time_iso_8601": "2025-01-29T13:26:41.431259Z",
"url": "https://files.pythonhosted.org/packages/65/d5/2912966f9d8fc80e6eaa2bb947d4bafea9b4a6e7bb99d9a83e6b3575d4c4/tbxforms-4.0.0-py3-none-any.whl",
"yanked": false,
"yanked_reason": null
},
{
"comment_text": "",
"digests": {
"blake2b_256": "2062de5cb046f3b8fc08270f58167843692da200a9e0abb695a7b43d619334cf",
"md5": "c0408bbca26537751e712957d393aeaa",
"sha256": "243e25bd91103d7a3f710f698ed46b5af69deb2b22b4713a7c85fe575a735a6d"
},
"downloads": -1,
"filename": "tbxforms-4.0.0.tar.gz",
"has_sig": false,
"md5_digest": "c0408bbca26537751e712957d393aeaa",
"packagetype": "sdist",
"python_version": "source",
"requires_python": "<4.0,>=3.8.1",
"size": 62010,
"upload_time": "2025-01-29T13:26:43",
"upload_time_iso_8601": "2025-01-29T13:26:43.216860Z",
"url": "https://files.pythonhosted.org/packages/20/62/de5cb046f3b8fc08270f58167843692da200a9e0abb695a7b43d619334cf/tbxforms-4.0.0.tar.gz",
"yanked": false,
"yanked_reason": null
}
],
"upload_time": "2025-01-29 13:26:43",
"github": true,
"gitlab": false,
"bitbucket": false,
"codeberg": false,
"github_user": "torchbox",
"github_project": "tbxforms",
"travis_ci": false,
"coveralls": false,
"github_actions": true,
"tox": true,
"lcname": "tbxforms"
}