You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Django开发的网站中集成Google Calendar实现双向同步展示

实现方案

一、后端逻辑修正与改造

首先你现有代码存在两个核心问题需要先修复:

  • 你当前用的InstalledAppFlow是桌面客户端的授权流程,不适用于Web多用户场景,且token.json存在服务端本地会导致所有用户共用同一份日历数据,需要替换为Web OAuth2授权流程,将每个用户的Google授权凭据加密存储在你的Django用户关联数据表中,每个用户请求时单独取自己的凭据调用Google API
  • 不要直接返回Google原生的事件结构,在后端先做字段转换适配前端组件

事件格式转换代码示例

def format_google_event(google_event):
    # 适配FullCalendar要求的字段
    formatted = {
        "id": google_event.get("id"),
        "title": google_event.get("summary", "无标题事件"),
        "url": google_event.get("htmlLink"),
        "extendedProps": {
            "hangoutLink": google_event.get("hangoutLink"),
            "attendees": google_event.get("attendees", []),
            "description": google_event.get("description", "")
        }
    }
    # 处理时间,区分全天事件和非全天事件
    start_info = google_event.get("start", {})
    if "dateTime" in start_info:
        formatted["start"] = start_info["dateTime"]
        formatted["timeZone"] = start_info.get("timeZone")
    else:
        formatted["start"] = start_info.get("date")
        formatted["allDay"] = True
    
    end_info = google_event.get("end", {})
    if "dateTime" in end_info:
        formatted["end"] = end_info["dateTime"]
    else:
        formatted["end"] = end_info.get("date")
    return formatted

改造后的Django视图示例

from django.contrib.auth.decorators import login_required
from django.http import JsonResponse

@login_required
def get_google_calendar_events(request):
    # 从当前登录用户的关联数据中取授权凭据,替换原有读本地token.json的逻辑
    creds = get_user_google_creds(request.user) # 你需要自己实现这个方法,从数据库取对应用户的凭据
    # 凭据过期自动刷新逻辑和原有一致
    if not creds or not creds.valid:
        if creds and creds.expired and creds.refresh_token:
            creds.refresh(Request())
            # 刷新后更新数据库里的凭据
            save_user_google_creds(request.user, creds)
        else:
            # 返回需要授权的提示,跳转到Google授权页
            return JsonResponse({"need_auth": True}, status=401)
    
    service = build('calendar','v3',credentials=creds)
    now = datetime.datetime.utcnow().isoformat()+'Z'
    page_token = None
    calendar_ids = []
    all_events = []
    while True:
        calendar_list = service.calendarList().list(pageToken=page_token).execute()
        for calendar_list_entry in calendar_list['items']:
            if "myorganization" in calendar_list_entry['id']:
                calendar_ids.append(calendar_list_entry['id'])
        page_token = calendar_list.get('nextPageToken')
        if not page_token:
            break
    
    for calendar_id in calendar_ids:
        eventsResult = service.events().list(
            calendarId = calendar_id,
            timeMin = now,
            maxResults = 100, # 可自行调整拉取数量
            singleEvents = True,
            orderBy = 'startTime').execute()
        raw_events = eventsResult.get('items',[])
        # 转换每个事件格式
        for e in raw_events:
            all_events.append(format_google_event(e))
    
    return JsonResponse(all_events, safe=False)

二、前端FullCalendar改造

直接把事件源指向你后端的接口即可,无需手动拼接事件:

document.addEventListener('DOMContentLoaded', function () {
  var calendarEl = document.getElementById('calendar');
  var calendar = new FullCalendar.Calendar(calendarEl, {
    initialView: 'dayGridMonth',
    headerToolbar: {
      left: 'prev,next today',
      center: 'title',
      right: 'dayGridMonth,timeGridWeek,timeGridDay'
    },
    events: '/get-google-calendar-events/', // 替换为你Django对应的接口地址
    // 如果需要实现修改同步,添加以下事件监听
    eventDrop: function(info) {
      // 事件被拖拽修改时间时,发请求到后端调用Google API更新事件
      fetch(`/update-google-event/${info.event.id}/`, {
        method: 'POST',
        headers: {
          'X-CSRFToken': getCSRFToken(), // 你需要自己实现获取Django CSRF Token的方法
          'Content-Type': 'application/json'
        },
        body: JSON.stringify({
          start: info.event.start.toISOString(),
          end: info.event.end ? info.event.end.toISOString() : null,
          allDay: info.event.allDay
        })
      })
    },
    eventResize: function(info) {
      // 事件时长被调整时的同步逻辑,和拖拽逻辑一致
    }
  });
  calendar.render();
});

三、双向同步实现补充

用户在站内修改日历事件时,你只需要在后端对应接口中,用当前用户的凭据调用Google Calendar API的events().update()方法即可将修改同步到用户的Google日历中,全程不需要用户将日历设为公开。

四、替代方案(不使用FullCalendar)

如果不想用第三方组件,你可以直接在后端按月/周/日维度对事件分组,渲染到HTML模板中,自行实现切换时间范围的交互即可,只是开发成本比直接用FullCalendar高很多。


内容的提问来源于stack exchange,提问作者anonymous

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.01 07:15:04