Google日历与Django的集成

v1l68za4  于 2022-09-21  发布在  Go
关注(0)|答案(4)|浏览(203)

有没有一个完全成熟的基于Django的Google日历集成的例子?我正在通读Google's example page,但他们底部的链接已经过时了。

我特别关注刷新令牌,因为Google的例子只关注如何获取访问令牌。这就是我到目前为止所知道的:

@staff_member_required
def authorize_access(request):
    return redirect(get_flow(request).step1_get_authorize_url())

@staff_member_required
def oauth2_callback(request):
    credentials = get_flow(request).step2_exchange(request.GET['code'])

    store = get_store()
    store.put(credentials)
    credentials.set_store(store)

    return redirect('...')

def get_flow(request):
    flow = client.flow_from_clientsecrets(os.path.join(CREDENTIAL_DIR, CLIENT_SECRET_FILE),
                                      SCOPES,
                                      redirect_uri='%s://%s/google-calendar/oauth2-callback/' % (request.META['wsgi.url_scheme'], request.META['HTTP_HOST'],))
    flow.params['access_type'] = 'offline'
    flow.params['approval_prompt'] = 'force'

    return flow

def get_store():
    return oauth2client.file.Storage(os.path.join(CREDENTIAL_DIR, ACCESS_TOKEN_FILE))

def has_valid_api_credentials():
    credentials = get_store().get()
    return credentials is not None

def build_service():
    credentials = get_store().get()

    if not credentials:
        return None
    elif credentials.access_token_expired:
        http = credentials.refresh(httplib2.Http())
        http = get_store().get().authorize(http)
    else:
        http = credentials.authorize(httplib2.Http())

    service = discovery.build('calendar', 'v3', http=http)

    return service

def create_events(rental_request):
    service = build_service()

    event = service.events().insert(...).execute()
ntjbwcob

ntjbwcob1#

研究了许多不同的方法后,我发现服务器到服务器身份验证是我想要的。这样,用户不必显式授予权限,获得的身份验证令牌也不必续订。取而代之的是,使用服务帐户,服务器可以自己进行调用。

在开始编码之前,您必须设置这样一个服务帐户,并将其添加到您希望该服务帐户访问的日历中。谷歌已经写下了在这里创建账户的三个步骤。然后,转到https://calendar.google.com,在屏幕左侧找到您要与新服务帐户共享的日历,然后单击它旁边的三角形。从下拉菜单中选择日历设置。这将把你带到一个屏幕,在那里你会找到你稍后需要的日历ID(所以把它写下来),并在顶部显示一个选项卡来共享对日历的访问。以Person的身份插入服务账号中的邮箱地址,赋予其相应的权限,然后点击保存(如果没有点击保存,服务账号将不会被添加)。

这样做的代码实际上非常优雅:

import os
from datetime import timedelta
import datetime
import pytz

import httplib2
from googleapiclient.discovery import build
from oauth2client.service_account import ServiceAccountCredentials

service_account_email = 'XXX@YYY.iam.gserviceaccount.com'

CLIENT_SECRET_FILE = 'creds.p12'

SCOPES = 'https://www.googleapis.com/auth/calendar'
scopes = [SCOPES]

def build_service():
    credentials = ServiceAccountCredentials.from_p12_keyfile(
        service_account_email=service_account_email,
        filename=CLIENT_SECRET_FILE,
        scopes=SCOPES
    )

    http = credentials.authorize(httplib2.Http())

    service = build('calendar', 'v3', http=http)

    return service

def create_event():
    service = build_service()

    start_datetime = datetime.datetime.now(tz=pytz.utc)
    event = service.events().insert(calendarId='<YOUR EMAIL HERE>@gmail.com', body={
        'summary': 'Foo',
        'description': 'Bar',
        'start': {'dateTime': start_datetime.isoformat()},
        'end': {'dateTime': (start_datetime + timedelta(minutes=15)).isoformat()},
    }).execute()

    print(event)

我使用的是oauth2Client版本2.2.0(pip install oauth2client)。

我希望这个答案能有所帮助:)

wljmcqd8

wljmcqd82#

这里只需要注意一点:尽管代码可以工作,但根据https://github.com/googleapis/google-auth-library-python/blob/7a8641a7f0718c0dce413436f23691e8590face1/docs/index.rst,oauth2client最近已被弃用,而是支持google-auth库-https://github.com/googleapis/google-auth-library-python/tree/edfe24602051969e32917e82bcedd2bace43e260

您可以在此处找到新库的文档-https://google-auth.readthedocs.io/en/latest/user-guide.html

要使用新的库,可以将代码编写为

import datetime
from datetime import timedelta

import pytz

from google.oauth2 import service_account

from googleapiclient.discovery import build

service_account_email = "app-calendar@xxxxxxxxx.iam.gserviceaccount.com"
SCOPES = ["https://www.googleapis.com/auth/calendar"]

credentials = service_account.Credentials.from_service_account_file('google_calendar_credential.json')
scoped_credentials = credentials.with_scopes(SCOPES)

def build_service():
    service = build("calendar", "v3", credentials=scoped_credentials)
    return service

def create_event():
    service = build_service()

    start_datetime = datetime.datetime.now(tz=pytz.utc)
    event = (
        service.events()
        .insert(
            calendarId="primary",
            body={
                "summary": "Foo 2",
                "description": "Bar",
                "start": {"dateTime": start_datetime.isoformat()},
                "end": {
                    "dateTime": (start_datetime + timedelta(minutes=15)).isoformat()
                },
            },
        )
        .execute()
    )

    print(event)

create_event()

由于我没有足够的声誉来发布这篇评论,我将这篇文章作为单独的帖子发布

h9a6wy2h

h9a6wy2h3#

由于这篇文章是很久以前的事了,我想分享我2020年的版本。谢谢你的这篇文章。帮助我实现了我的目标。

import datetime
from datetime import timedelta

import pytz
from googleapiclient.discovery import build
from oauth2client.service_account import ServiceAccountCredentials

service_account_email = "INSERT_HERE"
SCOPES = ["https://www.googleapis.com/auth/calendar"]
credentials = ServiceAccountCredentials.from_json_keyfile_name(
    filename="FILENAME.json", scopes=SCOPES
)

def build_service():
    service = build("calendar", "v3", credentials=credentials)
    return service

def create_event():
    service = build_service()

    start_datetime = datetime.datetime.now(tz=pytz.utc)
    event = (
        service.events()
        .insert(
            calendarId="CALENDARID@group.calendar.google.com",
            body={
                "summary": "Foo",
                "description": "Bar",
                "start": {"dateTime": start_datetime.isoformat()},
                "end": {
                    "dateTime": (start_datetime + timedelta(minutes=15)).isoformat()
                },
            },
        )
        .execute()
    )

    print(event)

create_event()
bjp0bcyl

bjp0bcyl4#

2022

致敬@Joey Coder(我本想添加这条评论,但太长了)

如果你想要你的网站或应用程序在不使用用户的谷歌账户的情况下制作活动或日历,你应该使用服务账户。

https://console.cloud.google.com/中选择您的项目或开始新项目。

在导航菜单中选择“API&Services”启用新的API,然后查找“日历API”,启用该API

在[API&服务]>[凭据]下,选择[创建凭据],点击[服务帐号],填写所需名称,继续。将角色设置为所有者(或其他所需的)(所有者为您提供完全访问权限,您可能希望切换到功能较弱的角色)。点击“完成”

这会将您重定向到凭据页面。在“服务帐户”下,单击所需的帐户(这会将您重定向到IAM&管理面板),在“密钥”选项卡下,单击“添加密钥”,然后选择json,这将下载一个json文件到您的计算机。

在Google Get的Calendar页面中,将日历ID添加到管理面板的AgendaClients“CalendarID”下,将服务帐户添加到作为admin共享的人员(对事件进行更改)

这是我的Django项目中的样子:

signals.py

import datetime
import json
import os

from django.db.models.signals import post_delete, post_save
from googleapiclient.discovery import build
from googleapiclient.errors import HttpError
from oauth2client.service_account import ServiceAccountCredentials
from .models import  Event

# If modifying these scopes, delete the file token.json.

SCOPES = ["https://www.googleapis.com/auth/calendar"]

def get_service(refresh=False):
    credentials = ServiceAccountCredentials.from_json_keyfile_dict(
        json.loads(os.environ.get("client_secret")), scopes=SCOPES
    )
    # or if you have a file
    # credentials = ServiceAccountCredentials.from_json_keyfile_name(
    #     filename="file.json", scopes=SCOPES
    # )
    service = build("calendar", "v3", credentials=credentials)
    return service

def handle_event(sender, created, instance,**kwargs):
        """this function creates the events in the google agenda and updates them if changed in the website"""
        service = get_service()
        event = instance
        if not event.end_date:
            event.end_date = event.start_date
        if not event.end_time and event.start_time:
            event.end_time = event.start_time
        elif not event.end_time:
            event.end_time = datetime.datetime.min.time()
        if not event.start_time:
            event.start_time = datetime.datetime.min.time()
        if event.end_date < event.start_date:
            event.end_date, event.start_date = event.start_date, event.end_date
        queryset = Event.objects.filter(
            id=event.id
        )  # https://stackoverflow.com/questions/1555060/how-to-save-a-model-without-sending-a-signal
        # this is used so that we can update the google event within this signal without reshooting this signal(signals shot every time an object is saved)
        event = {
            "summary": event.description,
            "location": event.location or "",
            "description": (event.description + " " + event.summary),
            "start": {
                "dateTime": datetime.datetime.combine(
                    event.start_date, event.start_time
                ).isoformat(),
                "timeZone": "Europe/Amsterdam",
            },
            "end": {
                "dateTime": datetime.datetime.combine(
                    event.end_date, event.end_time
                ).isoformat(),
                "timeZone": "Europe/Amsterdam",
            },
            "recurrence": [],
            "reminders": {},
        }

        if created or not instance.google_link:
            try:
                event = (
                    service.events()
                    .insert(
                        calendarId=os.environ.get("calendarId"),
                        body=event,
                    )
                    .execute()
                )
                queryset.update(google_link=event["id"])
            except HttpError as error:
                # print("An error occurred: %s" % error)
                pass
        else:
            try:
                event = (
                    service.events()
                    .update(
                        calendarId=os.environ.get("calendarId"),
                        body=event,
                        eventId=instance.google_link,
                    )
                    .execute()
                )
                queryset.update(google_link=event["id"])
            except HttpError as error:
                # print("An error occurred: %s" % error)
                pass
        # print("#############ADDED NEW       #############")

def delete_event(sender, instance,**kwargs):
    """this function deletes an event from google agenda when deleted in the website"""
    try:
        service = get_service()
        service.events().delete(
            calendarId=os.environ.get("CalendarId"),
            eventId=instance.google_link,
        ).execute()
    except:
        pass

post_save.connect(handle_event, sender=Event)
post_delete.connect(delete_event, sender=Event)

Models.py

class Event(models.Model):
    summary = models.CharField(max_length=50)
    description = models.CharField(max_length=50, null=True, blank=True)
    start_date = models.DateField()
    start_time = models.TimeField(null=True, blank=True)
    end_date = models.DateField(null=True, blank=True)
    end_time = models.TimeField(null=True, blank=True)
    location = models.CharField(max_length=50, null=True, blank=True)
    google_link = models.CharField(max_length=150, null=True, blank=True)
    # google link is used to edit events in google if you change them in your website

请随时提问或指出任何问题

相关问题