django-fobi

django-fobi (later on named just fobi) is a customisable, modular, user- and developer- friendly form builder application for Django. With fobi you can build Django forms using an intiutive GUI, save or mail posted form data. API allows you to build your own form elements and form handlers (mechanisms for handling the submitted form data).

Prerequisites

  • Django 1.5, 1.6, 1.7
  • Python >= 2.6.8, 2.7.*, 3.3.*

Note, that Django 1.7 is not yet proclaimed to be flawlessly supported!

Key concepts

  • Each form consists of elements. Form elements are divided into two groups:
      1. form fields (input field, textarea, hidden field, file field, etc.).
      1. content (presentational) elements (text, image, embed video, etc.).
  • Number of form elements is not limited.
  • Each form may contain handlers. Handler processes the form data (for example, saves it or mails it). Number of the handlers is not limited.
  • Both form elements and form handlers are made with Django permission system in mind.
  • As an addition to form handlers, form callbacks are implemented. Form callbacks are fired on various stages of pre- and post-processing the form data (on POST). Form callbacks do not make use of permission system (unless you intentionally do so in the code of your callback) and are fired for all forms (unlike form handlers, that are executed only if assigned).
  • Each plugin (form element or form handler) or a callback - is a Django micro-app.

Note, that Fobi does not require django-admin and administrative rights/ permissions to access the UI, although almost seamless integration with django-admin is implemented through the simple theme.

Main features and highlights

  • User-friendly GUI to quickly build forms.
  • Large variety of form elements/fields. Most of the Django fields are supported. HTML5 fields are supported as well.
  • Captcha integration comes out of the box with help of third-party app.
  • In addition to standard form elements, there are cosmetic (presentational) form elements (for adding a piece of text, image or a embed video) alongside standard form elements.
  • Data handling in plugins (form handlers). Save the data, mail it to some address or repost it to some other endpoint.
  • Developer-friendly API, which allows to or build new form fields and handlers without touching the core.
  • Support for custom user model.
  • Theming. There are 3 ready to use themes bundled: Bootstrap 3, Foundation 5 and Simple (in style of Django admin).
  • Implemented integration with FeinCMS (in a form of a FeinCMS Page widget).
  • Reordering of form elements using drag-n-drop.
  • Data export (db_store form handler plugin) into XLS/CSV format.

Roadmap

Some of the upcoming/in-development features/improvements are:

  • Form importers (and as a part of it - MailChimp integration, which would allow to import forms from MailChimp into Fobi using a user-friendly wizard).
  • Fieldsets.

See the TODOS for the full list of planned-, pending- in-development- or to-be-implemented features.

Installation

  1. Install latest stable version from PyPI:
$ pip install django-fobi

Or latest stable version from GitHub:

$ pip install -e git+https://github.com/barseghyanartur/django-fobi@stable#egg=django-fobi

Or latest stable version from BitBucket:

$ pip install -e hg+https://bitbucket.org/barseghyanartur/django-fobi@stable#egg=django-fobi
  1. Add fobi to INSTALLED_APPS of the your projects’ Django settings. Furthermore, all themes and plugins to be used, shall be added to the INSTALLED_APPS as well.
INSTALLED_APPS = (
    # ...
    # Fobi core
    'fobi',

    # Fobi themes
    'fobi.contrib.themes.bootstrap3', # Bootstrap 3 theme
    'fobi.contrib.themes.foundation5', # Foundation 5 theme
    'fobi.contrib.themes.simple', # Simple theme

    # Fobi form elements - fields
    'fobi.contrib.plugins.form_elements.fields.boolean',
    'fobi.contrib.plugins.form_elements.fields.date',
    'fobi.contrib.plugins.form_elements.fields.datetime',
    'fobi.contrib.plugins.form_elements.fields.email',
    'fobi.contrib.plugins.form_elements.fields.file',
    'fobi.contrib.plugins.form_elements.fields.hidden',
    'fobi.contrib.plugins.form_elements.fields.integer',
    'fobi.contrib.plugins.form_elements.fields.password',
    'fobi.contrib.plugins.form_elements.fields.radio',
    'fobi.contrib.plugins.form_elements.fields.select',
    'fobi.contrib.plugins.form_elements.fields.select_model_object',
    'fobi.contrib.plugins.form_elements.fields.select_multiple',
    'fobi.contrib.plugins.form_elements.fields.text',
    'fobi.contrib.plugins.form_elements.fields.textarea',
    'fobi.contrib.plugins.form_elements.fields.url',

    # Fobi form elements - content elements
    'fobi.contrib.plugins.form_elements.content.dummy',
    'fobi.contrib.plugins.form_elements.content.image',
    'fobi.contrib.plugins.form_elements.content.text',
    'fobi.contrib.plugins.form_elements.content.video',

    # Form handlers
    'fobi.contrib.plugins.form_handlers.db_store',
    'fobi.contrib.plugins.form_handlers.http_repost',
    'fobi.contrib.plugins.form_handlers.mail',

    # Other project specific apps
    'foo', # Test app
    # ...
)
  1. Make appropriate changes to the TEMPLATE_CONTEXT_PROCESSORS of the your projects’ Django settings.

And the following to the context processors.

TEMPLATE_CONTEXT_PROCESSORS = (
    # ...
    "fobi.context_processors.theme".
    # ...
)

Make sure that django.core.context_processors.request is in TEMPLATE_CONTEXT_PROCESSORS too.

  1. Configure URLs

Add the following line to urlpatterns of your urls module.

# View URLs
url(r'^fobi/', include('fobi.urls.view')),

# Edit URLs
url(r'^fobi/', include('fobi.urls.edit')),

View URLs are put separately from edit URLs in order to make it possible to prefix the edit URLs differently. For example, if you’re using the “Simple” theme, you would likely want to prefix the edit URLs with “admin/” so that it looks more like django-admin.

Demo

See the documentation for some screen shots:

In order to be able to quickly evaluate the Fobi, a demo app (with a quick installer) has been created (works on Ubuntu/Debian, may work on other Linux systems as well, although not guaranteed). Follow the instructions below for having the demo running within a minute.

Grab the latest django_fobi_example_app_installer.sh:

$ wget https://raw.github.com/barseghyanartur/django-fobi/stable/examples/django_fobi_example_app_installer.sh

Assign execute rights to the installer and run the django_fobi_example_app_installer.sh:

$ chmod +x django_fobi_example_app_installer.sh
$ ./django_fobi_example_app_installer.sh

Open your browser and test the app.

Dashboard:

Django admin interface:

If quick installer doesn’t work for you, see the manual steps on running the example project.

Creating a new form element plugin

Form element plugins represent the elements of which the forms is made: Inputs, checkboxes, textareas, files, hidden fields, as well as pure presentational elements (text or image). Number of form elements in a form is not limited.

Presentational form elements are inherited from fobi.base.FormElementPlugin.

The rest (real form elements, that are supposed to have a value) are inherited from fobi.base.FormFieldPlugin.

You should see a form element plugin as a Django micro app, which could have its’ own models, admin interface, etc.

Fobi comes with several bundled form element plugins. Do check the source code as example.

Let’s say, you want to create a textarea form element plugin.

There are several properties, each textarea should have. They are:

  • label (string): HTML label of the textarea.
  • name (string): HTML name of the textarea.
  • initial (string): Initial value of the textarea.
  • required (bool): Flag, which tells us whether the field is required or optional.

Let’s name that plugin sample_textarea. The plugin directory should then have the following structure.

path/to/sample_textarea/
├── __init__.py
├── fobi_form_elements.py # Where plugins are defined and registered
├── forms.py # Plugin configuration form
└── widgets.py # Where plugins widgets are defined

Form element plugins should be registered in “fobi_form_elements.py” file. Each plugin module should be put into the INSTALLED_APPS of your Django projects’ settings.

In some cases, you would need plugin specific overridable settings (see fobi.contrib.form_elements.fields.content.image plugin as an example). You are advised to write your settings in such a way, that variables of your Django project settings module would have FOBI_PLUGIN_ prefix.

Define and register the form element plugin

Step by step review of a how to create and register a plugin and plugin widgets. Note, that Fobi autodiscovers your plugins if you place them into a file named fobi_form_elements.py of any Django app listed in INSTALLED_APPS of your Django projects’ settings module.

path/to/sample_textarea/fobi_form_elements.py

A single form element plugin is registered by its’ UID.

Required imports.

from django import forms
from fobi.base import FormFieldPlugin, form_element_plugin_registry
from path.to.sample_textarea.forms import SampleTextareaForm

Defining the Sample textarea plugin.

class SampleTextareaPlugin(FormFieldPlugin):
    uid = "sample_textarea"
    name = "Sample Textarea"
    form = SampleTextareaForm
    group = "Samples" # Group to which the plugin belongs to

    def get_form_field_instances(self):
        kwargs = {
            'required': self.data.required,
            'label': self.data.label,
            'initial': self.data.initial,
            'widget': forms.widgets.Textarea(attrs={})
        }

        return [(self.data.name, forms.CharField, kwargs),]

Registering the SampleTextareaPlugin plugin.

form_element_plugin_registry.register(SampleTextareaPlugin)

Note, that in case you want to define a pure presentational element, make use of fobi.base.FormElementPlugin for subclassing, instead of fobi.base.FormFieldPlugin. See the source of the content plugins (fobi.contrib.plugins.form_elements.content) as a an example.

There might be cases, when you need to do additional handling of the data upon the successful form submittion. In such cases, you will need to define a submit_plugin_form_data method in the plugin, which accepts the following arguments:

  • form_entry (fobi.models.FormEntry): Form entry, which is being submitted.
  • request (django.http.HttpRequest): The Django HTTP request.
  • form (django.forms.Form): Form object (a valid one, which contains the cleaned_data attribute).

Example (taken from fobi.contrib.plugins.form_elements.fields.file):

def submit_plugin_form_data(self, form_entry, request, form):
    # Get the file path
    file_path = form.cleaned_data.get(self.data.name, None)
    if file_path:
        # Handle the upload
        saved_file = handle_uploaded_file(FILES_UPLOAD_DIR, file_path)
        # Overwrite ``cleaned_data`` of the ``form`` with path to moved
        # file.
        form.cleaned_data[self.data.name] = "{0}{1}".format(
            settings.MEDIA_URL, saved_file
            )

    # It's critically important to return the ``form`` with updated
    # ``cleaned_data``
    return form

In the example below, the original form is being modified. If you don’t want the original form to be modified, do not return anything.

Check the file form element plugin (fobi.contrib.plugins.form_elements.fields.file) for complete example.

path/to/sample_textarea/forms.py

Why to have another file for defining forms? Just to keep the code clean and less messy, although you could perfectly define all your plugin forms in the module fobi_form_elements.py, it’s recommended to keep it separate.

Take into consideration, that forms.py is not an autodiscovered file pattern. All your form element plugins should be registered in modules named fobi_form_elements.py.

Required imports.

from django import forms
from fobi.base import BasePluginForm

Form for for SampleTextareaPlugin form element plugin.

class SampleTextareaForm(forms.Form, BasePluginForm):
    plugin_data_fields = [
        ("name", ""),
        ("label", ""),
        ("initial", ""),
        ("required", False)
    ]

name = forms.CharField(label="Name", required=True)
label = forms.CharField(label="Label", required=True)
initial = forms.CharField(label="Initial", required=False)
required = forms.BooleanField(label="Required", required=False)

Note that although it’s not being checked in the code, but for form field plugins the following fields should be present in the plugin form (BasePluginForm) and the form plugin (FormFieldPlugin):

  • name

In some cases, you might want to do something with the data before it gets saved. For that purpose, save_plugin_data method has been introduced.

See the following example.

def save_plugin_data(self, request=None):
    """
    Saving the plugin data and moving the file.
    """
    file_path = self.cleaned_data.get('file', None)
    if file_path:
        saved_image = handle_uploaded_file(IMAGES_UPLOAD_DIR, file_path)
        self.cleaned_data['file'] = saved_image

path/to/sample_textarea/widgets.py

Required imports.

from fobi.base import FormElementPluginWidget

Defining the base plugin widget.

class BaseSampleTextareaPluginWidget(FormElementPluginWidget):
    # Same as ``uid`` value of the ``SampleTextareaPlugin``.
    plugin_uid = "sample_textarea"

path/to/sample_layout/fobi_form_elements.py

Register in the registry (in some module which is for sure to be loaded; it’s handy to do it in the theme module).

Required imports.

from fobi.base import form_element_plugin_widget_registry
from path.to.sample_textarea.widgets import BaseSampleTextareaPluginWidget

Define the theme specific plugin.

class SampleTextareaPluginWidget(BaseSampleTextareaPluginWidget):
    theme_uid = 'bootstrap3' # Theme for which the widget is loaded
    media_js = ['sample_layout/js/fobi.plugins.form_elements.sample_textarea.js',]
    media_css = ['sample_layout/css/fobi.plugins.form_elements.sample_textarea.css',]

Register the widget.

form_element_plugin_widget_registry.register(SampleTextareaPluginWidget)

Form element plugin final steps

Now, that everything is ready, make sure your plugin module is added to INSTALLED_APPS.

INSTALLED_APPS = (
    # ...
    'path.to.sample_textarea',
    # ...
)

Afterwards, go to terminal and type the following command.

$ ./manage.py fobi_sync_plugins

If your HTTP server is running, you would then be able to see the new plugin in the edit form interface.

Dashboard URL: http://127.0.0.1:8000/fobi/

Note, that you have to be logged in, in order to use the dashboard. If your new plugin doesn’t appear, set the FOBI_DEBUG to True in your Django’s local settings module, re-run your code and check console for error notifications.

Creating a new form handler plugin

Form handler plugins handle the form data. Fobi comes with several bundled form handler plugins, among which is the db_store and mail plugins, which are responsible for saving the submitted form data into the database and mailing the data to recipients specified. Number of form handlers in a form is not limited. Certain form handlers are not configurable (for example the db_store form handler isn’t), while others are (mail, http_repost).

You should see a form handler as a Django micro app, which could have its’ own models, admin interface, etc.

As said above, Fobi comes with several bundled form handler plugins. Do check the source code as example.

Define and register the form handler plugin

Let’s name that plugin sample_mail. The plugin directory should then have the following structure.

path/to/sample_mail/
├── __init__.py
├── fobi_form_handlers.py # Where plugins are defined and registered
└── forms.py # Plugin configuration form

Form handler plugins should be registered in “fobi_form_handlers.py” file. Each plugin module should be put into the INSTALLED_APPS of your Django projects’ settings.

path/to/sample_mail/fobi_form_handlers.py

A single form handler plugin is registered by its’ UID.

Required imports.

import json
from django.core.mail import send_mail
from fobi.base import FormHandlerPlugin, form_handler_plugin_registry
from path.to.sample_mail.forms import SampleMailForm

Defining the Sample mail handler plugin.

class SampleMailHandlerPlugin(FormHandlerPlugin):
    uid = "sample_mail"
    name = _("Sample mail")
    form = SampleMailForm

    def run(self, form_entry, request, form):
        send_mail(
            self.data.subject,
            json.dumps(form.cleaned_data),
            self.data.from_email,
            [self.data.to_email],
            fail_silently = True
            )

Some form handlers are configurable, some others not. In order to have a user friendly way of showing the form handler settings, what’s sometimes needed, a plugin_data_repr method has been introducd. Simplest implementation of it would look as follows:

def plugin_data_repr(self):
    """
    Human readable representation of plugin data.

    :return string:
    """
    return self.data.__dict__

path/to/sample_mail/forms.py

If plugin is configurable, it has configuration data. A single form may have unlimited number of same plugins. Imagine, you want to have different subjects and additional body texts for different user groups. You could then assign two form handler mail plugins to the form. Of course, saving the posted form data many times does not make sense, but it’s up to the user. So, in case if plugin is configurable, it should have a form.

Why to have another file for defining forms? Just to keep the code clean and less messy, although you could perfectly define all your plugin forms in the module fobi_form_handlers.py, it’s recommended to keep it separate.

Take into consideration, that forms.py is not an autodiscovered file pattern. All your form handler plugins should be registered in modules named fobi_form_handlers.py.

Required imports.

from django import forms
from django.utils.translation import ugettext_lazy as _
from fobi.base import BasePluginForm

Defining the form for Sample mail handler plugin.

class MailForm(forms.Form, BasePluginForm):
    plugin_data_fields = [
        ("from_name", ""),
        ("from_email", ""),
        ("to_name", ""),
        ("to_email", ""),
        ("subject", ""),
        ("body", ""),
    ]

    from_name = forms.CharField(label=_("From name"), required=True)
    from_email = forms.EmailField(label=_("From email"), required=True)
    to_name = forms.CharField(label=_("To name"), required=True)
    to_email = forms.EmailField(label=_("To email"), required=True)
    subject = forms.CharField(label=_("Subject"), required=True)
    body = forms.CharField(label=_("Body"), required = False,
                           widget=forms.widgets.Textarea)

After the plugin has been processed, all its’ data is available in a plugin_instance.data container (for example, plugin_instance.data.subject or plugin_instance.data.from_name).

Prioritise the excecution order

Some form handlers shall be executed prior others. A good example of such, is a combination of “mail” and “db_save” form handlers for the form. In case of large files posted, submittion of form data would fail if “mail” plugin would be executed after “db_save” has been executed. That’s why it’s possible to prioritise that ordering in a FOBI_FORM_HANDLER_PLUGINS_EXECUTION_ORDER setting variable.

If not specified or left empty, form handler plugins would be ran in the order of discovery. All form handler plugins that are not listed in the FORM_HANDLER_PLUGINS_EXECUTION_ORDER, would be ran after the plugins that are mentioned there.

FORM_HANDLER_PLUGINS_EXECUTION_ORDER = (
    'http_repost',
    'mail',
    # The 'db_store' is left out intentionally, since it should
    # be the last plugin to be executed.
)

Form handler plugin custom actions

By default, a single form handler plugin has at least a “delete” action. If plugin is configurable, it gets an “edit” action as well.

For some of your plugins, you may want to register a custom action. For example, the “db_store” plugin does have one, for showing a link to a listing page with saved form data for the form given.

For such cases, define a custom_actions method in your form handler plugin. That method shall return a list of triples. In each triple, first value is the URL, second value is the title and the third value is the icon of the URL.

The following example is taken from the “db_store” plugin.

def custom_actions(self):
    """
    Adding a link to view the saved form enties.

    :return iterable:
    """
    return (
        (
            reverse('fobi.contrib.plugins.form_handlers.db_store.view_saved_form_data_entries'),
            _("View entries"),
            'glyphicon glyphicon-list'
        ),
    )

Form handler plugin final steps

Do not forget to add the form handler plugin module to INSTALLED_APPS.

INSTALLED_APPS = (
    # ...
    'path.to.sample_mail',
    # ...
)

Afterwards, go to terminal and type the following command.

$ ./manage.py fobi_sync_plugins

If your HTTP server is running, you would then be able to see the new plugin in the edit form interface.

Creating a form callback

Form callbacks are additional hooks, that are executed on various stages of the form submission.

Let’s place the callback in the foo module. The plugin directory should then have the following structure.

path/to/foo/
├── __init__.py
└── fobi_form_callbacks.py # Where callbacks are defined and registered

See the callback example below.

Required imports.

from fobi.constants import (
    CALLBACK_BEFORE_FORM_VALIDATION,
    CALLBACK_FORM_VALID_BEFORE_SUBMIT_PLUGIN_FORM_DATA,
    CALLBACK_FORM_VALID, CALLBACK_FORM_VALID_AFTER_FORM_HANDLERS,
    CALLBACK_FORM_INVALID
    )
from fobi.base import FormCallback, form_callback_registry

Define and register the callback

class SampleFooCallback(FormCallback):
    stage = CALLBACK_FORM_VALID

    def callback(self, form_entry, request, form):
        print("Great! Your form is valid!")

form_callback_registry.register(SampleFooCallback)

Add the callback module to INSTALLED_APPS.

INSTALLED_APPS = (
    # ...
    'path.to.foo',
    # ...
)

Suggestions

Custom action for the form

Sometimes, you would want to specify a different action for the form. Although it’s possible to define a custom form action (action field in the “Form properties” tab), you’re advised to use the http_repost plugin instead, since then the form would be still validated locally and only then the valid data, as is, would be sent to the desired endpoint.

Take in mind, that if both cases, if CSRF protection is enabled on the endpoint, your post request would result an error.

When you want to customise too many things

Fobi, with its’ flexible form elements, form handlers and form callbacks is very customisable. However, there might be cases when you need to override entire view to fit your needs. Take a look at the FeinCMS integration as a good example of such. You may also want to compare the code from original view fobi.views.view_form_entry with the code from the widget to get a better idea of what could be changed in your case. If need a good advice, just ask me.

Theming

Fobi comes with theming API. While there are several ready-to-use themes:

  • Bootstrap 3 theme
  • Foundation 5 theme
  • Simple theme in style of the Django admin

Have in mind, that creating a brand new theme could be time consuming. Instead, you are advised to extend existing themes or in the worst case, if too much customisation required, create your own themes based on existing ones (just copy the desired theme to your project directory and work it out further).

It’s possible to use different templates for all “view” and “edit” actions (see the source code of the “simple” theme). Both Bootstrap 3 and Foundation 5 themes look great. Although if you can’t use any of those, the “simple” theme is the best start, since it looks just like django-admin.

Create a new theme

Let’s place the theme in the sample_theme module. The theme directory should then have the following structure.

path/to/sample_theme/
├── static
│   ├── css
│   │   └── sample_theme.css
│   └── js
│       └── sample_theme.js
├── templates
│   └── sample_theme
│       ├── _base.html
│       ├── add_form_element_entry.html
│       ├── ...
│       └── view_form_entry_ajax.html
├── __init__.py
├── fobi_form_elements.py
└── fobi_themes.py # Where themes are defined and registered

See the theme example below.

from django.utils.translation import ugettext_lazy as _

from fobi.base import BaseTheme, theme_registry

class SampleTheme(BaseTheme):
    """
    Sample theme.
    """
    uid = 'sample'
    name = _("Sample")

    media_css = (
        'sample_theme/css/sample_theme.css',
        'css/fobi.core.css',
    )

    media_js = (
        'js/jquery-1.10.2.min.js',
        'jquery-ui/js/jquery-ui-1.10.3.custom.min.js',
        'js/jquery.slugify.js',
        'js/fobi.core.js',
        'sample_theme/js/sample_theme.js',
    )

    # Form element specific
    form_element_html_class = 'form-control'
    form_radio_element_html_class = 'radio'
    form_element_checkbox_html_class = 'checkbox'

    form_edit_form_entry_option_class = 'glyphicon glyphicon-edit'
    form_delete_form_entry_option_class = 'glyphicon glyphicon-remove'
    form_list_container_class = 'list-inline'

    # Templates
    master_base_template = 'sample_theme/_base.html'
    base_template = 'sample_theme/base.html'

    form_ajax = 'sample_theme/snippets/form_ajax.html'
    form_snippet_template_name = 'sample_theme/snippets/form_snippet.html'
    form_properties_snippet_template_name = 'sample_theme/snippets/form_properties_snippet.html'
    messages_snippet_template_name = 'sample_theme/snippets/messages_snippet.html'

    add_form_element_entry_template = 'sample_theme/add_form_element_entry.html'
    add_form_element_entry_ajax_template = 'sample_theme/add_form_element_entry_ajax.html'

    add_form_handler_entry_template = 'sample_theme/add_form_handler_entry.html'
    add_form_handler_entry_ajax_template = 'sample_theme/add_form_handler_entry_ajax.html'

    create_form_entry_template = 'sample_theme/create_form_entry.html'
    create_form_entry_ajax_template = 'bootstrap3/create_form_entry_ajax.html'

    dashboard_template = 'sample_theme/dashboard.html'

    edit_form_element_entry_template = 'sample_theme/edit_form_element_entry.html'
    edit_form_element_entry_ajax_template = 'sample_theme/edit_form_element_entry_ajax.html'

    edit_form_entry_template = 'sample_theme/edit_form_entry.html'
    edit_form_entry_ajax_template = 'sample_theme/edit_form_entry_ajax.html'

    edit_form_handler_entry_template = 'sample_theme/edit_form_handler_entry.html'
    edit_form_handler_entry_ajax_template = 'sample_theme/edit_form_handler_entry_ajax.html'

    form_entry_submitted_template = 'sample_theme/form_entry_submitted.html'
    form_entry_submitted_ajax_template = 'sample_theme/form_entry_submitted_ajax.html'

    view_form_entry_template = 'sample_theme/view_form_entry.html'
    view_form_entry_ajax_template = 'sample_theme/view_form_entry_ajax.html'

Registering the SampleTheme plugin.

theme_registry.register(SampleTheme)

Sometimes you would want to attach additional properties to the theme in order to use them later in templates (rememeber, current theme object is always available in templates under name fobi_theme).

For such cases you would need to define a variable in your project’s settings module, called FOBI_CUSTOM_THEME_DATA. See the following code as example:

# Fobi custom theme data for to be displayed in third party apps
# like `django-registraton`.
FOBI_CUSTOM_THEME_DATA = {
    'bootstrap3': {
        'page_header_html_class': '',
        'form_html_class': 'form-horizontal',
        'form_button_outer_wrapper_html_class': 'control-group',
        'form_button_wrapper_html_class': 'controls',
        'form_button_html_class': 'btn',
        'form_primary_button_html_class': 'btn-primary pull-right',
    },
    'foundation5': {
        'page_header_html_class': '',
        'form_html_class': 'form-horizontal',
        'form_button_outer_wrapper_html_class': 'control-group',
        'form_button_wrapper_html_class': 'controls',
        'form_button_html_class': 'radius button',
        'form_primary_button_html_class': 'btn-primary',
    },
    'simple': {
        'page_header_html_class': '',
        'form_html_class': 'form-horizontal',
        'form_button_outer_wrapper_html_class': 'control-group',
        'form_button_wrapper_html_class': 'submit-row',
        'form_button_html_class': 'btn',
        'form_primary_button_html_class': 'btn-primary',
    }
}

You would now be able to access the defined extra properties in templates as shown below.

<div class="{{ fobi_theme.custom_data.form_button_wrapper_html_class }}">

You likely would want to either remove the footer text or change it. Define a variable in your project’s settings module, called FOBI_THEME_FOOTER_TEXT. See the following code as example:

FOBI_THEME_FOOTER_TEXT = gettext('&copy; django-fobi example site 2014')

Below follow the properties of the theme:

  • base_edit
  • base_view

There are generic templates made in order to simplify theming. Some of them you would never need to override. Some others, you would likely want to.

Templates that you likely would want to re-write in your custom theme implemention are marked with three asterics (***):

generic
├── snippets
│   ├── form_ajax.html
│   ├── form_edit_ajax.html
│   ├── *** form_properties_snippet.html
│   ├── *** form_snippet.html
│   ├── --- form_edit_snippet.html (does not exist in generic templates)
│   ├── --- form_view_snippet.html (does not exist in generic templates)
│   ├── form_view_ajax.html
│   └── messages_snippet.html
│
├── _base.html
├── add_form_element_entry.html
├── add_form_element_entry_ajax.html
├── add_form_handler_entry.html
├── add_form_handler_entry_ajax.html
├── base.html
├── create_form_entry.html
├── create_form_entry_ajax.html
├── *** dashboard.html
├── edit_form_element_entry.html
├── edit_form_element_entry_ajax.html
├── edit_form_entry.html
├── *** edit_form_entry_ajax.html
├── edit_form_handler_entry.html
├── edit_form_handler_entry_ajax.html
├── form_entry_submitted.html
├── *** form_entry_submitted_ajax.html
├── *** theme.html
├── view_form_entry.html
└── view_form_entry_ajax.html

From all of the templates listed above, the _base.html template is the most influenced by the Bootstrap 3 theme.

Make changes to an existing theme

As said above, making your own theme from scratch could be costy. Instead, you can override/reuse an existing one and change it to your needs with minimal efforts. See the override simple theme example. In order to see it in action, run the project with settings_override_simple_theme option:

./manage.py runserver --settings=settings_override_simple_theme

Details explained below.

Directory structure

override_simple_theme/
├── static
│   └── override_simple_theme
│       ├── css
│       │   └── override-simple-theme.css
│       └── js
│           └── override-simple-theme.js
│
├── templates
│   └── override_simple_theme
│       ├── snippets
│       │   └── form_ajax.html
│       └── base_view.html
├── __init__.py
└── fobi_themes.py # Where themes are defined and registered

fobi_themes.py

Overriding the “simple” theme.

__all__ = ('MySimpleTheme',)

from fobi.base import theme_registry

from fobi.contrib.themes.simple.fobi_themes import SimpleTheme

class MySimpleTheme(SimpleTheme):
    html_classes = ['my-simple-theme',]
    base_view_template = 'override_simple_theme/base_view.html'
    form_ajax = 'override_simple_theme/snippets/form_ajax.html'

Register the overridden theme. Note, that it’s important to set the force argument to True, in order to override the original theme. Force can be applied only once (for a overridden element).

theme_registry.register(MySimpleTheme, force=True)

templates/override_simple_theme/base_view.html

{% extends "simple/base_view.html" %}

{% load static %}

{% block stylesheets %}
<link
  href="{% static 'override_simple_theme/css/override-simple-theme.css' %}"
  rel="stylesheet" media="all" />
{% endblock stylesheets %}

{% block main-wrapper %}
<div id="sidebar">
  <h2>It's easy to override a theme!</h2>
</div>

{{ block.super }}
{% endblock main-wrapper %}

templates/override_simple_theme/snippets/form_ajax.html

{% extends "fobi/generic/snippets/form_ajax.html" %}

{% block form_html_class %}basic-grey{% endblock %}

Permissions

Plugin system allows administrators to specify the access rights to every plugin. Fobi permissions are based on Django Users and User Groups. Access rights are managable via Django admin (“/admin/fobi/formelement/”, “/admin/fobi/formhandler/”). If user doesn’t have the rights to access plugin, it doesn’t appear on his form even if has been added to it (imagine, you have once granted the right to use the news plugin to all users, but later on decided to limit it to Staff members group only). Note, that superusers have access to all plugins.

Plugin access rights management interface in Django admin
┌──────────────────────────────┬───────────────────────┬───────────────────────┐
│ `Plugin`                     │ `Users`               │ `Groups`              │
├──────────────────────────────┼───────────────────────┼───────────────────────┤
│ Text                         │ John Doe              │ Form builder users    │
├──────────────────────────────┼───────────────────────┼───────────────────────┤
│ Textarea                     │                       │ Form builder users    │
├──────────────────────────────┼───────────────────────┼───────────────────────┤
│ File                         │ Oscar, John Doe       │ Staff members         │
├──────────────────────────────┼───────────────────────┼───────────────────────┤
│ URL                          │                       │ Form builder users    │
├──────────────────────────────┼───────────────────────┼───────────────────────┤
│ Hidden                       │                       │ Form builder users    │
└──────────────────────────────┴───────────────────────┴───────────────────────┘

Management commands

There are several management commands available.

  • fobi_find_broken_entries. Find broken form element/handler entries that occur when some plugin which did exist in the system, no longer exists.
  • fobi_sync_plugins. Should be ran each time a new plugin is being added to the Fobi.
  • fobi_update_plugin_data. A mechanism to update existing plugin data in case if it had become invalid after a change in a plugin. In order for it to work, each plugin should implement and update method, in which the data update happens.

Tuning

There are number of Dash settings you can override in the settings module of your Django project:

  • FOBI_RESTRICT_PLUGIN_ACCESS (bool): If set to True, (Django) permission system for dash plugins is enabled. Defaults to True. Setting this to False makes all plugins available for all users.
  • FOBI_DEFAULT_THEME (str): Active (default) theme UID. Defaults to “bootstrap3”.
  • FORM_HANDLER_PLUGINS_EXECUTION_ORDER (list of tuples): Order in which the form handlers are executed. See the “Prioritise the excecution order” section for details.

For tuning of specific contrib plugin, see the docs in the plugin directory.

Bundled plugins and themes

Fobi ships with number of bundled form element- and form handler- plugins, as well as themes which are ready to be used as is.

Bundled form element plugins

Below a short overview of the form element plugins. See the README.rst file in directory of each plugin for details.

Content

Content plugins are presentational plugins, that make your forms look more

Bundled form handler plugins

Below a short overview of the form handler plugins. See the README.rst file in directory of each plugin for details.

  • DB store: Stores form data in a database.
  • HTTP repost: Repost the POST request to another endpoint.
  • Mail: Send the form data by email.

Bundled themes

Below a short overview of the themes. See the README.rst file in directory of each theme for details.

HTML5 fields

The following HTML5 fields are supported in appropriate bundled plugins:

  • date
  • datetime
  • email
  • max
  • min
  • number
  • url
  • placeholder
  • type

With the fobi.contrib.plugins.form_elements.fields.input support for HTML5 fields is extended to the following fields:

  • autocomplete
  • autofocus
  • list
  • multiple
  • pattern
  • step

Available translations

  • Dutch (core and plugins)
  • Russian (core and plugins)

Debugging

By default debugging is turned off. It means that broken form entries, which are entries with broken data, that are not possible to be shown, are just skipped. That’s safe in production. Although, you for sure would want to see the broken entries in development. Set the FOBI_DEBUG to True in the settings.py of your project in order to do so.

Most of the errors are logged (DEBUG). If you have written a plugin and it somehow doesn’t appear in the list of available plugins, do run the ./manage.py fobi_sync_plugins management command since it not only syncs your plugins into the database, but also is a great way of checking for possible errors.

If you have forms refering to form element- of form handler- plugins that are currently missing (not registered, removed, failed to load - thus there would be a risk that your form would’t be rendered properly/fully and the necessary data handling wouldn’t happen either) you will get an appropriate exception. Although it’s fine to get an instant error message about such failures in development, in production is wouldn’t look appropriate. Thus, there are two settings related to the non-existing (not-found) form element- and form handler- plugins.

  • FOBI_FAIL_ON_MISSING_FORM_ELEMENT_PLUGINS: If you want no error to be shown in case of missing form element plugins, set this to False in your settings module. Default value is True.
  • FOBI_FAIL_ON_MISSING_FORM_HANDLER_PLUGINS: If you want no error to be shown in case of missing form element handlers, set this to False in your settings module. Default value is True.

Troubleshooting

If you get a FormElementPluginDoesNotExist or a FormHandlerPluginDoesNotExist exception, make sure you have listed your plugin in the settings module of your project.

License

GPL 2.0/LGPL 2.1

Support

For any issues contact me at the e-mail given in the Author section.

Author

Artur Barseghyan <artur.barseghyan@gmail.com>

Screenshots

Bootstrap3 theme

Dashboard

  1. Dashboard
_images/01_dashboard.png

Create a form

  1. Create a form
_images/02_create_form.png

View/edit form

Form elements
  1. Edit form - form elements tab active, no elements yet
_images/03_edit_form_-_form_elements_tab_active_-_no_elements_yet.png
  1. Edit form - form elements tab active, add a form element menu
_images/04_edit_form_-_form_elements_tab_active_-_add_element_menu.png
  1. Edit form - add a form element (URL plugin)
_images/05_edit_form_-_add_form_element_url_plugin.png
  1. Edit form - form elements tab active, with form elements
_images/06_edit_form_-_form_elements_tab_active_-_with_elements.png
Form handlers
  1. Edit form - form handlers tab active, no handlers yet
_images/07_edit_form_-_form_handlers_tab_active_-_no_handlers_yet.png
  1. Edit form - form handlers tab tactive, add form handler menu
_images/08_edit_form_-_form_handlers_tab_active_-_add_handler_menu.png
  1. Edit form - add a form handler (Mail plugin)
_images/09_edit_form_-_add_form_handler_mail_plugin.png
  1. Edit form - form handlers tab active, with form handlers
_images/10_edit_form_-_form_handlers_tab_active_with_handlers.png
  1. Edit form - form properties tab active
_images/11_edit_form_-_form_properties_tab_active.png
  1. View form
_images/12_view_form.png
  1. View form - form submitted (thanks page)
_images/13_view_form_-_form_submitted.png
  1. Edit form - add a form element (Video plugin)
_images/14_edit_form_-_add_form_element_video_plugin.png
  1. Edit form - add a form element (Boolean plugin)
_images/15_edit_form_-_add_form_element_boolean_plugin.png
  1. Edit form
_images/16_edit_form.png
  1. View form
_images/17_view_form.png

Simple theme

View/edit form

  1. Edit form - form elements tab active, with form elements
_images/01_edit_form_-_form_elements_tab_active_with_elements.png
  1. Edit form - form elements tab active, add a form element menu
_images/02_edit_form_-_form_elements_tab_active_add_elements_menu.png
  1. Edit form - add a form element (Hidden plugin)
_images/03_edit_form_-_add_form_element_hidden.png
  1. Edit form - form handlers tab active, with form handlers
_images/04_edit_form_-_form_handlers_tab_active_with_handlers.png
  1. Edit form - form properties tab active
_images/05_edit_form_-_form_properties_tab_active.png
  1. View form
_images/06_view_form.png

Documentation

Contents:

fobi package

Subpackages

fobi.contrib package
Subpackages
fobi.contrib.apps package
Subpackages
fobi.contrib.apps.djangocms_integration package
Submodules
fobi.contrib.apps.djangocms_integration.apps module
fobi.contrib.apps.djangocms_integration.cms_plugins module
fobi.contrib.apps.djangocms_integration.conf module
fobi.contrib.apps.djangocms_integration.defaults module
fobi.contrib.apps.djangocms_integration.models module
fobi.contrib.apps.djangocms_integration.settings module
Module contents
fobi.contrib.apps.feincms_integration package
Submodules
fobi.contrib.apps.feincms_integration.apps module
class fobi.contrib.apps.feincms_integration.apps.Config(app_name, app_module)[source]

Bases: django.apps.config.AppConfig

label = 'fobi.contrib.apps.feincms_integration'
name = 'fobi.contrib.apps.feincms_integration'
fobi.contrib.apps.feincms_integration.conf module
fobi.contrib.apps.feincms_integration.conf.get_setting(setting, override=None)[source]

Get a setting from fobi.contrib.apps.feincms_integration conf module, falling back to the default.

If override is not None, it will be used instead of the setting.

Parameters:
  • setting – String with setting name
  • override – Value to use when no setting is available. Defaults to None.
Returns:

Setting value.

fobi.contrib.apps.feincms_integration.defaults module
fobi.contrib.apps.feincms_integration.helpers module
fobi.contrib.apps.feincms_integration.helpers.get_form_template_choices()[source]

Gets the form template choices. It’s possible to provide theme templates per theme or just per project.

Return list:
fobi.contrib.apps.feincms_integration.helpers.get_success_page_template_choices()[source]
Return list:
fobi.contrib.apps.feincms_integration.settings module
  • WIDGET_FORM_SENT_GET_PARAM (str): Name of the GET param indicating that form has been successfully sent.
fobi.contrib.apps.feincms_integration.widgets module
Module contents
Module contents
fobi.contrib.plugins package
Subpackages
fobi.contrib.plugins.form_elements package
Subpackages
fobi.contrib.plugins.form_elements.content package
Subpackages
fobi.contrib.plugins.form_elements.content.dummy package
Submodules
fobi.contrib.plugins.form_elements.content.dummy.apps module
class fobi.contrib.plugins.form_elements.content.dummy.apps.Config(app_name, app_module)[source]

Bases: django.apps.config.AppConfig

label = 'fobi.contrib.plugins.form_elements.content.dummy'
name = 'fobi.contrib.plugins.form_elements.content.dummy'
fobi.contrib.plugins.form_elements.content.dummy.fobi_form_elements module
class fobi.contrib.plugins.form_elements.content.dummy.fobi_form_elements.DummyPlugin(user=None)[source]

Bases: fobi.base.FormElementPlugin

Dummy plugin.

get_form_field_instances()[source]

Get form field instances.

group = <django.utils.functional.__proxy__ object at 0x7f7ff7492b90>
name = <django.utils.functional.__proxy__ object at 0x7f7ff7492c90>
post_processor()[source]

Always the same.

uid = 'dummy'
fobi.contrib.plugins.form_elements.content.dummy.widgets module
class fobi.contrib.plugins.form_elements.content.dummy.widgets.BaseDummyPluginWidget(plugin)[source]

Bases: fobi.base.FormElementPluginWidget

Base dummy form element plugin widget.

plugin_uid = 'dummy'
Module contents
fobi.contrib.plugins.form_elements.content.image package
Submodules
fobi.contrib.plugins.form_elements.content.image.apps module
class fobi.contrib.plugins.form_elements.content.image.apps.Config(app_name, app_module)[source]

Bases: django.apps.config.AppConfig

label = 'fobi.contrib.plugins.form_elements.content.image'
name = 'fobi.contrib.plugins.form_elements.content.image'
fobi.contrib.plugins.form_elements.content.image.conf module
fobi.contrib.plugins.form_elements.content.image.conf.get_setting(setting, override=None)[source]

Get a setting from fobi.contrib.plugins.form_elements.content.image conf module, falling back to the default.

If override is not None, it will be used instead of the setting.

Parameters:
  • setting – String with setting name
  • override – Value to use when no setting is available. Defaults to None.
Returns:

Setting value.

fobi.contrib.plugins.form_elements.content.image.defaults module
fobi.contrib.plugins.form_elements.content.image.fobi_form_elements module
fobi.contrib.plugins.form_elements.content.image.forms module
fobi.contrib.plugins.form_elements.content.image.helpers module
fobi.contrib.plugins.form_elements.content.image.helpers.handle_uploaded_file(image_file)[source]
Parameters:image_file (django.core.files.uploadedfile.InMemoryUploadedFile) –
Return string:Path to the image (relative).
fobi.contrib.plugins.form_elements.content.image.helpers.get_crop_filter(fit_method)[source]
fobi.contrib.plugins.form_elements.content.image.helpers.delete_file(image_file)[source]

Delete file from disc.

fobi.contrib.plugins.form_elements.content.image.helpers.ensure_unique_filename(destination)[source]

Makes sure filenames are never overwritten.

Parameters:destination (string) –
Return string:
fobi.contrib.plugins.form_elements.content.image.helpers.clone_file(source_filename, relative_path=True)[source]

Clones the file.

Parameters:source_filename (string) – Source filename.
Return string:Filename of the cloned file.
fobi.contrib.plugins.form_elements.content.image.settings module
  • FIT_METHOD_CROP_SMART (string)
  • FIT_METHOD_CROP_CENTER (string)
  • FIT_METHOD_CROP_SCALE (string)
  • FIT_METHOD_FIT_WIDTH (string)
  • FIT_METHOD_FIT_HEIGHT (string)
  • DEFAULT_FIT_METHOD (string)
  • FIT_METHODS_CHOICES (tuple)
  • FIT_METHODS_CHOICES_WITH_EMPTY_OPTION (list)
  • IMAGES_UPLOAD_DIR (string)
Module contents
fobi.contrib.plugins.form_elements.content.text package
Submodules
fobi.contrib.plugins.form_elements.content.text.apps module
class fobi.contrib.plugins.form_elements.content.text.apps.Config(app_name, app_module)[source]

Bases: django.apps.config.AppConfig

label = 'fobi.contrib.plugins.form_elements.content.text'
name = 'fobi.contrib.plugins.form_elements.content.text'
fobi.contrib.plugins.form_elements.content.text.fobi_form_elements module
fobi.contrib.plugins.form_elements.content.text.forms module
Module contents
fobi.contrib.plugins.form_elements.content.video package
Submodules
fobi.contrib.plugins.form_elements.content.video.apps module
class fobi.contrib.plugins.form_elements.content.video.apps.Config(app_name, app_module)[source]

Bases: django.apps.config.AppConfig

label = 'fobi.contrib.plugins.form_elements.content.video'
name = 'fobi.contrib.plugins.form_elements.content.video'
fobi.contrib.plugins.form_elements.content.video.conf module
fobi.contrib.plugins.form_elements.content.video.conf.get_setting(setting, override=None)[source]

Get a setting from fobi.contrib.plugins.form_elements.content.video conf module, falling back to the default.

If override is not None, it will be used instead of the setting.

Parameters:
  • setting – String with setting name
  • override – Value to use when no setting is available. Defaults to None.
Returns:

Setting value.

fobi.contrib.plugins.form_elements.content.video.defaults module
fobi.contrib.plugins.form_elements.content.video.fobi_form_elements module
fobi.contrib.plugins.form_elements.content.video.forms module
fobi.contrib.plugins.form_elements.content.video.settings module
Module contents
Module contents
fobi.contrib.plugins.form_elements.fields package
Subpackages
fobi.contrib.plugins.form_elements.fields.boolean package
Submodules
fobi.contrib.plugins.form_elements.fields.boolean.apps module
class fobi.contrib.plugins.form_elements.fields.boolean.apps.Config(app_name, app_module)[source]

Bases: django.apps.config.AppConfig

label = 'fobi.contrib.plugins.form_elements.fields.boolean'
name = 'fobi.contrib.plugins.form_elements.fields.boolean'
fobi.contrib.plugins.form_elements.fields.boolean.fobi_form_elements module
fobi.contrib.plugins.form_elements.fields.boolean.forms module
Module contents
fobi.contrib.plugins.form_elements.fields.captcha package
Submodules
fobi.contrib.plugins.form_elements.fields.captcha.apps module
class fobi.contrib.plugins.form_elements.fields.captcha.apps.Config(app_name, app_module)[source]

Bases: django.apps.config.AppConfig

label = 'fobi.contrib.plugins.form_elements.fields.captcha'
name = 'fobi.contrib.plugins.form_elements.fields.captcha'
fobi.contrib.plugins.form_elements.fields.captcha.fobi_form_elements module
fobi.contrib.plugins.form_elements.fields.captcha.forms module
Module contents
fobi.contrib.plugins.form_elements.fields.date package
Submodules
fobi.contrib.plugins.form_elements.fields.date.apps module
class fobi.contrib.plugins.form_elements.fields.date.apps.Config(app_name, app_module)[source]

Bases: django.apps.config.AppConfig

label = 'fobi.contrib.plugins.form_elements.fields.date'
name = 'fobi.contrib.plugins.form_elements.fields.date'
fobi.contrib.plugins.form_elements.fields.date.fobi_form_elements module
fobi.contrib.plugins.form_elements.fields.date.forms module
Module contents
fobi.contrib.plugins.form_elements.fields.datetime package
Submodules
fobi.contrib.plugins.form_elements.fields.datetime.apps module
class fobi.contrib.plugins.form_elements.fields.datetime.apps.Config(app_name, app_module)[source]

Bases: django.apps.config.AppConfig

label = 'fobi.contrib.plugins.form_elements.fields.datetime'
name = 'fobi.contrib.plugins.form_elements.fields.datetime'
fobi.contrib.plugins.form_elements.fields.datetime.fobi_form_elements module
fobi.contrib.plugins.form_elements.fields.datetime.forms module
Module contents
fobi.contrib.plugins.form_elements.fields.email package
Submodules
fobi.contrib.plugins.form_elements.fields.email.apps module
class fobi.contrib.plugins.form_elements.fields.email.apps.Config(app_name, app_module)[source]

Bases: django.apps.config.AppConfig

label = 'fobi.contrib.plugins.form_elements.fields.email'
name = 'fobi.contrib.plugins.form_elements.fields.email'
fobi.contrib.plugins.form_elements.fields.email.fobi_form_elements module
fobi.contrib.plugins.form_elements.fields.email.forms module
Module contents
fobi.contrib.plugins.form_elements.fields.file package
Submodules
fobi.contrib.plugins.form_elements.fields.file.apps module
class fobi.contrib.plugins.form_elements.fields.file.apps.Config(app_name, app_module)[source]

Bases: django.apps.config.AppConfig

label = 'fobi.contrib.plugins.form_elements.fields.file'
name = 'fobi.contrib.plugins.form_elements.fields.file'
fobi.contrib.plugins.form_elements.fields.file.conf module
fobi.contrib.plugins.form_elements.fields.file.conf.get_setting(setting, override=None)[source]

Get a setting from fobi.contrib.plugins.form_elements.fields.conf module, falling back to the default.

If override is not None, it will be used instead of the setting.

Parameters:
  • setting – String with setting name
  • override – Value to use when no setting is available. Defaults to None.
Returns:

Setting value.

fobi.contrib.plugins.form_elements.fields.file.defaults module
fobi.contrib.plugins.form_elements.fields.file.fobi_form_elements module
fobi.contrib.plugins.form_elements.fields.file.forms module
fobi.contrib.plugins.form_elements.fields.file.settings module
  • FILES_UPLOAD_DIR (string)
Module contents
fobi.contrib.plugins.form_elements.fields.hidden package
Submodules
fobi.contrib.plugins.form_elements.fields.hidden.apps module
class fobi.contrib.plugins.form_elements.fields.hidden.apps.Config(app_name, app_module)[source]

Bases: django.apps.config.AppConfig

label = 'fobi.contrib.plugins.form_elements.fields.hidden'
name = 'fobi.contrib.plugins.form_elements.fields.hidden'
fobi.contrib.plugins.form_elements.fields.hidden.fobi_form_elements module
fobi.contrib.plugins.form_elements.fields.hidden.forms module
Module contents
fobi.contrib.plugins.form_elements.fields.input package
Submodules
fobi.contrib.plugins.form_elements.fields.input.apps module
class fobi.contrib.plugins.form_elements.fields.input.apps.Config(app_name, app_module)[source]

Bases: django.apps.config.AppConfig

label = 'fobi.contrib.plugins.form_elements.fields.input'
name = 'fobi.contrib.plugins.form_elements.fields.input'
fobi.contrib.plugins.form_elements.fields.input.constants module
fobi.contrib.plugins.form_elements.fields.input.fobi_form_elements module
fobi.contrib.plugins.form_elements.fields.input.forms module
Module contents
fobi.contrib.plugins.form_elements.fields.integer package
Submodules
fobi.contrib.plugins.form_elements.fields.integer.apps module
class fobi.contrib.plugins.form_elements.fields.integer.apps.Config(app_name, app_module)[source]

Bases: django.apps.config.AppConfig

label = 'fobi.contrib.plugins.form_elements.fields.integer'
name = 'fobi.contrib.plugins.form_elements.fields.integer'
fobi.contrib.plugins.form_elements.fields.integer.fobi_form_elements module
fobi.contrib.plugins.form_elements.fields.integer.forms module
Module contents
fobi.contrib.plugins.form_elements.fields.password package
Submodules
fobi.contrib.plugins.form_elements.fields.password.apps module
class fobi.contrib.plugins.form_elements.fields.password.apps.Config(app_name, app_module)[source]

Bases: django.apps.config.AppConfig

label = 'fobi.contrib.plugins.form_elements.fields.password'
name = 'fobi.contrib.plugins.form_elements.fields.password'
fobi.contrib.plugins.form_elements.fields.password.fobi_form_elements module
fobi.contrib.plugins.form_elements.fields.password.forms module
Module contents
fobi.contrib.plugins.form_elements.fields.radio package
Submodules
fobi.contrib.plugins.form_elements.fields.radio.apps module
class fobi.contrib.plugins.form_elements.fields.radio.apps.Config(app_name, app_module)[source]

Bases: django.apps.config.AppConfig

label = 'fobi.contrib.plugins.form_elements.fields.radio'
name = 'fobi.contrib.plugins.form_elements.fields.radio'
fobi.contrib.plugins.form_elements.fields.radio.fobi_form_elements module
fobi.contrib.plugins.form_elements.fields.radio.forms module
Module contents
fobi.contrib.plugins.form_elements.fields.select package
Submodules
fobi.contrib.plugins.form_elements.fields.select.apps module
class fobi.contrib.plugins.form_elements.fields.select.apps.Config(app_name, app_module)[source]

Bases: django.apps.config.AppConfig

label = 'fobi.contrib.plugins.form_elements.fields.select'
name = 'fobi.contrib.plugins.form_elements.fields.select'
fobi.contrib.plugins.form_elements.fields.select.fobi_form_elements module
fobi.contrib.plugins.form_elements.fields.select.forms module
Module contents
fobi.contrib.plugins.form_elements.fields.select_model_object package
Submodules
fobi.contrib.plugins.form_elements.fields.select_model_object.apps module
class fobi.contrib.plugins.form_elements.fields.select_model_object.apps.Config(app_name, app_module)[source]

Bases: django.apps.config.AppConfig

label = 'fobi.contrib.plugins.form_elements.fields.select_model_object'
name = 'fobi.contrib.plugins.form_elements.fields.select_model_object'
fobi.contrib.plugins.form_elements.fields.select_model_object.conf module
fobi.contrib.plugins.form_elements.fields.select_model_object.conf.get_setting(setting, override=None)[source]

Get a setting from fobi.contrib.plugins.form_elements.fields.select_model_object conf module, falling back to the default.

If override is not None, it will be used instead of the setting.

Parameters:
  • setting – String with setting name
  • override – Value to use when no setting is available. Defaults to None.
Returns:

Setting value.

fobi.contrib.plugins.form_elements.fields.select_model_object.defaults module
fobi.contrib.plugins.form_elements.fields.select_model_object.fobi_form_elements module
fobi.contrib.plugins.form_elements.fields.select_model_object.forms module
fobi.contrib.plugins.form_elements.fields.select_model_object.settings module
Module contents
fobi.contrib.plugins.form_elements.fields.select_multiple package
Submodules
fobi.contrib.plugins.form_elements.fields.select_multiple.apps module
class fobi.contrib.plugins.form_elements.fields.select_multiple.apps.Config(app_name, app_module)[source]

Bases: django.apps.config.AppConfig

label = 'fobi.contrib.plugins.form_elements.fields.select_multiple'
name = 'fobi.contrib.plugins.form_elements.fields.select_multiple'
fobi.contrib.plugins.form_elements.fields.select_multiple.fobi_form_elements module
fobi.contrib.plugins.form_elements.fields.select_multiple.forms module
Module contents
fobi.contrib.plugins.form_elements.fields.select_multiple_model_objects package
Submodules
fobi.contrib.plugins.form_elements.fields.select_multiple_model_objects.apps module
class fobi.contrib.plugins.form_elements.fields.select_multiple_model_objects.apps.Config(app_name, app_module)[source]

Bases: django.apps.config.AppConfig

label = 'fobi.contrib.plugins.form_elements.fields.select_multiple_model_objects'
name = 'fobi.contrib.plugins.form_elements.fields.select_multiple_model_objects'
fobi.contrib.plugins.form_elements.fields.select_multiple_model_objects.conf module
fobi.contrib.plugins.form_elements.fields.select_multiple_model_objects.conf.get_setting(setting, override=None)[source]

Get a setting from fobi.contrib.plugins.form_elements.fields.select_multiple_model_objects conf module, falling back to the default.

If override is not None, it will be used instead of the setting.

Parameters:
  • setting – String with setting name
  • override – Value to use when no setting is available. Defaults to None.
Returns:

Setting value.

fobi.contrib.plugins.form_elements.fields.select_multiple_model_objects.defaults module
fobi.contrib.plugins.form_elements.fields.select_multiple_model_objects.fobi_form_elements module
fobi.contrib.plugins.form_elements.fields.select_multiple_model_objects.forms module
fobi.contrib.plugins.form_elements.fields.select_multiple_model_objects.settings module
Module contents
fobi.contrib.plugins.form_elements.fields.text package
Submodules
fobi.contrib.plugins.form_elements.fields.text.apps module
class fobi.contrib.plugins.form_elements.fields.text.apps.Config(app_name, app_module)[source]

Bases: django.apps.config.AppConfig

label = 'fobi.contrib.plugins.form_elements.fields.text'
name = 'fobi.contrib.plugins.form_elements.fields.text'
fobi.contrib.plugins.form_elements.fields.text.fobi_form_elements module
fobi.contrib.plugins.form_elements.fields.text.forms module
Module contents
fobi.contrib.plugins.form_elements.fields.textarea package
Submodules
fobi.contrib.plugins.form_elements.fields.textarea.apps module
class fobi.contrib.plugins.form_elements.fields.textarea.apps.Config(app_name, app_module)[source]

Bases: django.apps.config.AppConfig

label = 'fobi.contrib.plugins.form_elements.fields.textarea'
name = 'fobi.contrib.plugins.form_elements.fields.textarea'
fobi.contrib.plugins.form_elements.fields.textarea.fobi_form_elements module
fobi.contrib.plugins.form_elements.fields.textarea.forms module
Module contents
fobi.contrib.plugins.form_elements.fields.url package
Submodules
fobi.contrib.plugins.form_elements.fields.url.apps module
class fobi.contrib.plugins.form_elements.fields.url.apps.Config(app_name, app_module)[source]

Bases: django.apps.config.AppConfig

label = 'fobi.contrib.plugins.form_elements.fields.url'
name = 'fobi.contrib.plugins.form_elements.fields.url'
fobi.contrib.plugins.form_elements.fields.url.fobi_form_elements module
fobi.contrib.plugins.form_elements.fields.url.forms module
Module contents
Module contents
Module contents
fobi.contrib.plugins.form_handlers package
Subpackages
fobi.contrib.plugins.form_handlers.db_store package
Submodules
fobi.contrib.plugins.form_handlers.db_store.admin module
class fobi.contrib.plugins.form_handlers.db_store.admin.SavedFormDataEntryAdmin(model, admin_site)[source]

Bases: django.contrib.admin.options.ModelAdmin

Saved form data entry admin.

class Media[source]
js = ('/static/js/jquery-1.10.2.min.js', '/static/db_store/js/db_store.js', '/static/db_store/js/jquery.expander.min.js')
class SavedFormDataEntryAdmin.Meta[source]
app_label = <django.utils.functional.__proxy__ object at 0x7f7ff6404b10>
SavedFormDataEntryAdmin.actions = ['export_data']
SavedFormDataEntryAdmin.export_data(request, queryset)[source]

Export data into XLS.

SavedFormDataEntryAdmin.fieldsets = ((None, {'fields': ('form_entry', 'user')}), (<django.utils.functional.__proxy__ object at 0x7f7ff6404350>, {'fields': ('formatted_saved_data', 'created')}), (<django.utils.functional.__proxy__ object at 0x7f7ff6404bd0>, {'fields': ('form_data_headers', 'saved_data'), 'classes': ('collapse',)}))
SavedFormDataEntryAdmin.get_queryset(request)
SavedFormDataEntryAdmin.list_display = ('form_entry', 'user', 'formatted_saved_data', 'created')
SavedFormDataEntryAdmin.list_filter = ('form_entry', 'user')
SavedFormDataEntryAdmin.media
SavedFormDataEntryAdmin.queryset(request)[source]
SavedFormDataEntryAdmin.readonly_fields = ('created', 'formatted_saved_data')
fobi.contrib.plugins.form_handlers.db_store.apps module
class fobi.contrib.plugins.form_handlers.db_store.apps.Config(app_name, app_module)[source]

Bases: django.apps.config.AppConfig

label = 'fobi.contrib.plugins.form_handlers.db_store'
name = 'fobi.contrib.plugins.form_handlers.db_store'
fobi.contrib.plugins.form_handlers.db_store.conf module
fobi.contrib.plugins.form_handlers.db_store.conf.get_setting(setting, override=None)[source]

Get a setting from fobi.contrib.plugins.form_elements.content.image conf module, falling back to the default.

If override is not None, it will be used instead of the setting.

Parameters:
  • setting – String with setting name
  • override – Value to use when no setting is available. Defaults to None.
Returns:

Setting value.

fobi.contrib.plugins.form_handlers.db_store.defaults module
fobi.contrib.plugins.form_handlers.db_store.fobi_form_handlers module
class fobi.contrib.plugins.form_handlers.db_store.fobi_form_handlers.DBStoreHandlerPlugin(user=None)[source]

Bases: fobi.base.FormHandlerPlugin

custom_actions(form_entry, request=None)[source]

Adding a link to view the saved form enties.

Return iterable:
 
name = <django.utils.functional.__proxy__ object at 0x7f7ff74c2290>
run(form_entry, request, form)[source]
Parameters:
  • form_entry (fobi.models.FormEntry) – Instance of fobi.models.FormEntry.
  • request (django.http.HttpRequest) –
  • form (django.forms.Form) –
uid = 'db_store'
fobi.contrib.plugins.form_handlers.db_store.helpers module
class fobi.contrib.plugins.form_handlers.db_store.helpers.DataExporter(queryset)[source]

Bases: object

Exporting the data.

export_to_csv()[source]

Export data to CSV.

export_to_xls()[source]
graceful_export()[source]

Export data into XLS/CSV depending on what is available.

fobi.contrib.plugins.form_handlers.db_store.models module
class fobi.contrib.plugins.form_handlers.db_store.models.SavedFormDataEntry(*args, **kwargs)[source]

Bases: django.db.models.base.Model

Saved form data.

exception DoesNotExist

Bases: django.core.exceptions.ObjectDoesNotExist

exception SavedFormDataEntry.MultipleObjectsReturned

Bases: django.core.exceptions.MultipleObjectsReturned

SavedFormDataEntry.form_entry
SavedFormDataEntry.formatted_saved_data()[source]

Shows the formatted saved data records.

Return string:
SavedFormDataEntry.get_next_by_created(*moreargs, **morekwargs)
SavedFormDataEntry.get_previous_by_created(*moreargs, **morekwargs)
SavedFormDataEntry.objects = <django.db.models.manager.Manager object at 0x7f7ff74c2310>
SavedFormDataEntry.user
fobi.contrib.plugins.form_handlers.db_store.settings module
  • CSV_DELIMITER (string)
  • CSV_QUOTECHAR (string)
fobi.contrib.plugins.form_handlers.db_store.urls module
fobi.contrib.plugins.form_handlers.db_store.views module
fobi.contrib.plugins.form_handlers.db_store.views.view_saved_form_data_entries(request, *args, **kwargs)[source]

View saved form data entries.

Parameters:
  • request (django.http.HttpRequest) –
  • form_entry_id (int) – Form ID.
  • theme (fobi.base.BaseTheme) – Subclass of fobi.base.BaseTheme.
  • template_name (string) –
Return django.http.HttpResponse:
 
Module contents
fobi.contrib.plugins.form_handlers.http_repost package
Submodules
fobi.contrib.plugins.form_handlers.http_repost.apps module
class fobi.contrib.plugins.form_handlers.http_repost.apps.Config(app_name, app_module)[source]

Bases: django.apps.config.AppConfig

label = 'fobi.contrib.plugins.form_handlers.http_repost'
name = 'fobi.contrib.plugins.form_handlers.http_repost'
fobi.contrib.plugins.form_handlers.http_repost.fobi_form_handlers module
fobi.contrib.plugins.form_handlers.http_repost.forms module
fobi.contrib.plugins.form_handlers.http_repost.helpers module
Module contents
fobi.contrib.plugins.form_handlers.mail package
Submodules
fobi.contrib.plugins.form_handlers.mail.apps module
class fobi.contrib.plugins.form_handlers.mail.apps.Config(app_name, app_module)[source]

Bases: django.apps.config.AppConfig

label = 'fobi.contrib.plugins.form_handlers.mail'
name = 'fobi.contrib.plugins.form_handlers.mail'
fobi.contrib.plugins.form_handlers.mail.fobi_form_handlers module
fobi.contrib.plugins.form_handlers.mail.forms module
Module contents
Module contents
fobi.contrib.plugins.form_importers package
Subpackages
fobi.contrib.plugins.form_importers.mailchimp_importer package
Submodules
fobi.contrib.plugins.form_importers.mailchimp_importer.apps module
fobi.contrib.plugins.form_importers.mailchimp_importer.fobi_form_importers module
fobi.contrib.plugins.form_importers.mailchimp_importer.tests module
Module contents
Module contents
Module contents
fobi.contrib.themes package
Subpackages
fobi.contrib.themes.bootstrap3 package
Submodules
fobi.contrib.themes.bootstrap3.apps module
class fobi.contrib.themes.bootstrap3.apps.Config(app_name, app_module)[source]

Bases: django.apps.config.AppConfig

label = 'fobi.contrib.themes.bootstrap3'
name = 'fobi.contrib.themes.bootstrap3'
fobi.contrib.themes.bootstrap3.fobi_form_elements module
class fobi.contrib.themes.bootstrap3.fobi_form_elements.DummyPluginWidget(plugin)[source]

Bases: fobi.contrib.plugins.form_elements.content.dummy.widgets.BaseDummyPluginWidget

Dummy plugin widget for Boootstrap 3.

media_css = ['dummy/css/fobi.plugins.form_elements.dummy.css']
media_js = ['dummy/js/fobi.plugins.form_elements.dummy.js']
theme_uid = 'bootstrap3'
fobi.contrib.themes.bootstrap3.fobi_themes module
class fobi.contrib.themes.bootstrap3.fobi_themes.Bootstrap3Theme(user=None)[source]

Bases: fobi.base.BaseTheme

Bootstrap3 theme.

add_form_element_entry_ajax_template = 'bootstrap3/add_form_element_entry_ajax.html'
add_form_element_entry_template = 'bootstrap3/add_form_element_entry.html'
add_form_handler_entry_ajax_template = 'bootstrap3/add_form_handler_entry_ajax.html'
add_form_handler_entry_template = 'bootstrap3/add_form_handler_entry.html'
base_template = 'bootstrap3/base.html'
create_form_entry_ajax_template = 'bootstrap3/create_form_entry_ajax.html'
create_form_entry_template = 'bootstrap3/create_form_entry.html'
dashboard_template = 'bootstrap3/dashboard.html'
edit_form_element_entry_ajax_template = 'bootstrap3/edit_form_element_entry_ajax.html'
edit_form_element_entry_template = 'bootstrap3/edit_form_element_entry.html'
edit_form_entry_ajax_template = 'bootstrap3/edit_form_entry_ajax.html'
edit_form_entry_template = 'bootstrap3/edit_form_entry.html'
edit_form_handler_entry_ajax_template = 'bootstrap3/edit_form_handler_entry_ajax.html'
edit_form_handler_entry_template = 'bootstrap3/edit_form_handler_entry.html'
embed_form_entry_submitted_ajax_template = 'bootstrap3/embed_form_entry_submitted_ajax.html'
form_ajax = 'bootstrap3/snippets/form_ajax.html'
form_delete_form_entry_option_class = 'glyphicon glyphicon-remove'
form_edit_form_entry_option_class = 'glyphicon glyphicon-edit'
form_element_checkbox_html_class = 'checkbox'
form_element_html_class = 'form-control'
form_entry_submitted_ajax_template = 'bootstrap3/form_entry_submitted_ajax.html'
form_entry_submitted_template = 'bootstrap3/form_entry_submitted.html'
form_list_container_class = 'list-inline'
form_properties_snippet_template_name = 'bootstrap3/snippets/form_properties_snippet.html'
form_snippet_template_name = 'bootstrap3/snippets/form_snippet.html'
master_base_template = 'bootstrap3/_base.html'
media_css = ('bootstrap3/css/bootstrap.css', 'css/fobi.core.css')
media_js = ('js/jquery-1.10.2.min.js', 'jquery-ui/js/jquery-ui-1.10.4.custom.min.js', 'bootstrap3/js/bootstrap.min.js', 'js/jquery.slugify.js', 'js/fobi.core.js', 'bootstrap3/js/bootstrap3_fobi_extras.js')
messages_snippet_template_name = 'bootstrap3/snippets/messages_snippet.html'
name = <django.utils.functional.__proxy__ object at 0x7f7ff7409050>
uid = 'bootstrap3'
view_embed_form_entry_ajax_template = 'bootstrap3/view_embed_form_entry_ajax.html'
view_form_entry_ajax_template = 'bootstrap3/view_form_entry_ajax.html'
view_form_entry_template = 'bootstrap3/view_form_entry.html'
Module contents
fobi.contrib.themes.foundation5 package
Submodules
fobi.contrib.themes.foundation5.apps module
class fobi.contrib.themes.foundation5.apps.Config(app_name, app_module)[source]

Bases: django.apps.config.AppConfig

label = 'fobi.contrib.themes.foundation5'
name = 'fobi.contrib.themes.foundation5'
fobi.contrib.themes.foundation5.fobi_themes module
class fobi.contrib.themes.foundation5.fobi_themes.Foundation5Theme(user=None)[source]

Bases: fobi.base.BaseTheme

Foundation5 theme. Based on the “Workspace” example of the Foundation 5. Click here for more.

add_form_element_entry_ajax_template = 'foundation5/add_form_element_entry_ajax.html'
add_form_element_entry_template = 'foundation5/add_form_element_entry.html'
add_form_handler_entry_ajax_template = 'foundation5/add_form_handler_entry_ajax.html'
add_form_handler_entry_template = 'foundation5/add_form_handler_entry.html'
base_template = 'foundation5/base.html'
create_form_entry_ajax_template = 'foundation5/create_form_entry_ajax.html'
create_form_entry_template = 'foundation5/create_form_entry.html'
dashboard_template = 'foundation5/dashboard.html'
edit_form_element_entry_ajax_template = 'foundation5/edit_form_element_entry_ajax.html'
edit_form_element_entry_template = 'foundation5/edit_form_element_entry.html'
edit_form_entry_ajax_template = 'foundation5/edit_form_entry_ajax.html'
edit_form_entry_template = 'foundation5/edit_form_entry.html'
edit_form_handler_entry_ajax_template = 'foundation5/edit_form_handler_entry_ajax.html'
edit_form_handler_entry_template = 'foundation5/edit_form_handler_entry.html'
form_ajax = 'foundation5/snippets/form_ajax.html'
form_delete_form_entry_option_class = 'fi-page-delete'
form_edit_form_entry_option_class = 'fi-page-edit'
form_element_checkbox_html_class = 'checkbox'
form_element_html_class = 'form-control'
form_entry_submitted_ajax_template = 'foundation5/form_entry_submitted_ajax.html'
form_entry_submitted_template = 'foundation5/form_entry_submitted.html'
form_list_container_class = 'inline-list'
form_properties_snippet_template_name = 'foundation5/snippets/form_properties_snippet.html'
form_snippet_template_name = 'foundation5/snippets/form_snippet.html'
master_base_template = 'foundation5/_base.html'
media_css = ('foundation5/css/foundation.min.css', 'foundation5/css/foundation_fobi_extras.css', 'foundation5/icons/3/icons/foundation-icons.css')
media_js = ('foundation5/js/vendor/modernizr.js', 'foundation5/js/vendor/jquery.js', 'jquery-ui/js/jquery-ui-1.10.4.custom.min.js', 'foundation5/js/foundation.min.js', 'js/fobi.core.js', 'js/jquery.slugify.js', 'foundation5/js/foundation5_fobi_extras.js')
messages_snippet_template_name = 'foundation5/snippets/messages_snippet.html'
name = <django.utils.functional.__proxy__ object at 0x7f7ff7409250>
uid = 'foundation5'
view_form_entry_ajax_template = 'foundation5/view_form_entry_ajax.html'
view_form_entry_template = 'foundation5/view_form_entry.html'
Module contents
fobi.contrib.themes.simple package
Submodules
fobi.contrib.themes.simple.apps module
class fobi.contrib.themes.simple.apps.Config(app_name, app_module)[source]

Bases: django.apps.config.AppConfig

label = 'fobi.contrib.themes.simple'
name = 'fobi.contrib.themes.simple'
fobi.contrib.themes.simple.fobi_themes module
class fobi.contrib.themes.simple.fobi_themes.SimpleTheme(user=None)[source]

Bases: fobi.base.BaseTheme

Simple theme that has a native Django style.

add_form_element_entry_ajax_template = 'simple/add_form_element_entry_ajax.html'
add_form_element_entry_template = 'simple/add_form_element_entry.html'
add_form_handler_entry_ajax_template = 'simple/add_form_handler_entry_ajax.html'
add_form_handler_entry_template = 'simple/add_form_handler_entry.html'
base_edit_template = 'simple/base_edit.html'
base_template = 'simple/base.html'
base_view_template = 'simple/base_view.html'
create_form_entry_ajax_template = 'simple/create_form_entry_ajax.html'
create_form_entry_template = 'simple/create_form_entry.html'
dashboard_template = 'simple/dashboard.html'
edit_form_element_entry_ajax_template = 'simple/edit_form_element_entry_ajax.html'
edit_form_element_entry_template = 'simple/edit_form_element_entry.html'
edit_form_entry_ajax_template = 'simple/edit_form_entry_ajax.html'
edit_form_entry_template = 'simple/edit_form_entry.html'
edit_form_handler_entry_ajax_template = 'simple/edit_form_handler_entry_ajax.html'
edit_form_handler_entry_template = 'simple/edit_form_handler_entry.html'
form_ajax = 'simple/snippets/form_ajax.html'
form_delete_form_entry_option_class = 'glyphicon glyphicon-remove'
form_edit_ajax = 'simple/snippets/form_edit_ajax.html'
form_edit_form_entry_option_class = 'glyphicon glyphicon-edit'
form_edit_snippet_template_name = 'simple/snippets/form_edit_snippet.html'
form_element_checkbox_html_class = 'checkbox'
form_element_html_class = 'vTextField'
form_entry_submitted_ajax_template = 'simple/form_entry_submitted_ajax.html'
form_entry_submitted_template = 'simple/form_entry_submitted.html'
form_list_container_class = 'list-inline'
form_properties_snippet_template_name = 'simple/snippets/form_properties_snippet.html'
form_radio_element_html_class = 'radiolist'
form_snippet_template_name = 'simple/snippets/form_snippet.html'
form_view_snippet_template_name = 'simple/snippets/form_view_snippet.html'
master_base_template = 'simple/_base.html'
media_css = ('simple/css/fobi.simple.css', 'jquery-ui/css/django-admin-theme/jquery-ui-1.10.4.custom.min.css')
media_js = ('js/jquery-1.10.2.min.js', 'jquery-ui/js/jquery-ui-1.10.4.custom.min.js', 'js/jquery.slugify.js', 'js/fobi.core.js')
messages_snippet_template_name = 'simple/snippets/messages_snippet.html'
name = <django.utils.functional.__proxy__ object at 0x7f7ff74095d0>
uid = 'simple'
view_form_entry_ajax_template = 'simple/view_form_entry_ajax.html'
view_form_entry_template = 'simple/view_form_entry.html'
Module contents
Module contents
Module contents
fobi.management package
Subpackages
fobi.management.commands package
Submodules
fobi.management.commands.fobi_find_broken_entries module
fobi.management.commands.fobi_sync_plugins module
fobi.management.commands.fobi_update_plugin_data module
Module contents
Module contents
fobi.templatetags package
Submodules
fobi.templatetags.fobi_tags module
fobi.templatetags.fobi_tags.get_fobi_plugin(parser, token)[source]

Gets the plugin. Note, that entry shall be a instance of fobi.models.FormElementEntry or fobi.models.FormHandlerEntry.

Syntax:

{% get_fobi_plugin entry as [context_var_name] %}

Example:

{% get_fobi_plugin entry as plugin %}

{% get_fobi_plugin entry as plugin %} {{ plugin.render }}

fobi.templatetags.fobi_tags.get_fobi_form_handler_plugin_custom_actions(parser, token)[source]

Gets the form handler plugin custom actions. Note, that plugin shall be a instance of fobi.models.FormHandlerEntry.

Syntax:{% get_fobi_form_handler_plugin_custom_actions [plugin] [form_entry] as [context_var_name] %}
Example:{% get_fobi_form_handler_plugin_custom_actions plugin form_entry as form_handler_plugin_custom_actions %}
fobi.templatetags.future_compat module
fobi.templatetags.future_compat.firstof(parser, token, escape=False)[source]

Outputs the first variable passed that is not False, without escaping.

Outputs nothing if all the passed variables are False.

Sample usage:

{% firstof var1 var2 var3 %}

This is equivalent to:

{% if var1 %}
    {{ var1|safe }}
{% elif var2 %}
    {{ var2|safe }}
{% elif var3 %}
    {{ var3|safe }}
{% endif %}

but obviously much cleaner!

You can also use a literal string as a fallback value in case all passed variables are False:

{% firstof var1 var2 var3 "fallback value" %}

If you want to escape the output, use a filter tag:

{% filter force_escape %}
    {% firstof var1 var2 var3 "fallback value" %}
{% endfilter %}
Module contents
fobi.tests package
Submodules
fobi.tests.base module
fobi.tests.constants module
fobi.tests.data module
fobi.tests.helpers module
fobi.tests.test_browser_build_dynamic_forms module
fobi.tests.test_core module
fobi.tests.test_dynamic_forms module
fobi.tests.test_sortable_dict module
Module contents
fobi.urls package
Submodules
fobi.urls.edit module
fobi.urls.view module
Module contents

Submodules

fobi.admin module

fobi.app module

fobi.app.app_name(path, reduce_depth_by=1)[source]

Returns another path by reducing the depth by one.

Parameters:
  • path (str) – Absolute app path (from project root).
  • reduce_depth_by (int) –
Return str:
fobi.app.app_config(path, config_app_path='apps.Config')[source]
Parameters:
  • path (str) – Absolute app path (from project root).
  • config_app_path (str) – Relative config path (from app root)
Return str:

fobi.base module

All uids are supposed to be pythonic function names (see PEP http://www.python.org/dev/peps/pep-0008/#function-names).

class fobi.base.BaseDataStorage[source]

Bases: object

Base storage data.

class fobi.base.FormElementPluginDataStorage[source]

Bases: fobi.base.BaseDataStorage

Storage for FormField data.

class fobi.base.FormHandlerPluginDataStorage[source]

Bases: fobi.base.BaseDataStorage

Storage for FormField data.

class fobi.base.BasePluginForm[source]

Bases: object

Not a form actually. Defined for magic only.

Property iterable plugin_data_fields:
 

Fields to get when calling the get_plugin_data method. These field will be JSON serialized. All other fields, even if they are part of the form, won’t be. Make sure all fields are serializable. If some of them aren’t, override the save_plugin_data method and make them serializable there. See fobi.contrib.plugins.form_elements.fields.select.forms as a good example.

Example:
>>> plugin_data_fields = (
>>>    ('name', ''),
>>>    ('active': False)
>>> )
get_plugin_data(request=None, json_format=True)[source]

Data that would be saved in the plugin_data field of the fobi.models.FormElementEntry or ``fobi.models.FormHandlerEntry`.` subclassed model.

Parameters:request (django.http.HttpRequest) –
plugin_data_fields = None
save_plugin_data(request=None)[source]

Dummy, but necessary.

validate_plugin_data(form_element_entries, request=None)[source]
Parameters:
  • form_element_entries (iterable) – Iterable of fobi.models.FormElementEntry.
  • request (django.http.HttpRequest) –
Return bool:
class fobi.base.BasePlugin(user=None)[source]

Bases: object

Base form field from which every form field should inherit.

Properties:
  • uid (string): Plugin uid (obligatory). Example value: ‘dummy’,

    ‘wysiwyg’, ‘news’.

  • name (string): Plugin name (obligatory). Example value:

    ‘Dummy plugin’, ‘WYSIWYG’, ‘Latest news’.

  • description (string): Plugin decription (optional). Example

    value: ‘Dummy plugin used just for testing’.

  • help_text (string): Plugin help text (optional). This text would

    be shown in fobi.views.add_form_plugin_entry and fobi.views.edit_form_plugin_entry views.

  • form: Plugin form (optional). A subclass of django.forms.Form.

    Should be given in case plugin is configurable.

  • add_form_template (str) (optional): Add form template (optional).

    If given, overrides the

    fobi.views.add_form_handler_entry default template.

  • edit_form_template (string): Edit form template (optional). If

    given, overrides the fobi.views.edit_form_handler_entry default template.

  • html_classes (list): List of extra HTML classes for the plugin.

  • group (string): Plugin are grouped under the specified group.

    Override in your plugin if necessary.

add_form_template = None
clone_plugin_data(entry)[source]

Used when copying entries. If any objects or files are created by plugin, they should be cloned.

Parameters:fobi.models.AbstractPluginEntry – Instance of fobi.models.AbstractPluginEntry.
Return string:JSON dumped string of the cloned plugin data. The returned value would be inserted as is into the fobi.models.AbstractPluginEntry.plugin_data field.
delete_plugin_data()[source]

Used in fobi.views.delete_form_entry and fobi.views.delete_form_handler_entry. Fired automatically, when fobi.models.FormEntry object is about to be deleted. Make use of it if your plugin creates database records or files that are not monitored externally but by dash only.

description = None
edit_form_template = None
form = None
get_cloned_plugin_data(update={})[source]

Get the cloned plugin data and returns it in a JSON dumped format.

Parameters:update (dict) –
Return string:JSON dumped string of the cloned plugin data.
Example:
In the get_cloned_plugin_data method of your plugin, do as
follows:
>>> def clone_plugin_data(self, dashboard_entry):
>>>     cloned_image = clone_file(self.data.image, relative_path=True)
>>>     return self.get_cloned_plugin_data(update={'image': cloned_image})
get_form()[source]

Get the plugin form class. Override this method in your subclassed fobi.base.BasePlugin class when you need your plugin setup to vary depending on the placeholder, workspace, user or request given. By default returns the value of the form attribute defined in your plugin.

Return django.forms.Form|django.forms.ModelForm:
 Subclass of django.forms.Form or django.forms.ModelForm.
get_initialised_create_form(data=None, files=None)[source]

Used fobi.views.add_form_element_entry and fobi.views.add_form_handler_entry view to gets initialised form for object to be created.

get_initialised_create_form_or_404(data=None, files=None)[source]

Same as get_initialised_create_form but raises django.http.Http404 on errors.

get_initialised_edit_form(data=None, files=None, auto_id='id_%s', prefix=None, initial=None, error_class=<class 'django.forms.utils.ErrorList'>, label_suffix=':', empty_permitted=False, instance=None)[source]

Used in fobi.views.edit_form_element_entry and fobi.views.edit_form_handler_entry views.

get_initialised_edit_form_or_404(data=None, files=None, auto_id='id_%s', prefix=None, error_class=<class 'django.forms.utils.ErrorList'>, label_suffix=':', empty_permitted=False)[source]

Same as get_initialised_edit_form but raises django.http.Http404 on errors.

get_instance()[source]
get_plugin_form_data()[source]

Fed as initial argument to the plugin form when initialising the instance for adding or editing the plugin. Override in your plugin class if you need customisations.

get_updated_plugin_data(update={})[source]

Get the plugin data and returns it in a JSON dumped format.

Parameters:update (dict) –
Return string:JSON dumped string of the cloned plugin data.
get_widget(request=None, as_instance=False)[source]

Gets the plugin widget.

Parameters:
  • request (django.http.HttpRequest) –
  • as_instance (bool) –
Return mixed:

Subclass of fobi.base.BasePluginWidget or instance of subclassed fobi.base.BasePluginWidget object.

group = 'General'
help_text = None
html_class[source]

A massive work on positioning the plugin and having it to be displayed in a given width is done here. We should be getting the plugin widget for the plugin given and based on its’ properties (static!) as well as on plugin position (which we have from model), we can show the plugin with the exact class.

html_classes = []
html_id[source]
load_plugin_data(plugin_data)[source]

Loads the plugin data saved in fobi.models.FormElementEntry or fobi.models.FormHandlerEntry. Plugin data is saved in JSON string.

Parameters:plugin_data (string) – JSON string with plugin data.
media_css = []
media_js = []
name = None
plugin_data_repr()[source]

Human readable representation of plugin data. A very basic way would be just:

>>> return self.data.__dict__
Return string:
post_processor()[source]

Redefine in your subclassed plugin when necessary.

Post process plugin data here (before rendering). This methid is being called after the data has been loaded into the plugin.

Note, that request (django.http.HttpRequest) is available (self.request).

pre_processor()[source]

Redefine in your subclassed plugin when necessary.

Pre process plugin data (before rendering). This method is being called before the data has been loaded into the plugin.

Note, that request (django.http.HttpRequest) is available ( self.request).

process(plugin_data=None, fetch_related_data=False)[source]

Init plugin with data.

process_plugin_data(fetch_related_data=False)[source]

Processes the plugin data.

render(request=None)[source]

Renders the plugin HTML.

Parameters:request (django.http.HttpRequest) –
Return string:
storage = None
uid = None
update_plugin_data(entry)[source]

Used in fobi.management.commands.fobi_update_plugin_data.

Some plugins would contain data fetched from various sources (models, remote data). Since form entries are by definition loaded extremely much, you are advised to store as much data as possible in plugin_data field of fobi.models.FormElementEntry or fobi.models.FormHandlerEntry. Some externally fetched data becomes invalid after some time and needs updating. For that purpose, in case if your plugin needs that, redefine this method in your plugin. If you need your data to be periodically updated, add a cron-job which would run fobi_update_plugin_data management command (see fobi.management.commands.fobi_update_plugin_data module).

Parameters:or fobi.models.FormHandlerEntry (fobi.models.FormElementEntry) – Instance of fobi.models.FormeHandlerEntry.
Return dict:Should return a dictionary containing data of fields to be updated.
widget = None
class fobi.base.FormElementPlugin(user=None)[source]

Bases: fobi.base.BasePlugin

Base form element plugin.

Property fobi.base.FormElementPluginDataStorage storage:
 
Property bool has_value:
 If set to False, ignored (removed) from the POST when processing the form.
get_form_field_instances()[source]

Gets the instances of form fields, that plugin contains.

Parameters:
  • form_element_entry (fobi.models.FormElementEntry) – Instance.
  • origin (string) –
  • kwargs_update_func (callable) –
  • return_func (callable) –
Return list:

List of Django form field instances.

Example:
>>> from django.forms.fields import CharField, IntegerField, TextField
>>> [CharField(max_length=100), IntegerField(), TextField()]
get_origin_kwargs_update_func_results(kwargs_update_func, form_element_entry, origin, extra={})[source]

If kwargs_update_func is given, is callable and returns results without failures, return the result. Otherwise - return None.

get_origin_return_func_results(return_func, form_element_entry, origin)[source]

If return_func is given, is callable and returns results without failures, return the result. Otherwise - return None.

has_value = False
storage

alias of FormElementPluginDataStorage

submit_plugin_form_data(form_entry, request, form)[source]

Submit plugin form data. Called on form submittion (when user actually posts the data to assembed form).

Parameters:
  • form_entry (fobi.models.FormEntry) – Instance of fobi.models.FormEntry.
  • request (django.http.HttpRequest) –
  • form (django.forms.Form) –
class fobi.base.FormHandlerPlugin(user=None)[source]

Bases: fobi.base.BasePlugin

Form handler plugin.

custom_actions(form_entry, request=None)[source]

Override this method in your form handler if you want to specify custom actions. Note, that expected return value of this method is an iterable with a triple, where the first item is the URL of the action and the second item is the action title and the third item is the icon class of the action.

Example:
>>>  return (
>>>      ('/add-to-favorites/',
>>>       'Add to favourites',
>>>       'glyphicon glyphicon-favourties'),
>>>  )
get_custom_actions(form_entry, request=None)[source]

Internal method to for obtaining the get_custom_actions.

run(form_entry, request, form)[source]

Custom code should be implemented here.

Parameters:
  • form_entry (fobi.models.FormEntry) – Instance of fobi.models.FormEntry.
  • request (django.http.HttpRequest) –
  • form (django.forms.Form) –
storage

alias of FormHandlerPluginDataStorage

class fobi.base.FormCallback[source]

Bases: object

Base form callback.

callback(form_entry, request, form)[source]

Custom callback code should be implemented here.

Parameters:
  • form_entry (fobi.models.FormEntry) – Instance of fobi.models.FormEntry.
  • request (django.http.HttpRequest) –
  • form (django.forms.Form) –
stage = None
class fobi.base.BaseRegistry[source]

Bases: object

Registry of dash plugins. It’s essential, that class registered has the uid property.

If fail_on_missing_plugin is set to True, an appropriate exception (plugin_not_found_exception_cls) is raised in cases if plugin cound’t be found in the registry.

Property mixed type:
 
Property bool fail_on_missing_plugin:
 
Property fobi.exceptions.DoesNotExist plugin_not_found_exception_cls:
 
Property str plugin_not_found_error_message:
 
fail_on_missing_plugin = False
get(uid, default=None)[source]

Gets the given entry from the registry.

Parameters:uid (string) –

:return mixed.

plugin_not_found_error_message = "Can't find plugin with uid `{0}` in `{1}` registry."
plugin_not_found_exception_cls

alias of DoesNotExist

register(cls, force=False)[source]

Registers the plugin in the registry.

:param mixed.

type = None
unregister(cls)[source]
class fobi.base.FormElementPluginRegistry[source]

Bases: fobi.base.BaseRegistry

Form element plugins registry.

fail_on_missing_plugin = True
plugin_not_found_exception_cls

alias of FormElementPluginDoesNotExist

type = (<class 'fobi.base.FormElementPlugin'>, <class 'fobi.base.FormFieldPlugin'>)
class fobi.base.FormHandlerPluginRegistry[source]

Bases: fobi.base.BaseRegistry

Form handler plugins registry.

fail_on_missing_plugin = True
plugin_not_found_exception_cls

alias of FormHandlerPluginDoesNotExist

type

alias of FormHandlerPlugin

class fobi.base.FormCallbackRegistry[source]

Bases: object

Registry of callbacks. Holds callbacks for stages listed in the fobi.constants.CALLBACK_STAGES.

get_callbacks(stage=None)[source]

Get callbacks for the stage given.

Parameters:stage (string) –
Return list:
register(cls)[source]

Registers the plugin in the registry.

:param mixed.

uidfy(cls)[source]

Makes a UID string from the class given.

Return string:
class fobi.base.ClassProperty[source]

Bases: property

fobi.base.classproperty

alias of ClassProperty

fobi.base.get_registered_plugins(registry)[source]

Gets a list of registered plugins in a form if tuple (plugin name, plugin description). If not yet autodiscovered, autodiscovers them.

Return list:
fobi.base.get_registered_plugin_uids(registry, flattern=True)[source]

Gets a list of registered plugin uids as a list . If not yet autodiscovered, autodiscovers them.

Return list:
fobi.base.get_registered_form_element_plugins()[source]

Gets a list of registered plugins in a form if tuple (plugin name, plugin description). If not yet autodiscovered, autodiscovers them.

Return list:
fobi.base.get_registered_form_element_plugin_uids(flattern=True)[source]

Gets a list of registered plugins in a form if tuple (plugin name, plugin description). If not yet autodiscovered, autodiscovers them.

Return list:
fobi.base.validate_form_element_plugin_uid(plugin_uid)[source]

Validates the plugin uid.

Parameters:plugin_uid (string) –
Return bool:
fobi.base.get_registered_form_handler_plugins()[source]

Gets a list of registered plugins in a form of tuple (plugin name, plugin description). If not yet autodiscovered, autodiscovers them.

Return list:
fobi.base.get_registered_form_handler_plugin_uids(flattern=True)[source]

Gets a list of registered plugins in a form of tuple (plugin name, plugin description). If not yet autodiscovered, autodiscovers them.

Return list:
fobi.base.validate_form_handler_plugin_uid(plugin_uid)[source]

Validates the plugin uid.

Parameters:plugin_uid (string) –
Return bool:
fobi.base.get_registered_form_callbacks(stage=None)[source]

Gets registered form callbacks for the stage given.

fobi.base.fire_form_callbacks(form_entry, request, form, stage=None)[source]

Fires callbacks.

Parameters:
  • form_entry (fobi.models.FormEntry) –
  • request (django.http.HttpRequest) –
  • form (django.forms.Form) –
  • stage (string) –
Return django.forms.Form form:
 
fobi.base.run_form_handlers(form_entry, request, form)[source]

Runs form handlers.

Parameters:
  • form_entry (fobi.models.FormEntry) –
  • request (django.http.HttpRequest) –
  • form (django.forms.Form) –
fobi.base.ensure_autodiscover()[source]

Ensures that plugins are autodiscovered.

fobi.base.collect_plugin_media(form_element_entries, request=None)[source]

Collects the plugin media for form element entries given.

Parameters:
  • form_element_entries (iterable) – Iterable of fobi.models.FormElementEntry instances.
  • request (django.http.HttpRequest) –
Return dict:

Returns a dict containing the ‘js’ and ‘css’ keys. Correspondent values of those keys are lists containing paths to the CSS and JS media files.

fobi.base.get_registered_themes()[source]

Gets a list of registered themes in form of tuple (plugin name, plugin description). If not yet autodiscovered, autodiscovers them.

Return list:
fobi.base.get_registered_theme_uids(flattern=True)[source]

Gets a list of registered themes in a form of tuple (plugin name, plugin description). If not yet autodiscovered, autodiscovers them.

Return list:
fobi.base.validate_theme_uid(plugin_uid)[source]

Validates the theme uid.

Parameters:plugin_uid (string) –
Return bool:
class fobi.base.BaseFormFieldPluginForm[source]

Bases: fobi.base.BasePluginForm

Base form for form field plugins.

help_text = <django.forms.fields.CharField object at 0x7f7ff7580b10>
label = <django.forms.fields.CharField object at 0x7f7ff7580a50>
name = <django.forms.fields.CharField object at 0x7f7ff7580910>
plugin_data_fields = [('name', ''), ('label', ''), ('help_text', ''), ('required', False)]
required = <django.forms.fields.BooleanField object at 0x7f7ff7580b50>
validate_plugin_data(form_element_entries, request=None)[source]
Parameters:
  • form_element_entries (iterable) – Iterable of fobi.models.FormElementEntry.
  • request (django.http.HttpRequest) –
Return bool:
class fobi.base.FormFieldPlugin(user=None)[source]

Bases: fobi.base.FormElementPlugin

Form field plugin.

has_value = True
class fobi.base.FormElementPluginWidgetRegistry[source]

Bases: fobi.base.BasePluginWidgetRegistry

Registry of form element plugins.

type

alias of FormElementPluginWidget

class fobi.base.FormHandlerPluginWidgetRegistry[source]

Bases: fobi.base.BasePluginWidgetRegistry

Registry of form handler plugins.

type

alias of FormHandlerPluginWidget

class fobi.base.FormElementPluginWidget(plugin)[source]

Bases: fobi.base.BasePluginWidget

Form element plugin widget.

class fobi.base.FormHandlerPluginWidget(plugin)[source]

Bases: fobi.base.BasePluginWidget

Form handler plugin widget.

fobi.base.assemble_form_field_widget_class(base_class, plugin)[source]

Finish this or remove.

#TODO

fobi.compat module

fobi.conf module

fobi.conf.get_setting(setting, override=None)[source]

Get a setting from fobi conf module, falling back to the default.

If override is not None, it will be used instead of the setting.

Parameters:
  • setting – String with setting name
  • override – Value to use when no setting is available. Defaults to None.
Returns:

Setting value.

fobi.constants module

fobi.context_processors module

fobi.context_processors.theme(request)[source]

Gets active theme.

Parameters:request (django.http.HttpRequest) –
Return fobi.base.BaseTheme:
 Instance of fobi.base.BaseTheme.

fobi.data_structures module

class fobi.data_structures.SortableDict(data=None)[source]

Bases: dict

A dictionary that keeps its keys in the order in which they’re inserted. Very similar to (and partly based on) SortedDict of the Django, but has several additional methods implemented, such as: insert_before_key and insert_after_key.

clear()[source]
copy()[source]

Returns a copy of this object.

insert(index, key, value)[source]

Inserts the key, value pair before the item with the given index.

insert_after_key(target_key, key, value, fail_silently=True)[source]

Inserts the {key: value} after the target_key.

Parameters:
  • target_key (immutable) –
  • key (immutable) –
  • value (mutable) –
  • fail_silently (boolean) –
  • offset (int) –
Return bool:
insert_before_key(target_key, key, value, fail_silently=True, offset=0)[source]

Inserts the {key: value} before the target_key.

Parameters:
  • target_key (immutable) –
  • key (immutable) –
  • value (mutable) –
  • fail_silently (boolean) –
  • offset (int) –
Return bool:
items()[source]
iteritems()
iterkeys()
itervalues()
keys()[source]
move_after_key(source_key, target_key, fail_silently=True)[source]

Moves the {key: value} after the given source_key.

Parameters:
  • source_key (immutable) –
  • target_key (immutable) –
  • fail_silently (boolean) –
Return bool:
move_before_key(source_key, target_key, fail_silently=True, offset=0)[source]

Moves the {key: value} before the given source_key.

Parameters:
  • source_key (immutable) –
  • target_key (immutable) –
  • fail_silently (boolean) –
  • offset (int) –
Return bool:
pop(k, *args)[source]
popitem()[source]
setdefault(key, default)[source]
update(dict_)[source]
value_for_index(index)[source]

Returns the value of the item at the given zero-based index.

values()[source]

fobi.decorators module

fobi.decorators.permissions_required(perms, satisfy='all', login_url=None, raise_exception=False)[source]

Checks for the permissions given based on the strategy chosen.

Parameters:
  • perms (iterable) –
  • satisfy (string) – Allowed values are “all” and “any”.
  • login_url (string) –
  • raise_exception (bool) – If set to True, the PermissionDenied exception is raised on failures.
Return bool:
Example:
>>> @login_required
>>> @permissions_required(satisfy='any', perms=[
>>>     'fobi.add_formentry',
>>>     'fobi.change_formentry',
>>>     'fobi.delete_formentry',
>>>     'fobi.add_formelemententry',
>>>     'fobi.change_formelemententry',
>>>     'fobi.delete_formelemententry',
>>> ])
>>> def edit_dashboard(request):
>>>     # your code
fobi.decorators.all_permissions_required(perms, login_url=None, raise_exception=False)[source]
Example:
>>> @login_required
>>> @all_permissions_required([
>>>     'fobi.add_formentry',
>>>     'fobi.change_formentry',
>>>     'fobi.delete_formentry',
>>>     'fobi.add_formelemententry',
>>>     'fobi.change_formelemententry',
>>>     'fobi.delete_formelemententry',
>>> ])
>>> def edit_dashboard(request):
>>>     # your code
fobi.decorators.any_permission_required(perms, login_url=None, raise_exception=False)[source]
Example:
>>> @login_required
>>> @any_permission_required([
>>>     'fobi.add_formentry',
>>>     'fobi.change_formentry',
>>>     'fobi.delete_formentry',
>>>     'fobi.add_formelemententry',
>>>     'fobi.change_formelemententry',
>>>     'fobi.delete_formelemententry',
>>> ])
>>> def edit_dashboard(request):
>>>     # your code

fobi.defaults module

fobi.discover module

fobi.discover.autodiscover()[source]

Autodiscovers files that should be found by fobi.

fobi.dynamic module

fobi.dynamic.assemble_form_class(form_entry, base_class=<class 'django.forms.forms.BaseForm'>, request=None, origin=None, origin_kwargs_update_func=None, origin_return_func=None, form_element_entries=None)[source]

Assembles a form class by given entry.

Parameters:
  • form_entry
  • base_class
  • request (django.http.HttpRequest) –
  • origin (string) –
  • origin_kwargs_update_func (callable) –
  • origin_return_func (callable) –
  • form_element_entries (iterable) – If given, used instead of form_entry.formelemententry_set.all (no additional database hit).

fobi.exceptions module

exception fobi.exceptions.BaseException[source]

Bases: exceptions.Exception

Base exception.

exception fobi.exceptions.ImproperlyConfigured[source]

Bases: fobi.exceptions.BaseException

Exception raised when developer didn’t configure/write the code properly.

exception fobi.exceptions.InvalidRegistryItemType[source]

Bases: exceptions.ValueError, fobi.exceptions.BaseException

Raised when an attempt is made to register an item in the registry which does not have a proper type.

exception fobi.exceptions.DoesNotExist[source]

Bases: fobi.exceptions.BaseException

Raised when something does not exist.

exception fobi.exceptions.ThemeDoesNotExist[source]

Bases: fobi.exceptions.DoesNotExist

Raised when no theme with given uid can be found.

exception fobi.exceptions.PluginDoesNotExist[source]

Bases: fobi.exceptions.DoesNotExist

Raised when no plugin with given uid can be found.

exception fobi.exceptions.FormElementPluginDoesNotExist[source]

Bases: fobi.exceptions.PluginDoesNotExist

Raised when no form element plugin with given uid can be found.

exception fobi.exceptions.FormHandlerPluginDoesNotExist[source]

Bases: fobi.exceptions.PluginDoesNotExist

Raised when no form handler plugin with given uid can be found.

exception fobi.exceptions.NoDefaultThemeSet[source]

Bases: fobi.exceptions.ImproperlyConfigured

Raised when no active theme is chosen.

fobi.fields module

class fobi.fields.NoneField(required=True, widget=None, label=None, initial=None, help_text=u'', error_messages=None, show_hidden_initial=False, validators=, []localize=False)[source]

Bases: django.forms.fields.Field

To be used with content elements like text or images, that need to be present, for instance, in between form input elements.

bound_data(data, initial)[source]

Return the value that should be shown for this field on render of a bound form, given the submitted POST data for the field and the initial data, if any.

For most fields, this will simply be data; FileFields need to handle it a bit differently.

widget

alias of NoneWidget

fobi.form_importers module

class fobi.form_importers.BaseFormImporter(form_properties, form_data)[source]

Bases: object

Base importer.

description = None
extract_field_properties(field_data)[source]
field_properties_mapping = None
field_type_prop_name = None
fields_mapping = None
get_form_data()[source]
import_data()[source]

Imports data.

name = None
position_prop_name = None
uid = None
class fobi.form_importers.FormImporterPluginRegistry[source]

Bases: fobi.base.BaseRegistry

Form importer plugins registry.

type

alias of BaseFormImporter

fobi.forms module

fobi.helpers module

fobi.helpers.do_slugify(s)
fobi.helpers.lists_overlap(sub, main)[source]
fobi.helpers.iterable_to_dict(items, key_attr_name)[source]

Converts iterable of certain objects to dict.

Parameters:
  • items (iterable) –
  • key_attr_name (string) – Attribute to use as a dictionary key.
Return dict:
fobi.helpers.map_field_name_to_label(form)[source]

Takes a form and creates label to field name map.

Parameters:
  • form (django.forms.Form) – Instance of django.forms.Form.
  • keys_to_remove (list) –
Return dict:
fobi.helpers.clean_dict(source, keys=, []values=[])[source]

Removes given keys and values from dictionary.

Parameters:
  • source (dict) –
  • keys (iterable) –
  • values (iterable) –
Return dict:
fobi.helpers.two_dicts_to_string(headers, data, html_element='p')[source]

Takes two dictionaries, assuming one contains a mapping keys to titles and another keys to data. Joins as string and returns wrapped into HTML “p” tag.

fobi.helpers.ensure_unique_filename(destination)[source]

Makes sure filenames are never overwritten.

Parameters:destination (string) –
Return string:
fobi.helpers.handle_uploaded_file(upload_dir, image_file)[source]
Parameters:image_file (django.core.files.uploadedfile.InMemoryUploadedFile) –
Return string:Path to the image (relative).
fobi.helpers.delete_file(image_file)[source]

Delete file from disc.

fobi.helpers.clone_file(upload_dir, source_filename, relative_path=True)[source]

Clones the file.

Parameters:source_filename (string) – Source filename.
Return string:Filename of the cloned file.
fobi.helpers.get_registered_models(ignore=[])[source]

Gets registered models as list.

Parameters:ignore (iterable) – Ignore the following content types (should be in app_label.model format (example auth.User).
Return list:
fobi.helpers.admin_change_url(app_label, module_name, object_id, extra_path='', url_title=None)[source]

Gets an admin change URL for the object given.

Parameters:
  • app_label (str) –
  • module_name (str) –
  • object_id (int) –
  • extra_path (str) –
  • url_title (str) – If given, an HTML a tag is returned with url_title as the tag title. If left to None just the URL string is returned.
Return str:
fobi.helpers.uniquify_sequence(sequence)[source]

Makes sure items in the given sequence are unique, having the original order preserved.

Parameters:sequence (iterable) –
Return list:
fobi.helpers.safe_text(text)[source]

Safe text (encode).

Return str:
fobi.helpers.combine_dicts(headers, data)[source]

Takes two dictionaries, assuming one contains a mapping keys to titles and another keys to data. Joins as string and returns a result dict.

fobi.models module

fobi.settings module

  • RESTRICT_PLUGIN_ACCESS (bool): If set to True, (Django) permission system for fobi plugins is enabled.
  • FORM_ELEMENT_PLUGINS_MODULE_NAME (str): Name of the module to placed in the (external) apps in which the fobi form element plugin code should be implemented and registered.
  • FORM_HANDLER_PLUGINS_MODULE_NAME (str): Name of the module to placed in the (external) apps in which the fobi form handler plugin code should be implemented and registered.
  • FORM_CALLBACKS_MODULE_NAME (str): Name of the module to placed in the (external) apps in which the fobi form callback code should be implemented and registered.
  • FORM_HANDLER_PLUGINS_EXECUTION_ORDER (tuple): Order in which the form handler plugins are to be executed.
  • DEBUG

fobi.test module

fobi.utils module

fobi.views module

fobi.widgets module

class fobi.widgets.NoneWidget(attrs=None)[source]

Bases: django.forms.widgets.Widget

To be used with content elements.

media
render(name, value, attrs=None)[source]
class fobi.widgets.BooleanRadioSelect(*args, **kwargs)[source]

Bases: django.forms.widgets.RadioSelect

Boolean radio select for Django.

Example:
>>> class DummyForm(forms.Form):
>>>     agree = forms.BooleanField(label=_("Agree?"), required=False, widget=BooleanRadioSelect)
media

Module contents

Indices and tables