视图函数中的Django缓存数据库值

Django cache database value in view function

我正在制作一个应用程序,允许用户捕获 Google Sheet 作为图像并将其作为警报发送到我们公司的聊天服务中。所以我在数据库中保存 google sheet api 凭据,当用户单击 Web UI 中的“运行”按钮时,它会触发 ajax在 views.py 中运行函数以开始捕获的请求。如果凭据过期,此函数将刷新以获取新凭据并更新数据库中的新值。

但问题是,当旧凭据过期并被新凭据替换时,view.py 中的函数仍然使用数据库中的旧凭据,因此由于错误的凭据而失败。我认为原因是 Django 正在缓存数据库中的旧值,但不知道如何在从数据库中获取值之前清除缓存。

我有一个名为 ggchat 的主应用程序。我使用 docker、gunicorn、nginx 和 celery 来部署这个应用程序。

我在views.py中的函数:

...
from lib.custom import capture_gs

@login_required(login_url='/accounts/login/')
def run_task(request):
    task_id = request.GET.get('task_id', None)
    capture_gs(task_id)
    ...

函数capture_gs来自本地包。下面是这个包的代码:

from __future__ import print_function
import os.path
from googleapiclient.discovery import build
from google_auth_oauthlib.flow import InstalledAppFlow
from google.auth.transport.requests import Request
from google.oauth2.credentials import Credentials
import pandas as pd
import numpy as np
import requests
from mysite.models import Gstoken
from ggchat.models import Task
import datetime as dt
from lib.chat import upload_file

# If modifying these scopes, delete the file token.json.
SCOPES = ['https://www.googleapis.com/auth/spreadsheets']

# Get token from db, create credential for gsheet oauth. If not found token from db, create db from file token.json
try:
    gstoken = Gstoken.objects.get(email='abc@gmail.com')
    creds = Credentials(token = gstoken.token, refresh_token=gstoken.refresh_token, token_uri=gstoken.token_uri, client_id=gstoken.client_id, client_secret=gstoken.client_secret, expiry = gstoken.expiry.replace(tzinfo=None), scopes=SCOPES)
except:
    creds = Credentials.from_authorized_user_file('/app/lib/credentials/google/sheet/token.json', SCOPES)
    # comment in first docker run
    gstoken = Gstoken.objects.create(email='abc@gmail.com', token=creds.token, refresh_token=creds.refresh_token, token_uri=creds.token_uri, client_id=creds.client_id, client_secret=creds.client_secret, expiry = creds.expiry + dt.timedelta(hours=7))
    

# If token is outdated, refresh and update into db. If there are no (valid) credentials available, let the user log in.
if not creds.valid:
    creds.refresh(Request())
    # comment in first docker run
    try:
        gstoken.token = creds.token
        gstoken.expiry = creds.expiry + dt.timedelta(hours=7)
        gstoken.save()
    except:
        pass

def get_auth_token():
    return creds.token

def get_pdf(spreadsheet_id, **kwargs):
    """
    Return a screenshot pdf object from spreadsheet
    """
    url = "https://docs.google.com/spreadsheets/d/" + spreadsheet_id + "/export"
    params = {"format":"pdf", "vertical_alignment": "MIDDLE", "horizontal_alignment": "CENTER", "fzr": "false", "fzc": "false", "gridlines": "false"} # default params
    params.update(kwargs)
    headers = {"Authorization": "Bearer " + get_auth_token()}
    return requests.get(url, params = params, headers = headers)

def capture_gs(task_id):
    task = Task.objects.get(pk=task_id)
    r = get_pdf(task.ss_id, gid = task.gid, range = task.gs_range, scale = 4)
    pdf_file = '/app/temp/result.pdf'
    with open(pdf_file, 'wb') as saveFile:
        saveFile.write(r.content)

    upload_file(channel_name=task.channel, message=task.message, file_path=pdf_file)

因为它仍然使用旧的凭据,函数 get_pdf returns 一个损坏的 pdf 文件,出现 401 未经授权的错误。

我解决了这个问题。检查和刷新凭据的代码应该在一个函数中,然后在其他函数中调用该 check-refresh 函数以避免缓存凭据。所以我重写了本地包如下:

from __future__ import print_function
import os.path
from googleapiclient.discovery import build
from google_auth_oauthlib.flow import InstalledAppFlow
from google.auth.transport.requests import Request
from google.oauth2.credentials import Credentials
import pandas as pd
import numpy as np
import requests
from mysite.models import Gstoken
import datetime as dt

# If modifying these scopes, delete the file token.json.
SCOPES = ['https://www.googleapis.com/auth/spreadsheets']

def create_get_refresh_token():
    
    # Get token from db, create credential for gsheet oauth. If not found token from db, create db from file token.json
    try:
        gstoken = Gstoken.objects.get(email='abc@gmail.com')
        creds = Credentials(token = gstoken.token, refresh_token=gstoken.refresh_token, token_uri=gstoken.token_uri, client_id=gstoken.client_id, client_secret=gstoken.client_secret, expiry = gstoken.expiry.replace(tzinfo=None), scopes=SCOPES)
    except:
        creds = Credentials.from_authorized_user_file('/app/lib/credentials/google/sheet/token.json', SCOPES)
        # comment in first docker run
        try:
            gstoken = Gstoken.objects.create(email='abc@gmail.com', token=creds.token, refresh_token=creds.refresh_token, token_uri=creds.token_uri, client_id=creds.client_id, client_secret=creds.client_secret, expiry = creds.expiry + dt.timedelta(hours=7))
        except:
            pass

    # If token is outdated, refresh and update into db. If there are no (valid) credentials available, let the user log in.
    if not creds.valid:
        creds.refresh(Request())
        # comment in first docker run
        try:
            gstoken.token = creds.token
            gstoken.expiry = creds.expiry + dt.timedelta(hours=7)
            gstoken.save()
        except:
            pass

def create_service():
    create_get_refresh_token()
    gstoken = Gstoken.objects.get(email='abc@gmail.com')
    # create a service to connect to google sheet
    return build('sheets', 'v4', credentials=Credentials(token = gstoken.token, refresh_token=gstoken.refresh_token, token_uri=gstoken.token_uri, client_id=gstoken.client_id, client_secret=gstoken.client_secret, expiry = gstoken.expiry.replace(tzinfo=None), scopes=SCOPES))

def get_auth_token():
    create_get_refresh_token()
    return Gstoken.objects.get(email='abc@gmail.com').token

def get_pdf(spreadsheet_id, **kwargs):
    """
    Return a screenshot pdf object from spreadsheet
    """
    url = "https://docs.google.com/spreadsheets/d/" + spreadsheet_id + "/export"
    params = {"format":"pdf", "vertical_alignment": "MIDDLE", "horizontal_alignment": "CENTER", "fzr": "false", "fzc": "false", "gridlines": "false"} # default params
    params.update(kwargs)
    headers = {"Authorization": "Bearer " + get_auth_token()}
    return requests.get(url, params = params, headers = headers)

def capture_gs(task_id):
    task = Task.objects.get(pk=task_id)
    r = get_pdf(task.ss_id, gid = task.gid, range = task.gs_range, scale = 4)
    pdf_file = '/app/temp/result.pdf'
    with open(pdf_file, 'wb') as saveFile:
        saveFile.write(r.content)

    upload_file(channel_name=task.channel, message=task.message, file_path=pdf_file)