Skip to content

Instantly share code, notes, and snippets.

@mebaysan
Last active January 6, 2024 07:54
Show Gist options
  • Save mebaysan/1caf81117633e822a5c7798ffb020a87 to your computer and use it in GitHub Desktop.
Save mebaysan/1caf81117633e822a5c7798ffb020a87 to your computer and use it in GitHub Desktop.
Django Ajax Method Caller for Stunning Ajax Calls
# Medium article: https://medium.com/codex/django-ajax-calls-stunning-crafty-method-abaf6b828023
# helpers/dynamic_importer.py
import importlib
class DynamicImporter:
def import_module(self, module_name):
return importlib.import_module(module_name)
def import_class(self, module_name, class_name):
module = self.import_module(module_name)
return getattr(module, class_name)
# helpers/http.py
def get_ajax_result_dict(
result="false", msg="This is default message!", additional_data=None
):
"""
We use this function in all JSONResponse functions to unify responses
result (str): Response flag, true | false
msg (str): Response message
additional_data (dict): Extra data for result dict
"""
result = {"result": result, "msg": msg}
if additional_data is not None:
result.update(additional_data)
return result
# views.py
import re
@csrf_exempt # from django.views.decorators.csrf import csrf_exempt
def ajax_method_caller(request):
if request.method == "POST":
module_name = request.POST.get("module_name")
class_name = request.POST.get("class_name")
method_name = request.POST.get("method_name")
args = request.POST.getlist("args[]")
# Extract 'args[1][0][keyValueOfKey]', 'args[1][1][keyValueOfValue]', etc. and add them to args
arg_data_pattern = re.compile(r'args\[(\d+)\]\[(\d+)\]\[(\w+)\]')
arg_dicts = {}
for key, value in request.POST.items():
match = arg_data_pattern.match(key)
if match:
arg_index = int(match.group(1))
data_index = int(match.group(2))
data_key = match.group(3)
if arg_index not in arg_dicts:
arg_dicts[arg_index] = []
while data_index >= len(arg_dicts[arg_index]):
arg_dicts[arg_index].append({})
arg_dicts[arg_index][data_index][data_key] = value
for arg_dict_list in arg_dicts.values():
args.append(arg_dict_list)
importer = DynamicImporter()
try:
target_class = importer.import_class(module_name, class_name)
instance = target_class()
method = getattr(instance, method_name)
result = method(*args)
return JsonResponse(result)
except Exception as e:
return JsonResponse(get_ajax_result_dict("false", str(e), {"result": None}))
return JsonResponse(get_ajax_result_dict("false", "Request error!"))
# urls.py
urlpatterns.append(path("ajax-method-caller/", views.ajax_method_caller, name="ajax_method_caller"))
# helpers.js
const ajax_method_caller = (
module_name,
class_name,
method_name,
args,
success_func,
err_func,
beforeSend_func = null,
complete_func = null
) => {
/*
* module_name: module name of the method
* class_name: class name of the method
* method_name: method name to be called
* args: arguments to be passed to the method
* success_func: function to be called on success
* err_func: function to be called on error
* beforeSend_func: function to be called before sending the request
* complete_func: function to be called after the request is completed
*
* example:
ajax_method_caller("apps.datagateway.models",
"DataTable",
"apply_column_action",
[action_type, pk], // these are defined in the template
(res) => {
// success response
get_card_notification(res.result);
location.reload();
},
(err) => {
// error response
get_card_notification(err.msg);
});
*/
// Get CSRF token by using get_csrf_token function
$.ajaxSetup({
headers: {
"X-CSRFToken": get_csrf_token()
}
});
$.ajax({
url: "/ajax-method-caller/",
type: "POST",
data: {
'module_name': module_name,
'class_name': class_name,
'method_name': method_name,
'args': args
},
success: success_func,
error: err_func,
beforeSend: beforeSend_func,
complete: complete_func
});
}
const get_csrf_token = () => {
/*
* returns csrf token
* If there is no csrfmiddlewaretoken input in the page, it logs an error on console
*/
const csrfID = "csrfmiddlewaretoken";
const csrfElement = $(`input[name=${csrfID}]`);
if (csrfElement.length === 0) {
console.error(`${csrfID} input is not found in the page`);
}
return csrfElement.val();
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment