使用 Classroom API 管理评分周期

本指南介绍了如何使用 Google Classroom API 中的成绩评定周期端点。

概览

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

Classroom 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。如果管理员不是课程中的教师,则无法创建或修改 CourseWork。

管理 GradingPeriodSettings 资源

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

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

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

每个评分周期在创建时都会获得一个由 Classroom API 分配的标识符。

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

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

Classroom 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,这些 CourseWork 位于某个评分周期的开始日期和结束日期之间。请注意,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 的评分周期会被视为错误

Python

以下代码将基于本指南中的示例构建。系统会创建一个名为“夏季”的新评分周期。请求正文中的 applyToExistingCoursework 布尔值设置为 False

为此,系统会读取当前的 GradingPeriodSettings,向列表中添加新的成绩评定周期,并将 applyToExistingCoursework 布尔值设置为 False。请注意,已应用于现有 CourseWork 的任何评分周期都不会被移除。在前面的示例中,“第 1 学期”和“第 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

在此示例中,系统将修改“夏季”成绩评定期的结束日期。applyToExistingCoursework 字段将设置为 True。请注意,将此布尔值设置为 True 会将所有已配置的评分周期应用于现有的 CourseWork。在之前的 API 请求中,布尔值设置为 False,这样“夏季”评分周期就不会应用于现有的 CourseWork。现在,此布尔值字段已设置为 True,系统会将“夏季”评分周期应用于所有匹配的现有 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

如需继续本指南中的示例,请省略“夏季”这一成绩评定周期以将其删除。

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 属于现有评分周期的日期范围,则 Classroom 会在 CourseWork 上设置该评分周期 ID。如果未指定 dueDate 字段,Classroom 将根据 scheduledTime 字段确定 gradingPeriodId。如果这两个字段均未指定,或者没有匹配的评分周期日期范围,则不会在 CourseWork 上设置任何 gradingPeriodId

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

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

3. 没有评分周期关联

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

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

Go

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

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

如果您要更新 CourseWork dueDate 字段,并且想要保留自定义或无评分周期关联,则应在 updateMask 和请求正文中包含 dueDategradingPeriodId。这样一来,系统就不会使用与新 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()