FCM Django: Send push notifications via django to websites, iOS & android mobile devices through FCM (Firebase Cloud Messaging)
| 文件 | 最后提交记录 | 最后更新时间 |
|---|---|---|
| 2 个月前 | ||
| 4 年前 | ||
| 2 个月前 | ||
| 2 个月前 | ||
| 2 个月前 | ||
| 1 年前 | ||
| 2 个月前 | ||
| 11 个月前 | ||
| 2 个月前 | ||
| 9 年前 | ||
| 9 年前 | ||
| 2 个月前 | ||
| 3 年前 | ||
| 2 个月前 | ||
| 2 个月前 | ||
| 2 个月前 | ||
| 3 年前 | ||
| 2 个月前 |
fcm-django
.. image:: https://badge.fury.io/py/fcm-django.svg :target: https://badge.fury.io/py/fcm-django
适用于 Firebase Cloud Messaging 的 Django 应用。用作向移动设备和浏览器(安卓 / iOS / Chrome / Firefox / ...)发送推送通知的统一平台。
支持 Firebase Cloud Messaging HTTP v1 API。如果您需要旧版 API,请使用 fcm-django<1!
异步查询集发送 API 需要 firebase-admin>=6.9,因为它们直接使用 firebase_admin.messaging.send_each_async。
FCMDevice 模型字段
- registration_id(必填 - 即 FCM 令牌)
- name(可选)
- active(默认值:true)
- user(可选)
- device_id(可选 - 可用于唯一标识设备)
- type('android'、'web'、'ios')
功能:
- 所有必要的迁移
- Django 管理后台的模型管理界面
- 用于测试单个和批量通知发送的管理操作
- 自动设备清理:向其发送通知失败的设备会被标记为非活动状态
- 标记为非活动状态的设备将不会收到通知
- Django REST framework 视图集
演示 JavaScript 客户端项目
不确定如何使用此项目?请查看以下演示: https://github.com/xtrinch/fcm-django-web-demo
从 1.0 之前版本升级
如果您仍在从基于 pyfcm 的旧版本迁移,请参阅
v1.0 迁移指南。
设置
您可以使用 pip 直接从 PyPI 安装此库:
.. code-block:: console
pip install fcm-django
编辑您的 settings.py 文件:
.. code-block:: python
from firebase_admin import initialize_app
INSTALLED_APPS = (
...
"fcm_django"
...
)
# 仅当您已初始化 Firebase 应用时才是可选的:
# 访问 https://firebase.google.com/docs/admin/setup/#python
# 了解以下内容的更多选项:
# 存储一个名为 GOOGLE_APPLICATION_CREDENTIALS 的环境变量,
# 该变量是指向包含您凭据的 json 文件的路径。
# 还可以使用其他参数:credentials、options、name
FIREBASE_APP = initialize_app()
# 要了解更多信息,请访问此处的文档:
# https://cloud.google.com/docs/authentication/getting-started>
FCM_DJANGO_SETTINGS = {
# 一个 firebase_admin.App 实例,用作所有 fcm-django 请求的默认应用
# 默认值:None(默认的 Firebase 应用)
"DEFAULT_FIREBASE_APP": None,
# 默认值:_('FCM Django')
"APP_VERBOSE_NAME": "[AppConfig 的 verbose_name 字符串]",
# 如果您希望每个已注册用户一次只有一个活动设备,则设为 true
# 默认值:False
"ONE_DEVICE_PER_USER": True/False,
# 无法向其发送通知的设备,
# 在从 FCM 收到错误响应后会被删除
# 默认值:False
"DELETE_INACTIVE_DEVICES": True/False,
# 当此库停用设备时发出 ``device_deactivated`` 信号
# 默认值:False
"EMIT_DEVICE_DEACTIVATED_SIGNAL": True/False,
}
使用原生 Django 迁移。执行 manage.py migrate 将安装并迁移所有模型。
消息
您可以在此处_了解更多关于不同类型消息的信息。
.. _here: https://firebase.google.com/docs/cloud-messaging/concept-options
简而言之,有两种类型:通知消息和数据消息。
通知消息:
.. code-block:: python
from firebase_admin.messaging import Message, Notification Message( notification=Notification(title="title", body="text", image="url"), topic="Optional topic parameter: Whatever you want", )
数据消息:
.. code-block:: python
from firebase_admin.messaging import Message Message( data={ "Nick" : "Mario", "body" : "great match!", "Room" : "PortugalVSDenmark" }, topic="Optional topic parameter: Whatever you want", )
如以下示例所示,您可以发送通知消息、数据消息,或同时发送两者。您还可以自定义 Android、iOS 和 Web 配置以及其他 FCM 条件。访问 firebase_admin.messaging.Message 以了解有关这些配置的更多信息。
发送消息
其他参数包括 additional_registration_ids 和 skip_registration_id_lookup。查看“其他参数”部分了解更多信息。
.. code-block:: python
from firebase_admin.messaging import Message from fcm_django.models import FCMDevice
# 您仍然可以使用 .filter() 或任何返回 QuerySet 的方法(来自链式调用)
device = FCMDevice.objects.all().first()
# send_message 参数包括:message, dry_run, app
device.send_message(Message(data={...}))
device.send_message(Message(data={...}), dry_run=True)
批量发送消息
.. code-block:: python
from firebase_admin.messaging import Message from fcm_django.models import FCMDevice
# 您仍然可以使用 .filter() 或任何返回 QuerySet 的方法(来自链式调用)
devices = FCMDevice.objects.all()
devices.send_message(Message(data={...}))
devices.send_message(Message(data={...}), dry_run=True)
# 或者(send_message 参数包括:message, dry_run, app)
FCMDevice.objects.send_message(Message(...))
使用 dry_run=True 可以与 Firebase 验证负载,而不会实际发送通知。这在开发和集成测试期间非常有用,您可以验证消息构造,而无需向设备发送真实的推送通知。
发送消息时会引发 firebase-admin 引发的所有错误,因此请确保在应用程序代码中捕获并处理这些错误:
FirebaseError– 当向 FCM 服务发送消息时发生错误。ValueError– 如果输入参数无效。
检查批量发送失败
send_message() 会返回一个围绕 Firebase 的 BatchResponse 封装的 FirebaseResponseDict 对象。对于批量发送,Firebase 可能会在响应中返回每个设备的失败信息,而不是对整个调用抛出异常。
返回对象上的有用字段包括:
response.success_countresponse.failure_countresponse.has_failuresresponse.all_failedresponse.failed_registration_idsresponse.failed_exceptionsresponse.summary
示例:
.. code-block:: python
response = FCMDevice.objects.send_message(Message(...))
if response.has_failures:
print(response.failure_count)
print(response.failed_registration_ids)
print(response.failed_exceptions)
这对于配置相关的失败(例如 APNS 或凭据问题)特别有用,在这些情况下,设备可能会失败但不会被停用。
设备停用信号
如果您希望在 fcm-django 停用设备时有一个明确的钩子,请启用以下设置:
.. code-block:: python
FCM_DJANGO_SETTINGS = { "EMIT_DEVICE_DEACTIVATED_SIGNAL": True, }
然后订阅 device_deactivated:
.. code-block:: python
from fcm_django.signals import device_deactivated
def on_device_deactivated(
sender,
registration_ids,
device_ids,
user_ids,
reason,
source,
metadata,
**kwargs,
):
print(registration_ids)
print(device_ids)
print(user_ids)
print(reason)
print(source)
print(metadata)
device_deactivated.connect(on_device_deactivated)
该信号默认是禁用的,当库管理的设备停用时会触发。其负载包括:
registration_ids:被停用的注册令牌device_ids:匹配的设备主键user_ids:匹配的用户主键,不包括没有用户的设备reason:停用原因source:触发停用的库调用位置metadata:额外上下文,例如failed_exceptions
当前的 reason 值包括:
firebase_errorone_device_per_userduplicate_registration_idmanual_disable
当前的 source 值包括:
send_messageperform_createperform_updateserializer_createserializer_updateadmin_action
批量发送个性化消息
当每个设备需要接收不同标题或正文,但仍需通过 Firebase 批量发送时,请使用 send_bulk_personalized_messages。
.. code-block:: python
from fcm_django.models import FCMDevice
FCMDevice.objects.send_bulk_personalized_messages(
title_template="Hello {name}",
body_template="You have {count} new messages",
message_data={
"token-1": {"name": "Alice", "count": 3},
"token-2": {"name": "Bob", "count": 7},
},
data_fields={"kind": "digest"},
)
message_data 以注册 ID 为键。缺失的模板变量在渲染后的消息中保持不变。
异步查询集批量发送
如果您从异步 Django 视图或其他异步上下文中调用 fcm-django,请使用查询集批量 API 及其异步对应方法:
.. code-block:: python
from firebase_admin.messaging import Message, Notification from fcm_django.models import FCMDevice
await FCMDevice.objects.filter(user=request.user).asend_message(
Message(notification=Notification(title="Hi", body="Async batch send")),
)
await FCMDevice.objects.asend_bulk_personalized_messages(
title_template="Hello {name}",
body_template="You have {count} updates",
message_data={"token-1": {"name": "Alice", "count": 3}},
)
这些方法与 FCMDeviceQuerySet 上的 send_message 和 send_bulk_personalized_messages 相对应,旨在用于批量查询集操作。
用户订阅或取消订阅主题
.. code-block:: python
from fcm_django.models import FCMDevice
# 订阅
FCMDevice.objects.all().handle_topic_subscription(True, topic="TOPIC NAME")
device = FCMDevice.objects.all().first()
device.handle_topic_subscription(True, topic="TOPIC NAME")
# 最后,您可以向该主题发送消息
from firebase_admin.messaging import Message
FCMDevice.send_topic_message(Message(...), "TOPIC NAME")
# 取消订阅
FCMDevice.objects.all().handle_topic_subscription(False, topic="TOPIC NAME")
device = FCMDevice.objects.all().first()
device.handle_topic_subscription(False, topic="TOPIC NAME")
向主题发送消息
.. code-block:: python
from firebase_admin.messaging import Message from fcm_django.models import FCMDevice
FCMDevice.send_topic_message(Message(data={...}), "TOPIC NAME")
额外参数
您可以添加 additional_registration_ids(序列)来手动发送注册 ID。它会将这些 ID 追加到查询集查找返回的注册 ID 中。
您还可以添加 skip_registration_id_lookup(布尔值)以跳过与查询相关的数据库查找。
.. code-block:: python
from firebase_admin.messaging import Message from fcm_django.models import FCMDevice FCMDevice.objects.send_message(Message(...), False, ["registration_ids"])
使用多个 FCM 应用
默认情况下,消息将使用默认的 FCM firebase_admin.App(我们已在设置中初始化)发送,或者使用 DEFAULT_FIREBASE_APP 设置指定的应用。
通过在调用 send_message 时指定应用,可以覆盖此默认设置。这可用于使用不同的 Firebase 项目发送消息。
.. code-block:: python
from firebase_admin import initialize_app from firebase_admin.messaging import Message, Notification from fcm_django.models import FCMDevice
secondary_app = initialize_app(..., name="messaging")
device = FCMDevice.objects.all().first()
device.send_message(
Message(notification=Notification(title="Hi", body="Secondary app")),
app=secondary_app,
)
为 FCM 设置默认 Firebase 应用
如果您希望将特定的 Firebase 应用用于所有 fcm-django 请求,可以创建一个 firebase_admin.App 实例,并通过 DEFAULT_FIREBASE_APP 设置将其传递给 fcm-django。
DEFAULT_FIREBASE_APP 将用于所有发送/订阅/取消订阅请求,包括 FCMDevice 的管理操作。
在您的 settings.py 中:
.. code-block:: python
from firebase_admin import initialize_app, credentials from google.auth import load_credentials_from_file from google.oauth2.service_account import Credentials
# 创建自定义 Credentials 类以加载非默认的 Google 服务账户 JSON
class CustomFirebaseCredentials(credentials.ApplicationDefault):
def __init__(self, account_file_path: str):
super().__init__()
self._account_file_path = account_file_path
def _load_credential(self):
if not self._g_credential:
self._g_credential, self._project_id = load_credentials_from_file(self._account_file_path,
scopes=credentials._scopes)
# 初始化默认的 firebase 应用
# 这会使用 GOOGLE_APPLICATION_CREDENTIALS 环境变量加载默认的 Google 服务账户
FIREBASE_APP = initialize_app()
# 为 fcm-django 初始化第二个 firebase 应用
# 环境变量包含自定义 Google 服务账户 JSON 的路径
custom_credentials = CustomFirebaseCredentials(os.getenv('CUSTOM_GOOGLE_APPLICATION_CREDENTIALS'))
FIREBASE_MESSAGING_APP = initialize_app(custom_credentials, name='messaging')
FCM_DJANGO_SETTINGS = {
"DEFAULT_FIREBASE_APP": FIREBASE_MESSAGING_APP,
# [...] 您的其他设置
}
Django REST Framework (DRF) 支持
视图集有两种不同类型:
-
FCMDeviceViewSet- 权限遵循您的 Django REST Framework 配置
- 设备可以注册,无需将其与用户关联
- 不允许重复的 registration_id
-
FCMDeviceAuthorizedViewSet- 权限为
IsAuthenticated和自定义权限IsOwner,仅允许request.user获取和更新属于该用户的设备 - 要求用户进行身份验证,因此所有设备都将与用户关联
- 重复注册 ID 时会更新设备
- 权限为
可以通过以下两种方式添加路由:
Routers_(包含所有视图)
.. _Routers: http://www.django-rest-framework.org/tutorial/6-viewsets-and-routers#using-routers
.. code-block:: python
from fcm_django.api.rest_framework import FCMDeviceAuthorizedViewSet
from rest_framework.routers import DefaultRouter
router = DefaultRouter()
router.register('devices', FCMDeviceAuthorizedViewSet)
urlpatterns = [
# URL 将显示在 <api_root>/devices
# 列出所有可用端点的 DRF 可浏览 API
path('', include(router.urls)),
# ...
]
- 使用
as_view_(指定要包含的视图)
.. _as_view: http://www.django-rest-framework.org/tutorial/6-viewsets-and-routers#binding-viewsets-to-urls-explicitly
.. code-block:: python
from fcm_django.api.rest_framework import FCMDeviceAuthorizedViewSet
urlpatterns = [
# 仅允许已认证用户创建设备
path('devices', FCMDeviceAuthorizedViewSet.as_view({'post': 'create'}), name='create_fcm_device'),
# 详情路由必须包含视图集使用的查找字段
path(
'devices/<str:registration_id>',
FCMDeviceAuthorizedViewSet.as_view({'delete': 'destroy'}),
name='delete_fcm_device',
),
# ...
]
使用重复注册 ID 更新设备
令牌是设备特定的,因此,如果用户在您的设备上登出其账户,而另一位用户在同一设备上登录,您不希望旧用户在登出状态下收到消息。
通过 DRF,任何使用已存在注册 ID 创建设备的操作都将转换为更新操作。如果手动操作,则您需要负责删除旧的设备条目。
使用自定义 FCMDevice 模型
如果您需要自定义设备模型,请参阅 使用自定义 FCMDevice 模型。
Python 3 支持
fcm-django完全兼容 Python 3.10+- 已停止支持 Python 3.9,因为 Python 3.9 已达到生命周期结束。
- 对于 Python 3.6,请使用
fcm-django < 2.0.0,因为 6 版 firebase-admin 放弃了对 Python 3.6 的支持 - 对于 Python 3.7 + 3.8,请使用
fcm-django <= 2.2.1
Django 版本兼容性
兼容 Django 4.2+ 版本。
对于 Django 2.2 版本,请使用 fcm-django < 1.0.13。
对于更低的 Django 版本,请使用 fcm-django < 1.0.0。
需要帮助、有任何问题或建议?
请在此项目上提交 issue/PR。请勿向我发送电子邮件,因为这样社区将没有机会看到您的问题/提供答案。
贡献指南
设置开发环境:
- 使用
python3 -m venv env创建虚拟环境- 在 Windows 的 Powershell 中,使用
source env/bin/activate或.\env\Scripts\activate.ps1激活虚拟环境 - 运行
pip install -r requirements_dev.txt
- 在 Windows 的 Powershell 中,使用
要手动运行预提交钩子,请运行 pre-commit run --all-files。
由于可能使用交换模型,因此测试包含两个配置文件:
- 使用默认设置和非交换模型
settings/default.py - 仅包含 swapper 所需的覆盖设置
settings/swap.py
要在本地运行测试,您可以使用 pytest,如果需要在不同数据库上检查迁移,则必须指定环境变量 DATABASE_URL,例如
.. code-block:: console
export DATABASE_URL=postgres://postgres:postgres@127.0.0.1:5432/postgres export DJANGO_SETTINGS_MODULE=tests.settings.default # 或 export DJANGO_SETTINGS_MODULE=tests.settings.swap pytest
为 PyPi 打包
- 运行
source env/bin/activate - 运行
rm -rf dist/ - 运行
python3 -m build - 运行
twine upload dist/*
致谢
本库依赖 firebase-admin-sdk 发送通知,有关所有可能字段的更多信息,请参见: https://github.com/firebase/firebase-admin-python
从 v0 到 v1 的迁移由 Andrew-Chen-Wang 完成。
项目介绍
FCM Django: Send push notifications via django to websites, iOS & android mobile devices through FCM (Firebase Cloud Messaging)