使用 Classroom API 管理评分周期

本指南介绍了如何使用 Google 课堂 API 中的评分周期端点。

概览

创建评分周期是为了将家庭作业、测验和项目 按特定日期范围进行整理。借助 Google 课堂 API,开发者可以代表管理员和教师在 Google 课堂中创建、修改和读取评分周期。您还可以使用 Google 课堂 API 在 CourseWork 上设置评分周期。

Google 课堂 API 提供了两个端点,用于读取和写入课程中的评分周期信息:

  • GetGradingPeriodSettings:用于读取课程中的评分周期设置。
  • UpdateGradingPeriodSettings:用于管理课程中的评分周期设置,包括添加、修改和删除评分周期,以及将配置的评分周期应用于所有现有 CourseWork。

许可和资格要求

修改课程中的评分周期设置

如需使用 UpdateGradingPeriodSettings 端点在课程中创建、修改或删除评分周期,必须满足以下条件:

读取课程中的评分周期设置

网域管理员和课程教师可以读取评分周期设置,无论他们被分配了什么许可。 这意味着,可以代表任何网域管理员或教师向 GetGradingPeriodSettings 端点发出请求。

在 CourseWork 上设置评分周期 ID

课程教师可以在使用 API 创建或更新 CourseWork 时添加 gradingPeriodId,无论他们被分配了什么许可。

检查用户是否符合设置评分周期的条件

可以代表任何管理员或教师向 userProfiles.checkUserCapability 端点发出请求。使用此端点可确定用户是否可以修改评分周期。

前提条件

本指南提供了 Python 代码示例,并假定您已具备以下条件:

  • Google Cloud 项目。您可以按照 Python 快速入门中的说明进行设置。
  • 已将以下范围添加到项目的 OAuth 权限请求页面:
    • https://www.googleapis.com/auth/classroom.courses
    • https://www.googleapis.com/auth/classroom.coursework.students
  • 应修改评分周期的课程的 ID。课程 所有者必须拥有 Google Workspace 教育 Plus 版 许可。
  • 拥有 Google Workspace 教育 Plus 版许可的教师或管理员的凭据。您需要教师的凭据才能创建或修改 CourseWork。如果管理员不是课程中的教师,则无法创建或修改课程作业。

管理 GradingPeriodSettings 资源

GradingPeriodSettings 资源包含 GradingPeriods 列表和一个名为 applyToExistingCoursework 的布尔值字段。

确保列表中的每个 GradingPeriods 都满足以下要求:

  • 标题、开始日期和结束日期 :每个评分周期都必须有标题、开始日期和结束日期。
  • 唯一标题 :每个评分周期都必须有唯一的标题,该标题不得与课程中的任何其他评分周期重复。
  • 日期不重叠 :每个评分周期的开始日期或结束日期不得与课程中的任何其他评分周期重叠。
  • 按时间顺序排列 :评分周期必须按开始日期和结束日期的时间顺序排列。

创建后,每个评分周期都将获得一个由 Google 课堂 API 分配的标识符。

applyToExistingCoursework 布尔值是一个持久性设置,可让您将之前创建的 CourseWork 整理到评分周期中,而无需单独调用 API 来修改每个 CourseWork 的 gradingPeriodId。如果设置为 True,则当 courseWork.dueDate 落在现有评分周期的开始日期和结束日期之间时,Google 课堂会自动在所有现有 CourseWork 上设置 gradingPeriodId。如果 CourseWork 上未设置截止日期,Google 课堂将使用 courseWork.scheduledTime。如果这两个字段都不存在,或者在现有评分周期的开始日期和结束日期之间没有匹配项,则 CourseWork 将不会与任何评分周期相关联。

确定用户是否可以修改课程中的评分周期设置

Google 课堂 API 提供了 userProfiles.checkUserCapability 端点,可帮助您主动确定用户是否能够向 UpdateGradingPeriodSettings 端点发出请求。

Python

def check_grading_periods_update_capability(classroom_service, course_id):
    """Checks whether a user is able to create and modify grading periods in a course."""
    try:
        capability = classroom_service.userProfiles().checkUserCapability(
          userId="me",
          capability="UPDATE_GRADING_PERIOD_SETTINGS",
           # Required while the checkUserCapability method is available in the Developer Preview Program.
          previewVersion="V1_20240930_PREVIEW"
        ).execute()

        # Retrieve the `allowed` boolean from the response.
        if capability.get("allowed"):
          print("User is allowed to update grading period settings in the course.")
        else:
          print("User is not allowed to update grading period settings in the course.")
    except HttpError as error:
        # Handle errors as appropriate for your application.
        print(f"An error occurred: {error}")
        return error

添加评分周期

现在,您已确定用户有资格修改课程中的评分周期设置,可以开始向 UpdateGradingPeriodSettings 端点发出请求。对 GradingPeriodSettings资源的所有修改都是使用 UpdateGradingPeriodSettings端点执行的,无论您是添加单个评分 周期、修改现有评分周期还是删除评分周期。

Python

在以下示例中,gradingPeriodSettings 资源经过修改,包含两个评分周期。applyToExistingCoursework 布尔值设置为 True,这将修改落在某个评分周期的开始日期和结束日期之间的任何现有 CourseWork 的 gradingPeriodId。请注意,updateMask 包含这两个字段。在响应中返回各个评分周期的 ID 后,请保存这些 ID。如有必要,您需要使用这些 ID 来更新评分周期。

def create_grading_periods(classroom_service, course_id):
    """
    Create grading periods in a course and apply the grading periods
    to existing courseWork.
    """
    try:
        body = {
          "gradingPeriods": [
            {
              "title": "First Semester",
              "start_date": {
                "day": 1,
                "month": 9,
                "year": 2023
              },
              "end_date": {
                "day": 15,
                "month": 12,
                "year": 2023
              }
            },
            {
              "title": "Second Semester",
              "start_date": {
                "day": 15,
                "month": 1,
                "year": 2024
              },
              "end_date": {
                "day": 31,
                "month": 5,
                "year": 2024
              }
            }
          ],
          "applyToExistingCoursework": True
        }
        gradingPeriodSettingsResponse = classroom_service.courses().updateGradingPeriodSettings(
          courseId=course_id,
          updateMask='gradingPeriods,applyToExistingCoursework',
          body=body
        ).execute();

        print(f"Grading period settings updated.")
        return gradingPeriodSettingsResponse

    except HttpError as error:
        # Handle errors as appropriate for your application.
        print(f"An error occurred: {error}")
        return error

读取评分周期设置

GradingPeriodSettings 使用 GetGradingPeriodSettings 端点读取。任何用户(无论许可如何)都可以读取课程中的评分周期设置。

Python

def get_grading_period_settings(classroom_service, course_id):
    """Read grading periods settings in a course."""
    try:
        gradingPeriodSettings = classroom_service.courses().getGradingPeriodSettings(
          courseId=course_id).execute()
        return gradingPeriodSettings
    except HttpError as error:
        # Handle errors as appropriate for your application.
        print(f"An error occurred: {error}")
        return error

向列表中添加单个评分周期

对单个评分周期的更新必须遵循读取-修改-写入模式。也就是说,您应该:

  1. 使用 GetGradingPeriodSettings 端点读取 GradingPeriodSettings 资源中的评分周期列表。
  2. 对评分周期列表进行所选修改。
  3. 在向 UpdateGradingPeriodSettings 发出的请求中发送新的评分周期列表。

此模式将帮助您确保课程中的各个评分周期标题是不同的,并且评分周期的开始日期和结束日期之间没有重叠。

请注意以下有关更新评分周期列表的规则:

  1. 添加到列表但没有 ID 的评分周期被视为添加项
  2. 列表中缺少 的评分周期被视为删除项
  3. 具有现有 ID 但数据经过修改的评分周期被视为修改项 。未修改的属性将保持不变。
  4. 具有新 ID 或未知 ID 的评分周期被视为错误
UpdateGradingPeriodSettings

Python

以下代码将以本指南中的示例为基础。系统会创建一个新评分周期,标题为“Summer”。applyToExistingCoursework 布尔值在请求正文中设置为 False

为此,系统会读取当前的 GradingPeriodSettings,向列表中添加新的评分周期,并将 applyToExistingCoursework 布尔值设置为 False。请注意,已应用于现有 CourseWork 的任何评分周期都不会被移除。在之前的示例中,“Semester 1”和“Semester 2”评分周期已应用于现有 CourseWork,如果后续请求中将 applyToExistingCoursework 设置为 False,则不会从 CourseWork 中移除。

def add_grading_period(classroom_service, course_id):
    """
    A new grading period is added to the list, but it is not applied to existing courseWork.
    """
    try:
        # Use the `GetGradingPeriodSettings` endpoint to retrieve the existing
        # grading period IDs. You will need to include these IDs in the request
        # body to make sure existing grading periods aren't deleted.
        body = {
          "gradingPeriods": [
            {
              # Specify the ID to make sure the grading period is not deleted.
              "id": "FIRST_SEMESTER_GRADING_PERIOD_ID",
              "title": "First Semester",
              "start_date": {
                "day": 1,
                "month": 9,
                "year": 2023
              },
              "end_date": {
                "day": 15,
                "month": 12,
                "year": 2023
              }
            },
            {
              # Specify the ID to make sure the grading period is not deleted.
              "id": "SECOND_SEMESTER_GRADING_PERIOD_ID",
              "title": "Second Semester",
              "start_date": {
                "day": 15,
                "month": 1,
                "year": 2024
              },
              "end_date": {
                "day": 31,
                "month": 5,
                "year": 2024
              }
            },
            {
              # Does not include an ID because this grading period is an addition.
              "title": "Summer",
              "start_date": {
                "day": 1,
                "month": 6,
                "year": 2024
              },
              "end_date": {
                "day": 31,
                "month": 8,
                "year": 2024
              }
            }
          ],
          "applyToExistingCoursework": False
        }

        gradingPeriodSettings = classroom_service.courses().updateGradingPeriodSettings(
          courseId=course_id, body=body, updateMask='gradingPeriods,applyToExistingCoursework').execute()
        return gradingPeriodSettings

    except HttpError as error:
        # Handle errors as appropriate for your application.
        print(f"An error occurred: {error}")
        return error

有关 applyToExistingCoursework 布尔值字段的实用提示

请务必注意,applyToExistingCoursework 布尔值是持久性的 ,这意味着,如果在之前的 API 调用中将该布尔值设置为 True 且未更改,则对评分周期的后续更新将应用于现有 CourseWork。

请注意,如果您在向 UpdateGradingPeriodSettings 发出的请求中将此布尔值从 True 更改为 False,则只有您对 GradingPeriodSettings 所做的新更改不会应用于现有 CourseWork。在之前的 API 调用中,当布尔值设置为 True 时应用于 CourseWork 的任何评分周期信息都不会被移除。一种有用的思考方式是,此布尔值设置支持将现有 CourseWork 与您配置的评分周期相关联,但不支持移除 CourseWork 与配置的评分周期之间的现有关联。

如果您删除或更改评分周期的标题,这些更改将传播到所有现有 CourseWork,无论 applyToExistingCoursework 布尔值的设置如何。

更新列表中的单个评分周期

如需修改与现有评分周期关联的某些数据,请在列表中添加现有评分周期的 ID 以及修改后的数据。

Python

在此示例中,系统将修改“Summer”评分周期的结束日期。applyToExistingCoursework 字段将设置为 True。请注意,将此布尔值设置为 True 会将所有配置的评分周期应用于现有 CourseWork。在之前的 API 请求中,该布尔值设置为 False,因此“Summer”评分周期未应用于现有 CourseWork。现在,此布尔值字段设置为 True,“Summer”评分周期将应用于所有匹配的现有 CourseWork。

def update_existing_grading_period(classroom_service, course_id):
    """
    An existing grading period is updated.
    """
    try:
        # Use the `GetGradingPeriodSettings` endpoint to retrieve the existing
        # grading period IDs. You will need to include these IDs in the request
        # body to make sure existing grading periods aren't deleted.
        body = {
          "gradingPeriods": [
            {
              "id": "FIRST_SEMESTER_GRADING_PERIOD_ID",
              "title": "First Semester",
              "start_date": {
                "day": 1,
                "month": 9,
                "year": 2023
              },
              "end_date": {
                "day": 15,
                "month": 12,
                "year": 2023
              }
            },
            {
              "id": "SECOND_SEMESTER_GRADING_PERIOD_ID",
              "title": "Second Semester",
              "start_date": {
                "day": 15,
                "month": 1,
                "year": 2024
              },
              "end_date": {
                "day": 31,
                "month": 5,
                "year": 2024
              }
            },
            {
              # The end date for this grading period will be modified from August 31, 2024 to September 10, 2024.
              # Include the grading period ID in the request along with the new data.
              "id": "SUMMER_GRADING_PERIOD_ID",
              "title": "Summer",
              "start_date": {
                "day": 1,
                "month": 6,
                "year": 2024
              },
              "end_date": {
                "day": 10,
                "month": 9,
                "year": 2024
              }
            }
          ],
          "applyToExistingCoursework": True
        }

        gradingPeriodSettings = classroom_service.courses().updateGradingPeriodSettings(
          courseId=course_id, body=body, updateMask='gradingPeriods,applyToExistingCoursework').execute()
        return gradingPeriodSettings

    except HttpError as error:
        # Handle errors as appropriate for your application.
        print(f"An error occurred: {error}")
        return error

删除单个评分周期

如需删除评分周期,请从列表中省略该评分周期。请注意,如果删除了评分周期,则无论 applyToExistingCoursework 设置如何,CourseWork 上对该评分周期的任何引用也会被删除。

Python

如需继续本指南中的示例,请省略评分周期“Summer”以将其删除。

def delete_grading_period(classroom_service, course_id):
    """
    An existing grading period is deleted.
    """
    try:
        body = {
          "gradingPeriods": [
            {
              "id": "FIRST_SEMESTER_GRADING_PERIOD_ID",
              "title": "First Semester",
              "start_date": {
                "day": 1,
                "month": 9,
                "year": 2023
              },
              "end_date": {
                "day": 15,
                "month": 12,
                "year": 2023
              }
            },
            {
              "id": "SECOND_SEMESTER_GRADING_PERIOD_ID",
              "title": "Second Semester",
              "start_date": {
                "day": 15,
                "month": 1,
                "year": 2024
              },
              "end_date": {
                "day": 31,
                "month": 5,
                "year": 2024
              }
            }
          ]
        }

        gradingPeriodSettings = classroom_service.courses().updateGradingPeriodSettings(
          courseId=course_id, body=body, updateMask='gradingPeriods').execute()
        return gradingPeriodSettings

    except HttpError as error:
        # Handle errors as appropriate for your application.
        print(f"An error occurred: {error}")
        return error

管理 CourseWork 上的 gradingPeriodId 字段

CourseWork 资源包含 gradingPeriodId 字段。您可以使用 CourseWork 端点读取和写入与 CourseWork 关联的评分周期。您可以通过以下三种方式管理此关联:

  • 基于日期的自动评分周期关联
  • 自定义关联的评分周期
  • 无评分周期关联

1. 基于日期的评分周期关联

创建 CourseWork 时,您可以允许 Google 课堂为您处理评分周期关联。为此,请从 CourseWork 请求中省略 gradingPeriodId 字段。然后,在 CourseWork 请求中指定 dueDatescheduledTime 字段。如果 dueDate 落在现有评分周期的日期范围内,Google 课堂将在 CourseWork 上设置该评分周期 ID。如果未指定 dueDate 字段,Google 课堂将根据 scheduledTime 字段确定 gradingPeriodId。如果这两个字段均未指定,或者没有匹配的评分周期日期范围,则不会在 CourseWork 上设置 gradingPeriodId

2. 自定义关联的评分周期

如果您希望将 CourseWork 与不同于与 dueDatescheduledTime 一致的评分周期相关联,则可以在创建或更新 CourseWork 时手动设置 gradingPeriodId 字段。如果您手动设置 gradingPeriodId,Google 课堂将不会执行基于日期的自动评分周期关联。

3. 无评分周期关联

如果您不希望 CourseWork 与任何评分周期相关联,请在 CourseWork 请求中将 gradingPeriodId 字段设置为空字符串 (gradingPeriodId: "")。

如果您使用的是 Go 编程语言,并且不希望设置任何评分周期,还应在请求正文中添加 ForceSendFields 字段。借助 Go 客户端库,由于所有字段上都存在 omitempty 字段标记,因此 API 请求中会省略默认值。 ForceSendFields 字段会绕过此设置并发送空字符串,以表明您不希望为该 CourseWork 设置任何评分周期。如需了解详情,请参阅 Google APIs Go 客户端库文档

Go

courseWork := &classroom.CourseWork{
  Title: "Homework questions",
  WorkType: "ASSIGNMENT",
  State: "DRAFT",
  // ...other CourseWork fields...
  GradingPeriodId: "",
  ForceSendFields: []string{"GradingPeriodId"},
}

如果更新了截止日期,评分周期 ID 会发生什么变化?

如果您要更新 CourseWork dueDate 字段,并且希望保留自定义或无评分周期关联,则应在 updateMask 和请求正文中添加 dueDategradingPeriodId。这将告知 Google 课堂不要使用与新的 dueDate 匹配的评分周期覆盖 gradingPeriodId

Python

body = {
  "dueDate": {
    "month": 6,
    "day": 10,
    "year": 2024
  },
  "dueTime": {
    "hours": 7
  },
  "gradingPeriodId": "<INSERT-GRADING-PERIOD-ID-OR-EMPTY-STRING>"
}
courseWork = classroom_service.courses().courseWork().patch(
  courseId=course_id, id=coursework_id, body=body,
  updateMask='dueDate,dueTime,gradingPeriodId') # include the gradingPeriodId field in the updateMask
.execute()