Package: django-dialogform
OverviewDjango app to load and open form views within<dialog>element popups. These popups are auto-placed relative to their anchor and auto-sized to their content, placed within the referring page viewport area and have no menus or borders for resizing/moving.  This is meant for django forms that wouldn’t have a large amount of data, but maybe only present a few fields to modify some attributes of a model, create new relations between models, or run queries, etc., with the referring page in the background waiting for the dialog form to be closed.Three different dialog template options are included:dialog- displays a form within a<dialog>element in the same html document context where its anchor is;iframe- creates an<iframe>element within the<dialog>and loads the form and its associated media as a complete html iframe contentDocument;local- handles the presentation of a<dialog>element with a form that are part of the document already loaded.Dialog elements, their content forms and media are created and destroyed dynamically for the first two options.The dialogs are non-modal, so they allow for occasional dialog nesting actions (e.g a model-editing dialog that contains an “X” icon that opens another delete-confirmation dialog), or some other link to create an intermediate or new model to be referred to), if such links are present in the dialog.The dialog views are regular djangoformviews annotated by dialogform mixins.dialog-anchorelements take the role of anchor (<a>) elements that are inserted into view templates to open dialog view urls.Dialogform form and view templates may also be used within the Admin and contain Admin widgets.A simple demo app with all these variations is included in the dialogform/demo subdirectory.Known LimitationsDialogforms are auto-positioning and -sizing within the viewport. Dialogform media assets are restricted to sameorigin. Tested only as far as a few more complex Admin widgets (AdminSplitDateTime, RelatedObjectsWrapper, Autoselect…) and some similar third-party apps like django-addanother, django-autocomplete-light.Demo InstallationIn an empty directory do (don’t miss the “.” at the end):git clone https://github.com/zoltan-ky/django-dialogform.git .Check formanage.py,dialogform,README.rstto confirm. Set up a python3 environment (here e.g using bash):python3 -m venv .venv
source .venv/bin/activate
pip install -r requirements.txtThis will install the only requirement, django 4.1 or greater.  Then run:./manage.py runserver 8000that starts up a localhost debug server. Now browse tolocalhost:8000.Clicking on the various links within the list of notes will open tag assignment and note editing dialogs. The third and fourth columns that demo the use of Admin widgets outside of the admin require prior login to admin. At the bottom there is a link to log in withadmin,admin.There is a ‘search’ dialog above the list of notes that demonstrates local dialogs.  For implementation details refer to theDemo Appsection below.Running the automated selenium testsTo run basic tests, without installingtesting_requirements:./manage.py test dialogform.demo.tests.BasicIf you have Chrome or Firefox installed on your system then you can try to run the automated dialogform test within either of those browsers by:pip install -r testing_requirementsthen:./manage.py test dialogform.demo.tests.<Browser>eitherChromeorFirefoxwill run through all the demo dialogs. The first time it webdriver_manager will install the browser drivers into its cache, the tests may fail if the browser takes too long to start up - in this case repeat the test command above../manage.py testwill try to run all the tests - Basic, Chrome and Firefox.Using Dialogform within a Django projectWith a project .venv already set up:pip install django-dialogformAdd'dialogform',toINSTALLED_APPSin your project’ssettings.py.Formsdialogform.formsprovidesDialogMixinfor forms that are to be used as dialogforms. For example:from dialogform.forms import DialogMixin
...
class SomeDialogForm(DialogMixin,...)DialogMixinadds amethodattribute toForm(default: “POST”) that allows specifying “GET” for query forms that is used for form submission.  During the dialog phase, the form method is always set toDIALOG.DialogMixinadds arender_asattribute toForm(default: “div”) that allows selecting the dialogform output style without having to change templates or views. A convenience methodas_render_as()produces the output style selected byrender_as.DialogFormis aDialogForm(DialogMixin, forms.Form)shorthand.Two buttons controlling the<dialog>forms,CancelandOK, are added by the dialogform form template (see Templates below).  If saving the form fails, the dialog remains open with the form and errors displayed for correction.Cancelor a successfulOKsubmission closes the dialog.  TheCancelbutton is only added if the template gets aformvariable, otherwise only theOKwill show to close the dialog (e.g a minimal message-only dialog).If there’s no ‘autofocus` field in the form, theOKbutton gets the focus. The dialogs can also be cancelled and closed byEsc.Views and TemplatesTo convert a view to a dialog view:from dialogform.views import DialogFormMixin
...
class SomeModelUpdate(DialogFormMixin, UpdateView):
    template_name = "sometemplate.html"
    form_class = SomeDialogForm
    success_url = reverse_lazy("someviewname")success_urlrepresents the view that the dialog view will be redirected to after the form had been successfully saved.The template (e.gsometemplate.html) should extend one of the following templates depending on the View (Admin or not) and dialog type required:View/dialog-typeApp ViewsAdmin Viewsdialog, local… . .   dialog.htmliframepage.htmlstd admin templatesTemplates derived fromdialog.htmlare designed to render a document fragment within a<dialog>element containing a single<form>element as described under the Overview and Forms above.  These views/urls should be invoked bydialog-type anchors.Templates foriframe-type dialogs should be derived frompage.html.  These are complete html documents that could also be used to render a non-dialog, regular view. Theis_dialogtemplate context variable is set by DialogFormMixin for template use.Dialog Template Extension BlocksThe dialog templates listed in the table above may be extended. By default they contain the dialog view form only.dialog-content{% extends "dialogform/dialog.html" %}{# or "dialogform/page.html" #}
{% block dialog-content %}
   ...some content before the form...
   {{ block.super }}
   ...any content after the form...
{% endblock %}dialog-mediaIf some additional media, not captured by the form/widgets media, are required:{% extends "dialogform/dialog.html" %}{# or "dialogform/page.html" #}
{% block dialog-media %}
   ...additional media before the form media...
   {{ block.super }}
   ...and after...
{% endblock %}AnchorsAnchors arediv(block)  orspan(inline) elements withclass="dialog-anchor"and a few attributes desribed below.  The anchor content should either be an<img>element or a<span>containing some text.data-url attributeDialogform javascript processesdialog-anchorsthat serve the role of<a>link elements within referring views:<div class="dialog-anchor" data-url="{% url 'someapp:some-dialog-view-name' %}" title="some help text">
    <span>Some Anchor Text</span>   **or**:  <img src="some url to an anchor icon" ...>
</div>data-type attributeForiframe-type dialogs add thedata-typeattribute:<div class="dialog-anchor" data-url="{% url 'someapp:some-dialog-view-name' %}" title="some help text"
     data-type="iframe">
     ...Forlocal``typedialogs``data-typeshould predictably be set tolocal.data-cleanup attributeSometimes forms or widgets leave behind artefacts generated during form/widget instantiation. An example of this isAdminSplitDateTimewidget that leaves behind#calendarboxand#clockboxdivs in the document body.  Normally this is not a problem since after a valid form is submitted a new document will be loaded.  However, if the dialogform is cancelled, it’s anchor may have an optionaldata-cleanupattribute that names a global javascript function, loaded with the document or dialogform media that is invoked without parameters after closing the dialog. An example fromnote_list.html:<div class="dialog-anchor" data-url="{% url 'note-iframe-admin' pk=note.pk %}"
              title="Iframe Edit with admin widgets"
              data-type="iframe"
              data-cleanup="admin_cleanup">
           <span>{{ note.content }}</span></div>CSS StylingBasic dialogform styling is supported by light/dark color-scheme-aware variables:--dialog-background
--dialog-colorThese allow to make the dialog form somewhat different from the page over which it appears if desired.--dialog-anchor-bg-hoveraffects the background of dialog-anchor text spans when hovered over.--icon-sizedetermines the size of the icons displayed by dialog-anchors. To make the dialog-anchor image icon disappear until hovered over, addclass="hide"to the <img> element. dialog-anchor text span is shown underlined when hovered over.If your document layouts use ‘z-index’ add the following to your CSS:.dialogform-dialog { z-index: <maximum-z-index-of-your-pages> };to have dialogs appear on top of any layers they may end up overlapping with.Demo AppThe demo app is included to provide at least one example for the possible combinations of dialogform types without- and within the admin.ModelsThe following simple models are used:class Note(models.Model):
    content = models.CharField(max_length=200)
    date = models.DateTimeField('date written')
    published = models.BooleanField(default=False)
    parents = models.ManyToManyField('self', blank=True, symmetrical=False,
                                     related_name='children')

class Tag(models.Model):
    name = models.CharField(max_length=32, unique=True)
    notes = models.ManyToManyField('Note', blank=True, related_name='tags')Views, Forms, TemplatesThe demo app has two Note list views, one without admin (default url path"/") and the other within admin ("/admin/demo/note/").The demo appNoteslist view containsNoteChangeandNoteChangeIframeviews invoked bydialog- andiframe-type dialogs respectively.  It also includes alocaldialog for a Note search query.Both of these views have an optionaladminboolean keyword argument indicating the form (NoteFormorNote4AdminForm) to be used by the dialog view.  Thisadminargument is set by the request url (demo/urls.py).These views also select the base template thatdialogform/demo/note_form.htmlextends by setting thedialogform_templatecontext variable. This is pure convenience to minimize code duplication and view reuse in the demo app.Admin-widgets Used in the DemoThe admin widgets withinNote4AdminFormareAdminSplitDateTime,AutocompleteSelectMultipleandRelatedFieldWidgetWrapper, representative of more ‘complex’ admin widgets.These are the same widgets that are used within the auto-generated admin form for NoteAdmin - invoked through aiframe-type dialog anchor that targets the admin (auto-named)admin:demo_note_changeview.Admin Dialog TemplatesThese need to be modified to be used withiframe-type dialogs as these types load complete admin form documents into <iframe> contentDocuments within the dialog.The modification involves eliminating non-form related admin blocks within the standard admin templates and adding the dialog-required ‘Cancel’ and ‘OK’ buttons. The includeddialogform/templates/dialogform/demo/admin_note_change.htmlis an example, it extends the standardadmin/change_form.htmltemplate:{% extends "admin/change_form.html" %}

{# Eliminate non-form page elements #}
{% block header %}{% endblock %}
{% block nav-breadcrumbs %}{% endblock %}
{% block nav-sidebar %}{% endblock %}

{% block content %}
  <div class="dialogform-dialog">
    {{ block.super }}
  </div>
{% endblock %}

{% block submit_buttons_top %}
  <div class="dialogform-buttons">
    <button class="dialogform" value="cancel">Cancel</button>
    <button class="dialogform" value="confirm">OK</button>
  </div>
{% endblock %}
{% block submit_buttons_bottom %}
  <div class="dialogform-buttons">
    <button class="dialogform" value="cancel">Cancel</button>
    <button class="dialogform" value="confirm">OK</button>
  </div>
{% endblock %}and is referred to fromNoteAdmin(demo/admin.py) as:...
add_form_template = "admin/change_form.html"
change_form_template = "dialogform/demo/admin_note_change.html"
...For adding new Note objects via the+RelatedFieldWidgetWrapperadd_form_templateindemo/admin.pyis set to the standard admin change_form.