Layout()objects to design reusable forms in code. This requires some additional work upfront, but the end result should be a form that can be modified in one location (the forms.py file) and reused in multiple views and templates.
models.ModelFormclass. This makes it simpler to create a form for most, if not all, of Ghostwriter's use cases for a form.
ClientContactCreate) because the forms should be reusable. A form used to create a new model entry should be reusable to update that same entry.
Metaclass of every instance of
ModelFormmust declare the model as the variable
modeland then provide values for either
excludeto declare which fields should not be included in the form.
excludewould be a bigger list than
fields, then use
fieldsto declare which fields to include.
fields = "__all__".
from .forms import FORM_NAME.
Projectmodels and their associated child models pushed the single forms.py file beyond 1,000 lines. To make it easier to maintain each set of forms, the project moved them into files named forms._client.py and forms_project.py.
Layout()objects control the
<form></form>tags and the layout of the fields, respectively.
ModelForminstances, this is done in the form's
__init__method. Attributes should be set at the top of the
__init__method, like so:
placeholderattribute should be set for all fields. The placeholder text should provide an example of the intended content or an example of the proper input format. In more freeform fields, the placeholder should identify the field and guide the user towards its intended purpose (e.g., the
notefield in the above example).
offunless it is explicitly needed. Otherwise, autocomplete behavior can negatively impact user experience (e.g., autocomplete lists appearing and covering datepickers) or display non-public information when clicking on the field. The latter is mostly an issue for demonstrations of Ghostwriter.
self.helper. Create a
FormHelper()object named in the form's
__init__method. At a minimum, Ghostwriter form helpers set several values. These values ensure the form appears correctly in the content of the rendered webpage.
FormHelper()configuration. See the next section for more information.
Layout()object assigned to the
self.helper.layout. This object controls the form's HTML. Crispy uses a collection of HTML templates assigned to different
crispy_forms.bootstrapclasses to generate elements when the form is rendered.
id="my-div-id"to an instance of
Div()will result in Crispy using this to the render the div and set the div's
idattribute to my-div-id.
class, so they require using a different argument. To set the class attribute, use
ClientNoteform might look like this example. This form display a single
TextAreafor a note. The only other fields are hidden fields used for associating the entry with an individual
Div()class so they appear wrapped in
<div></div>tags. While not used in this example, this allows for specifying a CSS class and other attributes for the div.
css_class="btn btn-primary col-md-4"
css_class="btn btn-outline-secondary col-md-4
Submit()class. This class accepts a name and a value. In most examples online the
nameparameter is set to submit. The name can be anything, but using submit-button is generally preferred. The value should always be Submit.
cancel_linkcontext variable to templates with forms. This variable contains a pre-defined URL that will return the user to a sensible location if they choose to abandon the form.
HTML()class to create a button with an
onclickattribute that uses the
cancel_linkcontext variable and sets the other necessary values for the button.
Tabholder()class. This class must contain tabs that hold different sections of the form.
Tab()class. Instead, there is a
CustomTab()class available in the project that allows for additional customization of the tabs.