Django Ajax Method Caller для потрясающих вызовов Ajax с помощью динамического импорта

Всем привет. В этой статье я собираюсь написать о методе, который я увидел, когда был стажером-разработчиком в проекте erp, написанном на PHP. Я реализовал этот хитрый метод на Python, чтобы использовать его в своем проекте Django. Я буду писать о том, как мы можем собрать части, вместо того, чтобы подробно рассказывать о том, что такое importlib и т. д.

Короче говоря, этот метод вызывает методы в классах, используя строковые пути, и передает параметры, если они есть. Используя этот метод, я могу легко использовать вызовы AJAX и обмениваться данными между интерфейсом и сервером. Это уменьшает количество создания представлений для обработки запросов.

Помощники: класс DynamicImporter и функция get_ajax_result_dict

По сути, класс DynamicImporter имеет 2 метода: import_module и import_class.

# 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)

Мы можем присвоить класс переменной, используя метод: DynamicImporter().import_class("apps.book.models", "Book") . Для этого мы используем importlib, который является встроенным пакетом Python.



У меня также есть еще одна вспомогательная функция, get_ajax_result_dict, которую я использую для создания ответа dict. Это просто стандарт для унификации ответов и упрощения их поиска.

# 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

Представление вызывающего метода и URL-адрес

Представление ниже сталкивается с запросами ajax, и мы всегда отправляем наш запрос ajax этому представлению. Это представление сначала создает экземпляр класса, а затем присваивает его метод переменной для вызова. Мы используем представление ниже, используя функцию JavaScript в следующем разделе.

# views.py

@csrf_exempt # from django.views.decorators.csrf import csrf_exempt (optional, you can handle the csrf token with js)
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[]")

        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(get_ajax_result_dict("true", "SUCCESS!", {"result": 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!"))

Вы можете спросить, почему вы переопределяете «результат» в ответе об успехе 🥲 Это зависит от вашего использования, вы можете реализовать все, что хотите.

Его простой URL.

# urls.py

urlpatterns.append(path("ajax-method-caller/", views.ajax_method_caller, name="ajax_method_caller"))

Вызывающий метод JavaScript

Приведенная ниже функция отправляет запрос POST в представление ajax_method_caller.

// helpers.js 

// it requires JQuery

const ajax_method_caller = (
    module_name,
    class_name,
    method_name,
    args,
    success_func,
    err_func
) => {
    /*
        * 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
     */
    $.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,
    });
}

Прикладной пример метода

Вы можете увидеть пример применения метода ниже. Теперь вы можете легко использовать свои классы Python, вызывая их из внешнего интерфейса.

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);
    });

Окончательно

Надеюсь, это было полезно, и вам понравилось. Вы можете получить доступ к коду, используя Gist ниже.

С уважением