Skip to main content

Django AJAX ModelForms. Read-only display ModelForms. Django AJAX grids with CRUD and custom actions. Supports Django Templates.

Project description

django-jinja-knockout

PyPI package https://circleci.com/gh/Dmitri-Sintsov/django-jinja-knockout.svg?style=shield https://img.shields.io/travis/Dmitri-Sintsov/django-jinja-knockout.svg?style=flat Watch selenium tests recorded videos. Join the chat at https://gitter.im/django-jinja-knockout/Lobby

Screenshot of sample application:

https://raw.githubusercontent.com/wiki/Dmitri-Sintsov/djk-sample/djk_edit_inline.png

More screenshots with descriptions are available at: https://github.com/Dmitri-Sintsov/djk-sample/wiki

Documentation (in development): https://django-jinja-knockout.readthedocs.org/

  • Django 1.8, 1.9, 1.10, 1.11, 2.0 support. Python 3.4 / 3.5 / 3.6 support.

Please contribute to the localization of the project:

Localization contributors:

  • Dutch: Melvyn Sopacua

  • Polish: pawelkoston

Key features

  • AJAX based django.admin-like grids (paginated datatables) with sorting / filters and custom actions.

  • Supports existing Django templates (DTL).

  • Bootstrap 3 / Jinja2 / Knockout.js integration into Django projects.

  • No deep knowledge of Knockout.js is required: it has ready working components.

  • Dynamic adding / removing of inline formsets with Knockout.js, protected from XSS.

  • ForeignKeyGridWidget provides ForeignKeyRawIdWidget-like functionality to select ModelForm foreign key field value via AJAX query / response.

  • Django raw queries with filter() / exclude() / order() / values() / values_list() and SQL slicing support via FilteredRawQuerySet, suitable for usage in ListView / ListSortingView / KoGridView derived classes.

  • ListQuerySet to query Python lists.

  • Jinja2 templates can be integrated into existing Django templates via custom template library tag:

    {% extends 'base_min.html' %}
    {% load jinja %}
    {% load staticfiles %}
    
    {% block main %}
    {% jinja 'bs_list.htm' with _render_=1 view=view object_list=object_list is_paginated=is_paginated page_obj=page_obj %}
    {% endblock main %}

Overview

Templating languages are my favorite topic in programming. I love semantically organic way of HTML templating in Knockout.js that uses html5 “data-bind” JSON-like attributes instead of semantically alien double braces, which conflicts almost every server-side templating language out there (including DTL and Jinja2).

When developing with Django, I felt a lack of more powerful server-side templating when used built-in DTL templates. So I switched to Jinja2, thank to Django 1.8+ built-in support of this templating engine and to great project https://github.com/niwinz/django-jinja which simplifies Jinja2 integration.

So, basically in this project two great templating engines (client-side https://github.com/knockout/knockout and server-side https://github.com/mitsuhiko/jinja2) meet together. That allows to write complex dynamic HTML code with less effort, cleaner look and easily readable. Both also are very fast, Knockout.js templates being one of the fastest at client-side, while Jinja2 estimated to be faster few times than built-in DTL templates, and is more powerful.

When thinking of Angluar.js, not only I dislike curly braces in templates but also I believe that using such large framework for non-SPA applications is an overkill. And Django primary usage are non-SPA classical Web applications, which aren’t “outdated” in any way - because such applications are much better indexable by web crawlers and Python is better language than Javascript in general and server-side has less glitches than browsers.

My personal feeling is that Django itself lacks a bit heavier support of client-side Javascript out-of-box. Knockout.js would be great inclusion for empty_form handling and in django.admin, considering it’s small size.

AJAX form validation, AJAX viewmodels response routing and Knockout.js processing of formset.empty_form) are implemented via bundled client-side scripts.

Major changes (version 0.7.0)

Grids (datatables) now have new type of action 'pagination'. There are two built-in actions of this type implemented: 'rows_per_page' and 'switch_highlight'.

Grids (datatables) support compound columns for better utilization of the display space. That allows to display more data columns, including foreign relations at the screen.

Grids glyphicon actions are rendered in the single column of datatable, instead of each action per column for better utilization of the display space.

Static assets are moved to ‘/djk’ subdirectory, minimizing the risk of conflicts with third party assets.

Updated to latest versions of Knockout.js / jQuery / Bootstrap 3 (should also work with not-too-old ones).

viewmodels AJAX response routing is rewritten as App.ViewModelRouter class with default instance App.vmRouter. It now supports binding viewmodel handlers to Javascript class instances methods.

Optional built-in Javascript error logger.

App.NestedList internally used by App.renderNestedList for greater flexibility of client-side Javascript nested lists rendering. App.NestedList now supports ordered maps via _.ODict instances.

Ajax forms submitting is refactored into App.AjaxForm class, while setting up the ajax forms is performed by App.AjaxForms, for better flexibility.

App.readyInstances introduced for global client-side IoC, available in custom user scripts as well.

Knockout.js method subscription / unsubscription is placed into App.ko.Subscriber mixin class. focus binding is implemented for Knockout.js.

Request mock-up when running without web server is greatly improved. That enables reverse resolving of FQN urls in console management commands and in background celery tasks via reverseq() calls when sites framework is correctly set up.

ast_eval templage tag.

Headless Chrome Selenium webdriver support (phantom.js is deprecated).

Major changes (version 0.6.0)

AJAX actions are rewritten as server-side ActionsView class and client-side counterpart App.Actions. It is now used as foundation for most of AJAX code, including grid datatables and new App.EditForm / App.EditInline client-side components.

New widget widgets.PrefillWidget to select pre-filled text from the list of supplied values.

Selective skipping of DisplayText field widget rendering.

Basic version of ViewmodelValidator for AJAX submitted forms.

Major changes (version 0.5.0)

Rewritten recursive underscore.js template processor, see underscore.js templates.

Displaying verbose field names in grid rows, grid row actions and in ForeignKeyGridWidget placeholder.

Clean-up of client-side components code.

Better support for grids that use RAW queries with LEFT JOIN, which may have multiple rows with the same pkVal === null.

Improvements in Selenium automation testing: better handling of automation commands, more of commands implemented, much larger test coverage.

  • Numerous bugfixes, including related field queries support in FilteredRawQuerySet.

Major changes (version 0.4.0)

Large improvements in Selenium testing support: additional commands are implemented, auto-retry on DOM timeout, fixtures loading / saving which allows to skip already debugged parts of tests, saving developer’s time.

ContextMiddleware supports request mocking and request-time storage.

FilteredRawQuerySet supports Q expressions (Q objects) with relation mapping.

BaseFilterView / KoGridView - basic support for Q expressions (currently is used for None value of field filter), support for in query for choice filter value via the list of values.

Even better support of optional Django model get_str_fields() method in DisplayText widget and in Knockout.js grids.

Various bugfixes.

Minor changes (version 0.4.1)

Implemented multiple_choices: True option of the field filter type choices in ListSortingView. That allows to perform in field lookups for the selected field filter.

Large monolithic views.py split into smaller parts with symbols exported via module __init__.py for the convenience and compatibility.

Alternative breadcrumbs layout of field filters widgets.

Bugfixes and security fixes in query / views modules.

Major changes (version 0.3.0)

Auto-configuration of nested foreign key filter fields in KoGridView / ForeignKeyGridWidget.

FilteredRawQuerySet now supports more precise .count() method.

ListQuerySet supports significant part of Django queryset functionality for the lists of Django model instances, returned by prefetch_related().

Bootstrap tabs generation macro bs_tabs() with client-side support of switching tabs when window.location.hash value changes.

SendmailQueue functionality can be extended via injecting ioc class - for example to send email in the background via celery task.

Major changes (version 0.2.0)

$.inherit() Javascript prototype inheritance function now supports multi-level inheritance with nested .super calls without having to specify parent class prototype property implicitely in descendant class instances, with newly introduced $.SuperChain class.

“django.admin-like” AJAX functionality was implemented via KoGridView class-based view (CBV) at server-side with corresponding Knockout.js templates and Javascript classes at client-side. Besides providing standard CRUD actions and filters, it allows to implement arbitrary actions in descendant classes and quickly design django.admin-like user interfaces in non-admin views. AJAX calls also minimize server HTTP traffic, reducing network bandwitch and making the UI more responsive.

New ForeignKeyGridWidget was developed which provides ForeignKeyRawIdWidget-like functionality in non-admin ModelForm classes to select foreign key fields value via AJAX query / response.

Support of auto-instantiating Javascript classes with binding these to selected DOM nodes with ‘component’ css class via App.Components class.

Support of auto-compiling / auto-loading client-side underscore.js templates via App.compileTemplate / App.domTemplate / App.loadTemplates. One of usage examples is the possibility of loading modal body from underscore.js template in App.Dialog.

Support of client-side generation of view urls with kwargs for client-side url names via updated context_processors.py and client-side App.routeUrl() Javascript function.

tpl.resolve_cbv() allows to resolve view class via url name and it’s kwargs.

Django templates (DTL) and Jinja2 templates now can be mixed using shared Jinja2 template code via {% load jinja %} template library jinja template tags, which performs include for Jinja2 template with current context:

{% extends 'base_min.html' %}
{% load jinja %}
{% load staticfiles %}

{% block main %}
{% jinja 'bs_list.htm' with _render_=1 view=view object_list=object_list is_paginated=is_paginated page_obj=page_obj %}
{% endblock main %}

Numerous bug fixes.

Documentation

The full documentation is at https://django-jinja-knockout.readthedocs.org.

Quick notes:

Cookiecutter Tools Used in Making This Package

  • cookiecutter

  • cookiecutter-djangopackage

History

0.1.0

  • To be released on PyPI.

0.2.0

  • Django 1.8 / 1.9 / 1.10, Python 3.4 / 3.5 support.

  • djk-sample demo / automated testing project.

  • “django.admin-like” AJAX functionality implemented via KoGridView class-based view.

  • $.inherit() Javascript prototype inheritance function now supports multi-level inheritance with nested ._super._call().

  • FilteredRawQuerySet supports Django raw querysets with .filter() / .exclude() / .order_by() / .values() / .values_list() and SQL level slicing.

  • ForeignKeyGridWidget provides ForeignKeyRawIdWidget -like functionality via AJAX query / response in non-admin forms to select ModelForm foreign key values.

  • Client-side generation of view urls with kwargs in Javascript client-side routes via App.routeUrl().

  • Nested autocompiled underscore.js client-side templates for Javascript components, primarily used with Knockout.js, but is not limited to.

0.3.0

  • ContentTypeLinker - added method to return html representation of content types framework related object (html link with the description by default).

  • FilteredRawQuerySet now supports more precise .count() method to calculate the length of raw queryset.

  • ListQuerySet implements large part of queryset methods for the lists of Django model instances. Such lists are created by Django queryset .prefetch_related() method.

  • Auto-highlight bootstrap navs which have ‘auto-highlight’ css class at client-side.

  • bs_tabs() Jinja2 macro which simplifies generation of bootstrap tabs. Bootstrap tabs now support automatic switching via window.location.hash change.

  • ListSortingView improvements:

    • Supports graceful handling of error reporting, producing in-place messages instead of just rising an exception.

    • .get_filter_args() / .get_no_match_kwargs() methods are implemented to generate macro arguments used in bs_list.htm Jinja2 template. This allows to override default messages for field filters / no match reports in the grid classes.

  • KoGridView has multiple improvements:

    • decimal field filter is renamed to number as now it supports both Django model DecimalField and IntegerField.

    • Django model IntegerField is now bound either to choices type filter, when it has non-empty choices attribute, or to number type filter to select range of values, otherwise.

    • Action handlers do not require to return default viewmodel view name manually, now it’s being done automatically (when viewmodel view name is not specified).

    • get_default_grid_options() method was renamed to shorter get_grid_options() method.

    • grid_options may be defined as class attribute, not having to always define get_grid_options() method which is more verbose (but is more flexible).

    • discover_grid_options() method was implemented to populate grid fkGridOptions which are used to setup foreign key filter fields automatically (when possible). That allows to reduce boilerplate data in grid_options / get_grid_options(), especially when using nested foreign key filters. fkGridOptions nested dictionary still can be specified manually as the part of get_grid_options() result, in complex cases (eg. DB or view kwargs based options).

    • Enable quick selection / deselection of currently displayed grid rows when selectMultipleRows is true.

  • ForeignKeyGridWidget also autodetects foreign key filter fkGridOptions.

  • SendmailQueue supports extension of add() / flush() methods via ioc class.

  • SendmailQueue may be used to send uncaught exception emails when running in production mode.

0.4.0

  • Improvements in testing support:

    • AutomationCommands now uses yield to generate the sequence of opcodes and their args, resulting in cleaner code.

    • SeleniumCommands is reworked into BaseSeleniumCommands. It supports:

      • Saving current database state to Django fixtures at the particular points of tests via dump_data command. That allows to skip already debugged parts of tests via .has_fixture() method, greatly reducing the time required to develop and debug long running Selenium tests. To make proper order (sequence) of stored / loaded fixtures, one has to define fixtures_order attribute of DjkTestCase derived class.

      • Automatic retry of the last Selenium commands execution in case current command is timed out when running at slow client due to DOM is not being updated in time.

      • css parsing / xpath string escaping.

    • SeleniumQueryCommands implements generic Selenium commands, including Django reverse url support for navigation bar, anchors and forms, which could be useful in any Django application.

    • DjkSeleniumQueryCommands implements additional Selenium commands related to django-jinja-knockout functionality, such as BootstrapDialog and Knockout.js grids / widgets support.

forms.py

  • BootstrapModelForm always populates .request attribute for convenience.

  • CustomFullClean / StripWhilespaceMixin mixins for Django forms.

middleware.py

  • ContextMiddleware class:

    • Supports request mocking when running not under HTTP server, for example as shell command / celery task.

    • Supports request-time storage of lists / dicts of objects via add_instance / yield_out_instances methods.

query.py

  • FilteredRawQuerySet supports Q expressions (Q objects) with relation mapping.

views submodule

  • BaseFilterView

    • filter_queryset() now supports args in addition to kwargs. That allows to use Django Q objects in grids and lists, although actual generation of Q objects is still limited to None value filtering.

    • None can be valid value of field filter query. It is mapped to is_null field lookup, also it uses Django Q.__or__ operation in case None is presented in the list of field filter values.

    • Query filters now support in clause for drop-down choice filter.

widgets.py

  • DisplayText field widget __init__() method now supports two types of get_text callback arguments:

    • get_text_method which binds passed function to DisplayText widget instance (self as first argument)

    • get_text_fn which uses unbound function (no self).

If form that defined widget uses WidgetInstancsMixin and model field instance has get_str_fields() method implemented, such field will be auto-rendered via print_list_group() / print_bs_well() functions of tpl modile to produce structured output.

ko_grid_body.htm

  • Fixed ko_grid_body() macro not including underscore.js templates copied with different template_id when these templates were called from related underscore.js templates.

ko-grid.js

  • Reset filter now uses undefined value instead of null value because filtering by None value is now supported in KoGridView.

  • App.ko.GridRow class toDisplayValue() method now automatically picks nested relation value from nested strFields value, when available. That allows to traverse nested get_str_fields() values automatically.

    See getDisplayValue() method for the implementation.

  • Allow to click nested elements of row cells when these are enclosed into anchors.

  • Allow to override grid callback action via viewmodel callback_action property.

  • Query filters now support multi-value in clause for values of drop-down choice filter.

  • Grid viewmodel deleted_pks key values are processed first in App.ko.Grid.updatePage(). That allows to delete old row and add new row with the same pkVal at once (forced update).

  • App.ko.Grid class .setFiltersChoices() method simplifies programmatic filtering of grid at client-side, for example from the parsed querystring.

plugins.js

$.linkPreview now has separate inclusion filter for local urls and exclusion filter for remote urls, which minimizes the possibility of preview glitches due to wrong guess of resource type.

0.4.1

Support of the 'choices' filter option multiple_choices: True in non-AJAX ListSortingView. That allows to perform in field lookups for the selected field filter which was previously available only in AJAX KoGridView.

Large monolithic views.py split into smaller parts with symbols exported via module __init__.py for the convenience and compatibility.

Alternative breadcrumbs layout of field filters widgets.

0.4.2

  • Compatibility to 1.10+ new-style middleware (thanks to Melvyn Sopacua).

  • Fixed pagination when multiple filter field choices are seiected in views.ListSortingView.

0.4.3

  • Django 1.11 / Python 3.6 support.

  • Selenium testing commands fixes.

0.5.0

  • Reworked recursive underscore.js template processor as App.Tpl class.

  • Grid rows, grid row actions and ForeignKeyGridWidget placeholder now are displaying Django model instances verbose field names along with their values. Related model fields verbose names are displayed as well.

  • Client-side components code now uses separate html5 data attribute data-component-class to bind DOM subtrees to Javascript component classes (for example grids), instead of placing everything into data-component-options attribute as in previous versions.

  • Overridable method to check whether two grid rows match the same Django model instance, suitable for RAW query grids with LEFT JOIN, which could have multiple rows with the same pkVal === null.

  • Automation commands now uses SimpleNamespace as chained context, which allows to use different nodes for relative search queries chaining. Currently implemented are relative Selenium queries for form, component, bootstrap dialog and grid. Much better tests coverage in djk-sample project. Many new Selenium commands are implemented, including screenshot command.

  • ko_generic_inlineformset_factory supports dynamic adding / removal of generic inline formsets.

  • FilteredRawQuerySet / ListQuerySet queryset classes values() and values_list() methods now support model relations in queried field names via __ separator, just like usual Django querysets.

  • Numerous bugfixes.

0.6.0

  • ActionsView with App.Actions client-side counterpart implements AJAX viewmodels routing to create generic AJAX actions / responses. It is now used as base foundation for App.ModelFormDialog / ModelFormActionsView and with knockout datatables actions (see modelFormAction method).

  • ModelFormActionsView with App.ModelFormActions client-side counterpart allows to use Django forms / inline formsets with AJAX-powered BootstrapDialog via App.EditForm / App.EditInline client-side components.

  • Selective skipping of DisplayText field widget rendering via setting skip_output property in get_text_method callback.

  • Do not bind App.ko.Formset to display-only bs_inline_formsets() generated forms with inline formsets.

  • Knockout grids (datatables) 'button_footer' built-in action type.

  • djk_seed Django management command.

  • App.renderNestedList supports rendering of jQuery objects values.

  • App.TabPane supports hiding / dynamic content loading of bootstrap 3 panes.

  • App.Dialog is now closable by default. App.Dialog now can be run as component.

  • html and replaceWith viewmodels applies App.initClient hooks, also works correctly with viewmodel .html content that is not wrapped into top tags.

  • Implemented App.propByPath which is now used to load Javascript object specified for App.renderNestedList as options.blockTags string. That allows to pass Javascript path string as options.blockTags via server-side AJAX response. App.Dialog class, 'alert' / 'alert_error' viewmodels suppports this functionality when message option has object type value.

  • App.getClassFromPath / App.newClassFromPath is used by App.Tpl class factories.

  • App.ko.Grid.iocKoFilter_* methods now are orthogonal thus are easier to override.

  • Grid dialogs default hotkeys (Escape, Enter).

  • widgets.PrefillWidget - field widget to prefill form input value from bootstrap 3 dropdown menu. ListQuerySet now has prefill_choices() method, which may provide prefill values for the form field from db field list of values.

  • .badge.btn-* CSS classes which can be used to wrap long text in bootstrap buttons.

  • Separate admin.js script to enable client-side of OptionalWidget in django admin.

  • App.ko.Grid actions meta / list / meta_list first requests passing HTTP POST firstLoad variable to detect the initial grid datatable action at server-side in KoGridView derived class.

  • Fixed selection of all current page grid datatable rows at miltiple grid datatable pages.

  • plugins.js: jQuery.id() to get multiple DOM ids, _.moveOptions() to move options with possible default values. highlightListUrl jQuery function bugfixes.

  • tooltips.js: form_error viewmodel handler, used to display AJAX forms validation errors now has the diagnostic for missing auto_id values and better support for multiple error messages per field.

  • contenttypes: Create content types / user groups / user permissions / Django model migration seeds. For the example of seeds, see djk_seed Django management command.

  • FormWithInlineFormsets supports form auto_id prefix and optional customizeable form / formset constructor kwargs.

  • json_validators module is renamed into validators, which implements generic ViewmodelValidator class to validate AJAX submitted form input and to return error viewmodels when needed.

  • DjkJSONEncoder serializes lazy strings to prevent json serialization errors.

  • BaseSeleniumCommands logs browser errors.

  • tpl module reworked and expanded. Nested lists use common class PrintList. Implemented json_flatatt() and format_html_attrs() functions which work like built-in Django flatatt() and format_html() but automatically convert list / dict types of arguments into html attributes and / or JSON strings.

  • Many bugfixes.

0.7.0

  • Grids (datatables)

    • New type of action 'pagination'.

      • There are two built-in actions of this type implemented: 'rows_per_page' and 'switch_highlight'.

    • Support of compound columns.

    • glyphicon actions are rendered in the single column of datatable, instead of each action per column.

  • Static assets are moved to ‘/djk’ subdirectory, minimizing the risk of conflicts with third party assets.

  • Updated to latest versions of Knockout.js / jQuery / Bootstrap 3 (should also work with not-too-old ones).

  • viewmodels AJAX response routing is rewritten as App.ViewModelRouter class with default instance App.vmRouter. It now supports binding viewmodel handlers to Javascript class instances methods.

  • Optional built-in Javascript error logger.

  • App.NestedList internally used by App.renderNestedList for greater flexibility of client-side Javascript nested lists rendering. App.NestedList now supports ordered maps via _.ODict instances.

  • Ajax forms submitting is refactored into App.AjaxForm class, while setting up the ajax forms is performed by App.AjaxForms.

  • App.readyInstances introduced for global client-side IoC, available in custom user scripts as well.

  • Knockout.js method subscription / unsubscription is placed into App.ko.Subscriber mixin class.

  • focus binding is implemented for Knockout.js.

  • Request mock-up when running without web server allows reverse resolving of FQN urls in console management commands and in background celery tasks via reverseq() calls when sites framework is correctly set up.

  • ast_eval templage tag.

  • Headless Chrome Selenium webdriver support.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

django-jinja-knockout-0.7.1.tar.gz (529.1 kB view hashes)

Uploaded Source

Supported by

AWS AWS Cloud computing and Security Sponsor Datadog Datadog Monitoring Fastly Fastly CDN Google Google Download Analytics Microsoft Microsoft PSF Sponsor Pingdom Pingdom Monitoring Sentry Sentry Error logging StatusPage StatusPage Status page