Metadata-Version: 2.2
Name: wagtail-model-forms
Version: 0.9.0
Summary: The Wagtail Form Builder functionalities available for your models/snippets.
Author: R. Moorman <rob@vicktor.nl>
Classifier: Environment :: Web Environment
Classifier: Framework :: Django
Classifier: Operating System :: Unix
Classifier: Framework :: Wagtail :: 5
Classifier: Framework :: Wagtail :: 6
Classifier: Framework :: Wagtail :: 7
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.8
Classifier: Programming Language :: Python :: 3.9
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Programming Language :: Python :: 3.14
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: wagtail>=5
Provides-Extra: test
Requires-Dist: black; extra == "test"
Requires-Dist: coverage; extra == "test"
Requires-Dist: flake8; extra == "test"
Requires-Dist: isort; extra == "test"
Requires-Dist: pytest; extra == "test"
Requires-Dist: pytest-cov; extra == "test"
Requires-Dist: pytest-django; extra == "test"
Dynamic: author
Dynamic: classifier
Dynamic: description
Dynamic: description-content-type
Dynamic: provides-extra
Dynamic: requires-dist
Dynamic: summary

# Wagtail Model Forms

[![Version](https://img.shields.io/pypi/v/wagtail-model-forms.svg?style=flat)](https://pypi.python.org/pypi/wagtail-model-forms/)
![CI](https://github.com/vicktornl/wagtail-model-forms/actions/workflows/ci.yml/badge.svg)

The Wagtail Form Builder functionalities available for your models/snippets.

## Features

* Well-known Form Builder functionalities
* Form block for StreamField support
* Extensible models (Form, FormSubmission, UploadedFile & FormBlock)
* Inspect, edit and delete views for form submissions
* File uploads
* Reports
* Email notifications
* Webhooks & API integrations
* Crispy forms support

## Requirements

- Python >= 3.8
- Django >= 4.2
- Wagtail >= 5.2

## Installation

Install the package

```
pip install wagtail-model-forms
```

Add `wagtail_model_forms` to your INSTALLED_APPS

```python
INSTALLED_APPS = [
    ...
    "wagtail_model_forms",
]
```

Create your models

```python
from django.utils.functional import cached_property
from modelcluster.fields import ParentalKey
from wagtail.core.models import Page
from wagtail.snippets.models import register_snippet
from wagtail_model_forms.mixins import FormSnippetMixin
from wagtail_model_forms.models import AbstractForm, AbstractUploadedFile, AbstractFormSubmission


class FormSubmission(AbstractFormSubmission):
    form = models.ForeignKey(
        "Form",
        on_delete=models.CASCADE,
        related_name="+",
        verbose_name=_("Form"),
    )


class UploadedFile(AbstractUploadedFile):
    pass


@register_snippet
class Form(AbstractForm):
    @cached_property
    def edit_url(self):
        # return your url here, commonly your own modeladmin configuration
        url_helper = FormModelAdmin().url_helper
        return url_helper.get_action_url("edit", self.id)


class MyPage(FormSnippetMixin, Page):
    pass
```

In order to let the page now that there is a form on it (handle post methods, caching etc.) we need to make sure the method `page_has_form` returns `True`. To make your life easier you can set the property `streamfields` with the names of the StreamField which can have the form added. Also make sure the name of the block is matched, commonly called `form` in your list of blocks. In some cases you might want to override this method and implement your own bespoke logic here.

```python
from wagtail_model_forms.blocks import FormBlock


class MyPage(FormSnippetMixin, Page):
    block_type = "form" # has by default already the value form
    streamfields = ["content"] # the name of your streamfields
    
    content = StreamField([
      # your other blocks
      ("form", FormBlock()),
    ])
```

More advanced with your bespoke implementation

```python
from django.utils.functional import cached_property


class MyPage(FormSnippetMixin, Page):
    @cached_property
    def page_has_form(self):
        # your bespoke import in order to determine a form is on the page
```

It's not mandatory to use the `register_snippet` functionality. You can e.g. use `wagtailmodelchooser` for it or any other bespoke implementation in order to put the form on your page.

## Settings

###### WAGTAIL_MODEL_FORMS_ADD_NEVER_CACHE_HEADERS`

Default `True`

######  WAGTAIL_MODEL_FORMS_FORM_MODEL

Must be of the form `app_label.model_name`

###### WAGTAIL_MODEL_FORMS_SUBMISSION_MODEL

Must be of the form `app_label.model_name`

###### WAGTAIL_MODEL_FORMS_UPLOADED_FILE_MODEL

Must be of the form `app_label.model_name`

###### WAGTAIL_MODEL_FORMS_REPORTS`

Default `True`

###### WAGTAIL_MODEL_FORMS_CIRSPY_FORMS_FORM_TAG

Default `False`

## Templates

**wagtail_model_forms/form.html**

```html
{% if not request.form_success is self.form.id %}
<form action="" method="POST" novalidate>
    {% csrf_token %}
    <input type="hidden" name="form_id" value="{{ self.form.id }}">
    {{ form.as_ul }}
    <button type="submit">Submit</button>
</form>
{% else %}
    <p>Form success</p>
{% endif %}
```

## FAQ

###### The form is not submitted

Make sure you have added the `FormSnippetMixin` and implemented the `page_has_form` method correctly.

###### Request is not available in get_context of FormBlock

Make sure you render your blocks in your templates with `include_block`, see <https://docs.wagtail.org/en/stable/topics/streamfield.html>.
