Last active
January 6, 2024 07:54
-
-
Save mebaysan/1caf81117633e822a5c7798ffb020a87 to your computer and use it in GitHub Desktop.
Django Ajax Method Caller for Stunning Ajax Calls
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# 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
https://medium.com/codex/django-ajax-calls-stunning-crafty-method-abaf6b828023