Design Patterns Reference¶
Due to the size of the AMY codebase and the number of views available, it can be tricky to figure out if something has been done before or not.
This document acts as a reference for where certain design patterns can be found in the UI and code base.
Forms¶
Update choice field options dynamically when a different field is updated¶
Demo: Go to the edit view for any Person with an Instructor badge, and select the "Community Roles" tab. Notice how changing the "Role name" selection between "Maintainer" and "Instructor" updates the options available under "Associated award" and "Generic relation object."
Method: It's not possible to make these dynamic updates using Django without submitting the form. Instead, we must use JavaScript.
- Use JavaScript to change the request that is used to get the available choices for the dynamically changing field. Add the dependent field as a parameter in the request. (e.g.
$("#id_communityrole-award").select2({...})
in /static/communityrole_form.js) - In the relevant form, ensure that the JS file is included under the
Media
metaclass (e.g.CommunityRoleForm
in /communityroles/forms.py) - In the relevant lookup view, check for the presence of the extra parameters and use them to filter the results as needed (e.g.
AwardLookupView
in /workshops/lookups.py) - Write tests using different parameter settings (e.g.
TestAwardLookupView
in /workshops/tests/test_lookups.py)
Make a field required/not required according to another field's value¶
Demo: Go to the edit view for any Person with an Instructor badge, and select the "Community Roles" tab. Leave the rest of the form empty, and notice how changing the "Role name" selection between "Trainer" and "Instructor" changes which fields give a "Please fill in this field" error if you click Submit.
Method: It's not possible to make these dynamic updates using Django without submitting the form. Instead, we must use JavaScript.
- Use JavaScript to set the
required
property on the dynamically changing field when the dependent field is updated. (e.g. in /static/communityrole_form.js) - In the relevant form, ensure that the JS file is included under the
Media
metaclass (e.g.CommunityRoleForm
in /communityroles/forms.py) - Ensure that the relevant form/model has validation that matches the dynamic behaviour (e.g.
CommunityRoleForm.clean()
in /communityroles/forms.py)
Autofill some form fields when creating one object using data from another¶
Demo: Go to the "Workshop requests" page and open the detail view for any pending request. Select 'Accept and create a new event' at the bottom. Notice that some fields in the Event form are pre-filled with data from the request (e.g. Start and End, Curricula, Tags).
Method:
- Create a view that inherits the
AMYCreateAndFetchObjectView
- Set a URL for the view that includes the original object's ID, e.g.
workshop_request/<int:request_id>/accept_event/
- Set the
model
andform_class
variables in the view according to the model of the object that will be created - Set the
queryset_other
,context_other_object_name
, andpk_url_kwarg
variables in the view according to the original object. These are used byAMYCreateAndFetchObjectView
to select the correct object to use data from. The object will become available asself.other_object
in the view - Override
get_initial()
to set form fields based on data inself.other_object
Reference files:
extrequests/views.py
- all the...AcceptEvent
classesextrequests/urls.py
extrequests/base_views.py
-WRFInitial
andAMYCreateAndFetchObjectView
Tests¶
Migration tests¶
Use the django_test_migrations
package, e.g. /workshops/tests/test_migrations.py