Ajax inlines¶
AjaxInline¶
This is a very powerfull way to display children rows of a parent. It’s use can be alternative to that of TabularInline but differs in many details:
Rows can be added only when the parent has already been saved. If you want to abort the creation of the father if the children are not created, this is not the correct tool.
Add/Change/Delete is done via iframe/ajax, that make it fast and user-friendly. On the other hand
Tabular/StakedInline
use a single huge form.Any row is displayed using official django result_list templatetag, the same used in changelist, the
ChangeList
object used has a modifiedChangeList.get_query_set()
to filter children of a parent. You can customize it or simply customizeAjaxInline.get_queryset()
method.All fields defined in
AjaxInline
’slist_display
attribute will be treated in the standard way forlist_display
onModelForm
i.e.: you can define functions and the like.
Layout can only be controlled via tabs
You need to register a ModelAdmin separately for the Child Model you want to edit See below for Row customization.
DataTable jQuery plugin, take care of presenting data in an effective way, sorting is done locally, searching is done by default on any field.
Only one ajax_inline can be registered for each model, that means that you cannot use 2 different ajax_inlines to edit/delete records
To add AjaxInline to your ModelAdmin, resulting in something similar to what is shown in the figure can be accomplished as follows:
from django.contrib import admin
from jmb.jadmin import AjaxInline, ConstrainedModelForm, register_inline
from jmb.jadmin.options import JumboModelAdmin
class ContactAjaxInline(AjaxInline):
model = Contact
fk_name = 'company'
list_display = ('title', 'first_name', 'role','user', )
class CompanyModelAdmin(JumboModelAdmin):
...
tabs = (
('main', {}),
('contacts', {'items' : [ContactAjaxInline]}),
...
)
class ContactForm(ConstrainedModelForm):
class Meta:
model = Contact
hidden_fields = ('organization',) # ALTERNATIVELY you can use get_form below
class ContactModelAdmin(JumboModelAdmin):
model = Contact
# form = ContactForm
def get_form(self, request, obj=None, **kwargs):
'''
Return a form that forces all fields in the GET as not changeable
'''
# Alternative to declaring hidden_fields in the ConstraintForm
hidden_fields = [key for key in request.GET.keys() if not key.startswith('_')]
name = "%sForm" % self.model.__name__
return type(name, (ContactForm,), {
'hidden_fields' : hidden_fields,
})
register_inline(ContactAjaxInline)
admin.site.register(Contact, ContactModelAdmin)
admin.site.register(Company, CompanyModelAdmin)
You need to use ConstrainedModelForm
to make sure foreign keys to
the parent are not writeble
Row customization¶
ajax_inline.html
uses Django’s result_list
templatetag to render
the single object, so any standard way to customize the changelist can be used:
field_names in list_display
can be functions defined on the ModelAdmin or
on the model as described in django documentation.
When you add/modify a record you use the standard ModleAdmin called in an
iframe. After saving the obj the object itself is rendered in the same
way it would be in the chagelist, that implies you need to register which
AjaxInlines will be used so that redsponse_add/change can use it. This is
solved by registering the inlines via register_inline()
ConstraintForm¶
When editing an inline you want to hide the foreign_key field: it simply isn’t usefull and you want to prevent the used to change it. But it must be present in the form as HiddenField as it’s needed when saving the record.
You can use set the widget to Hidden using a CostrainedForm
and declaring
it as hidden in the class. If you plan to use the same form both as AjaxInlien and
in a standard change_form, you can set hidden fields dinamically as shown in
the example above
API¶
-
class
jmb.jadmin.ajax_inlines.
AjaxParentModelAdmin
(model, admin_site)[sorgente]¶ A ModelAdmin that provides handling for
_hjson
parameter that returns the object formatted according to a registered AjaxInline-
delete_view
(request, object_id, extra_context=None)[sorgente]¶ The “delete” admin view for this model.
-
get_urls
()[sorgente]¶ Add a view named
<app_label>_<model_name>_json
that returns an array as the following:data_json = [{ "pk": 9134, "model": "Ticket", "fields": '<tr class="row1">....</tr>'} ] data_json[0].method = "" action = '' message = ''
message
will be the pending messages for the user
-
json_view
(request, obj=None, pk=None)[sorgente]¶ Return a json view of the a single object. Used to refresh the changelist.
- Parametri
request – the request
obj – the object to be returned
-
response_add
(request, obj, post_url_continue=None)[sorgente]¶ Return a response. Handles
_hjson
in GET
-
response_change
(request, obj)[sorgente]¶ Return a response. Handles
_hjson
in GET
-
-
class
jmb.jadmin.ajax_inlines.
ConstrainedModelForm
(*args, **kwargs)[sorgente]¶ A ModelForm that forces HiddenInput on fields declared in
hidden_fields
It’s main goal is to be used when a child is edited and the parent must be forced without giving the user the opportunity to alter it.
It’s
__init__()
calls hide_field() for any field declared inhidden_fields
. If you need to implement more logic in your__init__
you can simply callhide_field()
by youself.We use it along with a javascript code (
jmb.hide_input()
) that hide the label of the relative fields called from withinchange_form.html
-
class
jmb.jadmin.ajax_inlines.
ChildrenChangeList
(request, parent=None, fk_name=None, model=None, list_display=(), list_display_links=(), list_filter=None, date_hierarchy=None, search_fields=(), list_select_related=True, list_per_page=200, list_max_show_all=200, single_child=None, list_editable=None, model_admin=None, ajax_inline=None)[sorgente]¶ A ChangeList that has as queryset the children of a parent
This is used to represent all children of a parent using the same features used in a normal changelist but when using AjaxInline
It’s also used from within
json_response
feeding a standard ModelAdmin asajax__inline
parameter-
add_edit_delete_icons
()[sorgente]¶ Add icons to edit and delete
Disabled since it should be done by_hand Creates problems when this ChangeList is used from changelist
-
-
class
jmb.jadmin.ajax_inlines.
AjaxInline
(parent_model=None, admin_site=None, parent=None)[sorgente]¶ Options for inline editing of
model
instances.This is an
inline
whose editing happens via separate iframes but that are displayed along with normal ones.- Parametri
parent_model – needed to get the foreign key
admin_site – the admin_site, needed to get the ModelAdmin (?)
parent – needed to get all children when rendering the changelist
-
clean_table_headers
(html)[sorgente]¶ Return a table with js stripped from headers :arg html: the output of th template
-
get_queryset
(request)[sorgente]¶ Return a queryset of all the objects to represent in this run
- Parametri
request – HttpRequest
-
get_rows
(obj)[sorgente]¶ Return all the rows that should be displayed by this AjaxInLine
- Parametri
obj – the object whose row we want to fetch
-
render
()[sorgente]¶ Render the whole section using
self.template
(default:ajax_inline.html
) The search path follows the same rules aschange_form.html
& similar.ajax_inline.html
uses standardresult_list
used inchange_list.html
If the
parent
is missing (not yet saved) and nosingle_child
is defined it returnsrendered_presaved()
(that defults to empty string)
-
render_presaved
()[sorgente]¶ Return html code to be used when parent object is not saved yet
-
render_row
()[sorgente]¶ Return the single row inside a
return_list
output We know there is just onetr
in thistbody
-
set_changelist
(request, obj=None)[sorgente]¶ Add a changelist to the inline so that rendering can occurre
- Parametri
request – An HttpRequest
obj – the only object that should be returned by this changelist