What is DynamicForms?
=====================

DynamicForms wants to eliminate HTML form boilerplate for generic tables & forms. Specifying a single DRF Serializer / ViewSet and possibly desired form layout instantly provides both HTML renders and JSON renders (and anything else DRF supports) giving you free choice of how to implement your project. 

It performs all the visualisation & data entry of your DRF Serializers & ViewSets and adds some candy of its
own: It is a `django <https://www.djangoproject.com/>`_ library that gives you the power of dynamically-shown form
fields, auto-filled default values, dynamic record loading and similar candy with little effort. To put it differently:
once defined, a particular ViewSet / Serializer can be rendered in multiple ways allowing you to perform viewing and
authoring operations on the data in question.

It is based on `django-rest-framework <http://www.django-rest-framework.org/>`_

Documentation `on readthedocs <https://dynamicforms.readthedocs.io/>`_


Why DynamicForms
----------------

* Turn your rest-framework ViewSets into HTML forms
* Powerful HTML based CRUD

   * Support for fetching "new" records, both in JSON or in HTML
   * Render to HTML, dialog html or from your own template
   * Render form (embedded or dialog) or table, depending on situation
   * Dynamically display & hide fields based on other fields' values
   * Easily add actions and place the buttons to execute them anywhere you like

* Clear separation of list & dialog templates
* Dynamic loading of additional records for table views
* Easy implementation of simple filtering
* Action items, declared globally, placed where you need them
* Custom templates whenever & wherever you want them
* Render to full html or work with dialogs within same page or both at the same time
* Each form and field have a unique HTML id for easy finding & manipulation
* Bootstrap 3 & 4 and jQuery UI templates, easy to make your own or enhance existing
* Support for form validation, will show errors even if they are not tied to a field
* Convenient JS functions for easier action scripting
* Progress dialog for long lasting ajax operations

Quick start guide
=================

.. code-block:: bash

   pip install dynamicforms

Then you need to Activate DynamicForms in DRF.

Also make sure you specify a proper base page template DYNAMICFORMS_PAGE_TEMPLATE - see below for an
example).

DynamicForms has been designed to cause minimal disruption to your existing code patterns.

So instead of DRF ModelViewSet just use DynamicForms ModelViewSet, instead of ModelSerializer - DynamicForms
ModelSerializer.

Currently only the dynamicforms.viewsets.ModelViewSet is supported for ViewSets. We have others planned,
but not implemented yet.

examples/rest/page_load.py

.. code-block:: python

   from dynamicforms import serializers, viewsets
   from ..models import PageLoad


   class PageLoadSerializer(serializers.ModelSerializer):
       form_titles = {
           'table': 'Dynamic page loader list',
           'new': 'New object',
           'edit': 'Editing object',
       }

       class Meta:
           model = PageLoad
           exclude = ()


   class PageLoadViewSet(viewsets.ModelViewSet):
       template_context = dict(url_reverse='page-load')
       pagination_class = viewsets.ModelViewSet.generate_paged_loader(30)  # enables pagination

       queryset = PageLoad.objects.all()
       serializer_class = PageLoadSerializer


examples/models.py  (excerpt)

.. code-block:: python

   from django.db import models

   class PageLoad(models.Model):
       """
       Shows how DynamicForms handles dynamic loading of many records in ViewSet result
       """
       description = models.CharField(max_length=20, help_text='Item description')


If you want filter in list view just set serializers property show_filter value to True. Filter will be applied if user
press enter in filter field. If you want to have filter button in list header, call Actions with
add_default_filter = True.

examples/rest/filter.py

.. code-block:: python

   from dynamicforms import serializers, viewsets
   from dynamicforms.action import Actions
   from ..models import Filter


   class FilterSerializer(serializers.ModelSerializer):
       form_titles = {
           'table': 'Dynamic filter list',
           'new': 'New object',
           'edit': 'Editing object',
       }
       actions = Actions(add_default_crud=True, add_default_filter=True)
       show_filter = True

       class Meta:
           model = Filter
           exclude = ()


   class FilterViewSet(viewsets.ModelViewSet):
       template_context = dict(url_reverse='filter')
       pagination_class = viewsets.ModelViewSet.generate_paged_loader(30)  # enables pagination

       queryset = Filter.objects.all()
       serializer_class = FilterSerializer



Following is an example page template to render straight router URLs. Lines 12, 17 & 20 show the lines that obtain
and render the actual data, be it table or form. See DYNAMICFORMS_PAGE_TEMPLATE.

.. code-block:: django

   {% extends 'examples/base.html' %}
   {% load dynamicforms %}
   {% block title %}
     {{ serializer.page_title }}
   {% endblock %}
   {% block body %}
     {% get_data_template as data_template %}

   <div class="{{ DYNAMICFORMS.bs_card_class }}">
     <div class="{{ DYNAMICFORMS.bs_card_header }}">
       {{ serializer.page_title }}
       {% if serializer.render_type == 'table' %}{% render_table_commands serializer 'header' %}{% endif %}
     </div>
     <div class="{{ DYNAMICFORMS.bs_card_body }}">
       {% include data_template with serializer=serializer data=data %}
     </div>
   </div>
   {% endblock %}


Done. Point your DRF router to the ViewSet you just created and your browser to its URL - make sure you add ".html" to
the URL to specify the renderer. If you forget that, you will get DRF's API renderer.
