Хотите открыть соединение с базой данных pymongo с помощью декоратора

#python #flask #pymongo #decorator #python-decorators

Вопрос:

 @api.route('/api/get_contacts')
def get_contacts():
with pymongo.MongoClient(f"mongodb srv://{mongo_username}:{mongo_password}@dev.glstt.mongodb.net/xxxx?retryWrites=trueamp;w=majority") as document:
 

На это слишком много смотреть. Я пытаюсь сделать так, чтобы:

 @api.route('/api/get_contacts')
@mongo
def get_contacts():
 

Проблема в том, что я действительно не понимаю декораторов.
Итак, это то, что я делал до сих пор:

 
def mongo(f):
    @wraps(f)
    def wrap (*args,**kwargs):
        with pymongo.MongoClient(f"mongodb srv://{mongo_username}:{mongo_password}@dev.glstt.mongodb.net/xxx?retryWrites=trueamp;w=majority") as document:

            return f(document)
        return wrap
 

Не уверен, что мне нужно сделать, чтобы декоратор добавил к коду «с оператором» и передал x, а затем документ обратно в функцию маршрута.

Ответ №1:

Декораторы работают в основном путем замены вашей функции на decorator(function) . Например:

 @decorator
def my_function():
    pass
 

Равно

 def my_function():
    pass

my_function = decorator(my_function)
 

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

Например:

 import functools

def decorator(decorated_function):
    @functools.wraps(decorated_function) # This means that the function that returns from this decorator, "wrapper", will keep the decorated_function's name,  `__doc__` argument and more.
    def wrapper(*args, **kwargs):
        """
        Every time you will call the function that returned from the decorator, this function will be called with the particular arguments in args and kwargs.
        """
        return decorated_function(*args, **kwargs)   10
    return wrapper


@decorator
def func(n):
    return n * 2

result = func(2) # here we called the function `wrapper`, the result is func(2)   10, as we did when we called the function.

print(result) # 14
 

Мы тоже можем print(func) , и результат будет примерно таким
<function func at 0x7f5eb16b0040> , и если бы мы не использовали functools.wraps : <function decorator.<locals>.wrapper at 0x7fba9ba0f040> .

Теперь по вашему вопросу, когда вы складываете декораторы,

 @c
@b
@a
def func(): pass
 

этот приказ таков
c(b(a(func)))
И, следовательно, ваша функция с именем mongo должна принимать аргумент «запрос» от api.route('/api/get_contacts') . (Я не знаю, что это за фреймворк, поэтому не могу предсказать, будет ли этот фреймворк предоставлять запрос в качестве аргумента функции).

если фреймворк не передает запрос в качестве аргумента:

 def mongo(f):
    @functools.wraps(f)
    def wrap():
        with pymongo.MongoClient(f"mongodb srv://{mongo_username}:{mongo_password}@dev.glstt.mongodb.net/xxx?retryWrites=trueamp;w=majority") as document:
            return f(document)
    return wrap
 

и если это произойдет:

 def mongo(f):
    @functools.wraps(f)
    def wrap(request):
        # do something with the request
        with pymongo.MongoClient(f"mongodb srv://{mongo_username}:{mongo_password}@dev.glstt.mongodb.net/xxx?retryWrites=trueamp;w=majority") as document:
            return f(document)
    return wrap

 

И тогда это позволит вам сделать это:

 @api.route('/api/get_contacts')
@mongo
def get_contacts(document):
    pass
 

Комментарии:

1. Это действительно помогло, спасибо, что уделили мне время. Это колба, и она не передает запрос в качестве аргумента.