Step 3: Porting the route to the new agent execute function
In the legacy agent, users had to implement the action by creating a route handler in the appropriate app/urls.py file.
This is no longer needed as the new agent provides a context object that contains all the information that is needed to implement the action.
When porting the route handler to the new agent, you will need to:
Move the body of the route handler to the execute function of the action.
Replace self.get_ids_from_request() call with context.get_record_ids().
Replace return JsonResponse(); calls with return result_builder.success() or return result_builder.error(), or the appropriate result_builder method.
from django.http import HttpResponse
from app.model import Company
class MarksLiveAction(ActionView):
def post(self, request, *args, **kwargs):
ids = self.get_ids_from_request(request, self.Model)
company = Company.objects.filter(id__in=ids)[0]
company.status = "live"
company.save()
return HttpResponse(status=204)
from forestadmin.datasource_toolkit.interfaces.query.filter.unpaginated import Filter
from forestadmin.datasource_toolkit.interfaces.query.condition_tree.nodes.leaf import ConditionTreeLeaf
from forestadmin.datasource_toolkit.decorators.action.context.single import ActionContextSingle
from forestadmin.datasource_toolkit.decorators.chart.result_builder import ResultBuilder
async def mark_as_live(context: ActionContextSingle, result_builder: ResultBuilder):
company_id = await context.get_record_id()
await context.collection.update(
{ "status": 'live' },
Filter(
{"condition_tree": ConditionTreeLeaf("id", "equal", company_id)}
)
)
return result_builder.success('Company is now live!')
agent.customize_collection('companies').addAction('Mark as Live', {
"scope": "Single",
"execute": mark_as_live
}
)
Step 4: Porting Smart Action hooks
Load hooks and change hooks have been replaced on the new agent by the possibility to use callbacks in the form definition.
Here is an example of a load hook where the default value of a field is set to 50 euros converted into dollars:
from django_forest.utils.collection import Collection
class CustomersForest(Collection):
def load(self):
self.actions = [
{
"type": "single",
"name": "Charge credit card",
"fields": [
{
"field": "amount",
"type": "number",
},
],
"hooks": {
"load": self.send_invoice_load_hook,
},
},
]
def send_invoice_load_hook(self, fields, request, *args, **kwargs):
amount_field = next((x for x in fields if x["field"] == "amount"), None)
amount_field["value"] = convertEurosIntoDollars(50)
return fields
from forestadmin.datasource_toolkit.decorators.action.context.single import ActionContextSingle
def amount_default_value(context: ActionContextSingle):
return convertEurosIntoDollars(50)
agent.customize_collection('customers').add_action('Charge credit card', {
"scope": "Single",
"form": [
{
"field": 'amount',
"type": "Number",
# the function given can also be an async function,
# it will be automatically awaited
"default_value": amount_default_value,
# or a lambda
# "default_value": lambda context: convertEurosIntoDollars(50),
},
]}
)
And another for a change hook which makes a field required if the value of another field is greater than 100:
from django_forest.utils.collection import Collection
class CustomersForest(Collection):
def load(self):
self.actions = [
{
"type": "single",
"name": "Charge credit card",
"fields": [
{
"field": "amount",
"type": "number",
"hook": "on_amount_change",
},
{
"field": "motivation",
"type": "string",
"is_required": False,
},
],
"hooks": {
"change": {
"on_amount_change": on_amount_change,
},
},
},
]
def on_amount_change(self, fields, request, changed_field, *args, **kwargs):
amount_field = next((x for x in fields if x["field"] == "amount"), None)
motivation_field = next(
(x for x in fields if x["field"] == "motivation"), None
)
motivationField["is_required"] = amount_field["value"] > 100
return fields
from forestadmin.datasource_toolkit.decorators.action.context.single import ActionContextSingle
async def amount_is_required(context: ActionContextSingle):
return context.form_values.get("amount", 0) > 100
agent.customize_collection('customers').add_action('Charge credit card', {
"scope": "Single",
"form": [
{
"field": 'amount',
"type": "Number",
},
{
"field": 'motivation',
"type": "String",
# the function given can also be an async function,
# it will be automatically awaited
"is_required": amount_is_required,
# or a lambda
# "is_required": lambda context:context.form_values.get("amount", 0)>100,
},
]}
)