如何在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
相关产品推荐
相关产品推荐

