Giter VIP home page Giter VIP logo

omni-forms's Introduction

Omni Forms on pypi Omni Forms on readthedocs MIT license Build status

Omni Forms

Omni forms is a simple form builder with admin integration for django versions >= 1.8 that allows you to easily create forms for your django website.

pip install omniforms

Once the package has been installed just add omni_forms to INSTALLED_APPS in your settings file:

INSTALLED_APPS += ('omniforms',)

Once you've done this run python manage.py migrate to migrate your database.

Configuration

The OmniForms application can be configured in a number of different ways:

Permitted content types

You may not want administrators to be able to create forms for all different types of content in your database. There are 2 different ways of restricting the types of content that can be associated with model forms created through the admin interface:

OMNI_FORMS_CONTENT_TYPES

It is possible to define specific apps and/or models which can be used by the omniforms app using the OMNI_FORMS_CONTENT_TYPES setting.

For example:

The following configuration would allow any of the models in the app foo and the modelone and modeltwo models within the bar app to be used.

OMNI_FORMS_CONTENT_TYPES = [
    {'app_label': 'foo'},
    {'app_label': 'bar', 'model': 'modelone'},
    {'app_label': 'bar', 'model': 'modeltwo'},
]

If the OMNI_FORMS_CONTENT_TYPES setting is not defined it will default to None and the OMNI_FORMS_EXCLUDED_CONTENT_TYPES setting will be used instead (default values or otherwise).

OMNI_FORMS_EXCLUDED_CONTENT_TYPES

It is possible to prevent model forms from being created for specific apps or specific models using the OMNI_FORMS_EXCLUDED_CONTENT_TYPES setting.

For example:

The following configuration would prevent forms being created for any of the models in the app foo and for the modelone and modeltwo models within the bar app.

OMNI_FORMS_EXCLUDED_CONTENT_TYPES = [
    {'app_label': 'foo'},
    {'app_label': 'bar', 'model': 'modelone'},
    {'app_label': 'bar', 'model': 'modeltwo'},
]

If you do not specify this setting it will default to the following:

OMNI_FORMS_EXCLUDED_CONTENT_TYPES = [
    {'app_label': 'omniforms'}
]

This will prevent administrators from creating form_builder forms with the formbuilder itself. It's worth mentioning that allowing administrators to do this represents a potential security risk and should be avoided. As such, if you need to define your own OMNI_FORMS_EXCLUDED_CONTENT_TYPES setting it would be wise to exclude all omniforms models as shown above.

OMNI_FORMS_CUSTOM_FIELD_MAPPING

Although the omniforms app accounts for the majority of use cases you may have models that use custom model fields. In these instances the form builder will not be able to map a model field to a form field and you will need to provide a custom field mapping using the OMNI_FORMS_CUSTOM_FIELD_MAPPING setting.

  • Each key within the mapping dictionary must be a string (python dotted import path) to a model field class.
  • Each value within the mapping dictionary must be a string (python dotted import path) to an OmniField subclass.

For example, you can map a TagField to an OmniCharField model instance using the following configuration:

OMNI_FORMS_CUSTOM_FIELD_MAPPING = {
    'taggit.TagField': 'omniforms.models.OmniCharField',
}

With this configuration any instances of taggit.TagField on your models will be represented as charfields in the corresponding forms generated by omniforms.

It is also possible to create your own OmniField subclasses to use in your custom form builders. For example:

OMNI_FORMS_CUSTOM_FIELD_MAPPING = {
    'taggit.TagField': 'my_app.MySuperOmniField',
}

It is important to note that the dictionary values defined within the OMNI_FORMS_CUSTOM_FIELD_MAPPING MUST be subclasses of omniforms.models.OmniField. If you attempt to register Field handlers that do not subclass omniforms.models.OmniField an ImproperlyConfigured exception will be raised.

Wagtail Integration

If you would like to integrate the form builder with Wagtail you will need to add the omniforms.wagtail submodule to your applications INSTALLED_APPS setting as well as the omniforms module e.g.

INSTALLED_APPS = [
    'omniforms',
    'omniforms.wagtail',
    ...
]

Once this has been done, run database migrations python manage.py migrate and away you go.

Customizing wagtail admin forms

In some cases it may be desirable to customize the form class that wagtail uses for a custom related model type (i.e. an OmniForm Field or OmniForm Handler model). If this is desirable, the custom form class needs to be assigned to a base_form_class property on the model. e.g.

class MyOmniFieldForm(forms.ModelForm):
    def clean_name(self, value):
        if value.contains("something"):
            raise ValidationError("The field name cannot contain the word 'something'")
        return value

class MyOmniField(OmniField):
    base_form_class = MyOmniFieldForm

It is worth noting that the base_form_class must subclass django.forms.ModelForm. You do not need to specify the model that the form is for (using the forms meta class) as this will be generated dynamically when the form class is created.

Preventing forms from being changed or cloned

It may be desirable for forms to be locked under certain conditions. For example, if a form has been set up for data collection, and has already collected data, you may want to prevent the form from being modified or deleted. For this purpose we have added a custom wagtail hook which can be used to implement logic to prevent the form from being edited further.

The hook name is 'omniform_permission_check' and is registered like any other wagtail hook. The hook takes 3 positional arguments:

  • action: The type of action being performed on the form (clone, update, delete);
  • instance: The form instance
  • user: The currently logged in user

Example:

from wagtail.wagtailcore import hooks

@hooks.register('omniform_permission_check')
def lock_form(action, form, user):
    if action in ['update', 'delete'] and form.some_relationship.count() > 0:
        raise PermissionDenied

Docs

To generate the docs for this repo.

pip install -r requirements.txt
cd ./docs
make html

Compatibility

Django

  • Django 1.11.x

Wagtail

  • Wagtail 1.11.x
  • Wagtail 1.12.x
  • Wagtail 1.13.x

Python

  • Python 2.7
  • Python 3.4
  • Python 3.5
  • Python 3.6

ChangeLog

  • 0.1 - Initial Build
  • 0.2 - Adds ability to create arbitrary non model form instances
  • 0.3 - Adds OmniChoiceField and OmniMultipleChoiceField form field types and wagtail integration
  • 0.4 - Wagtail related improvements (see the full changelog in the release)

omni-forms's People

Contributors

fatboystring avatar pawelad avatar semvertsar avatar aabele avatar nologo avatar mitch104 avatar

Stargazers

Julian Beggs avatar  avatar  avatar Nikolaus Schlemm avatar

Watchers

James Cloos avatar  avatar

omni-forms's Issues

Add verbose_name and verbose_name_plural attributes to model meta for field models

The field models are all prefixed with 'Omni' (e.g. OmniCharField) so that we do not run into namespacing issues when generating actual form fields from OmniField model instances. This data is basically redundant for end users.

I propose we add explicit 'verbose_name' and 'verbose_name_plural' attributes to OmniField models to explicitly remove the 'Omni' prefix.

Save Data handler validation blocking handler save

Currently, if you try and create a save data handler for a model, the validation prevents the handler from saving - ostensibly becuase the model's required fields are not represented by corresponding fields in the model form.

This occurs even if the required fields' equivalents are present in the model form.

The error message is a bit naive, and includes in the field list of missing fields all remaining fields on the model not represented on the form, rather than just those which are mandatory and not present on the model form.

Additionally, the handler also includes in its error message fields which should be excluded - like auto-incrementing ID fields, and auto on-save date/time fields.

Include friendly handlers and descriptions of form fields

As it stands, the available fields are using developer terminology. While this is fine for developers, when it comes time for non-technical users to use the library it can be confusing.

A solution that allows for friendly names and descriptions of form fields would be ideal.

Field Editing

Once a model field has been created it can not be edited. This needs to be implemented

OmniForm instance should be passed to related forms in wagtail admin views

A common use case here is that handlers and fields may need to restrict choices for related fields (foreign keys and M2M fields) based on the form they're attached to. Ensuring the model form create view has an instance with a pre-populated reference to the associated form instance will allow this to be handled easier.

It must be possible to 'lock' a form based on its state

It may be desirable to prevent a form from being changed or deleted under certain conditions. For example, if a data collection form has already started collecting data, if a certain date has passed, or any number of other scenarios.

We should not bake this logic into the library itself, but we should provide users with a mechanism by which they can provide their own validation hooks (wagtail specific).

OmniFormEmailHandler help text

The OmniFormEmailHandler class contains a template field allowing administrators to define the contents of the email to be sent.

This handler will be passed an arbitrary cleaned form data dict (depending on the form class that uses it) as the template context. It would be extremely useful if the available template context variables were made available to administrators in the django admin as help text.

This should be possible using introspection

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.