VB.net 2010 视频教程 VB.net 2010 视频教程 python基础视频教程
SQL Server 2008 视频教程 c#入门经典教程 Visual Basic从门到精通视频教程
当前位置:
首页 > 编程开发 > python爬虫 >
  • Flask 教程 第二十一章:用户通知(2)

': Notification}
复制代码

我还将在用户模型中添加一个add_notification()辅助方法,以便更轻松地处理这些对象:

app/models.py:Notification模型。

复制代码
1 class User(UserMixin, db.Model):
2     # ...
3 
4     def add_notification(self, name, data):
5         self.notifications.filter_by(name=name).delete()
6         n = Notification(name=name, payload_json=json.dumps(data), user=self)
7         db.session.add(n)
8         return n
复制代码

此方法不仅为用户添加通知给数据库,还确保如果具有相同名称的通知已存在,则会首先删除该通知。 我将要使用的通知将被称为unread_message_count。 如果数据库已经有一个带有这个名称的通知,例如值为3,则当用户收到新消息并且消息计数变为4时,我就会替换旧的通知。

在任何未读消息数改变的地方,我需要调用add_notification(),以便我更新用户的通知,这样的地方有两处。 首先,在send_message()视图函数中,当用户收到一个新的私有消息时:

app/main/routes.py:更新用户通知。

复制代码
 1 @bp.route('/send_message/<recipient>', methods=['GET', 'POST'])
 2 @login_required
 3 def send_message(recipient):
 4     # ...
 5     if form.validate_on_submit():
 6         # ...
 7         user.add_notification('unread_message_count', user.new_messages())
 8         db.session.commit()
 9         # ...
10     # ...
复制代码

第二个地方是用户转到消息页面时,未读计数需要归零:

app/main/routes.py:查看消息视图函数。

复制代码
1 @bp.route('/messages')
2 @login_required
3 def messages():
4     current_user.last_message_read_time = datetime.utcnow()
5     current_user.add_notification('unread_message_count', 0)
6     db.session.commit()
7     # ...
复制代码

既然用户的所有通知都保存在数据库中,那么我可以添加一条新路由,客户端可以使用该路由为登录用户检索通知:

app/main/routes.py:通知视图函数。

复制代码
 1 from app.models import Notification
 2 
 3 # ...
 4 
 5 @bp.route('/notifications')
 6 @login_required
 7 def notifications():
 8     since = request.args.get('since', 0.0, type=float)
 9     notifications = current_user.notifications.filter(
10         Notification.timestamp > since).order_by(Notification.timestamp.asc())
11     return jsonify([{
12         'name': n.name,
13         'data': n.get_data(),
14         'timestamp': n.timestamp
15     } for n in notifications])
复制代码

这是一个相当简单的函数,它返回一个包含用户通知列表的JSON负载。 每个通知都以包含三个元素的字典的形式给出,即通知名称,与通知有关的附加数据(如消息数量)和时间戳。 通知按照从创建时间顺序进行排序。

我不希望客户重复发送通知,所以我给他们提供了一个选项,只请求给定时间戳之后产生的通知。 since选项可以作为浮点数包含在请求URL的查询字符串中,其中包含开始时间的unix时间戳。 如果包含此参数,则只有在此时间之后发生的通知才会被返回。

完成此功能的最后一部分是在客户端实现实际轮询。 最好的做法是在基础模板中实现,以便所有页面自动继承该行为:

app/templates/base.html:轮询通知。

复制代码
 1 ...
 2 {% block scripts %}
 3     <script>
 4         // ...
 5         {% if current_user.is_authenticated %}
 6         $(function() {
 7             var since = 0;
 8             setInterval(function() {
 9                 $.ajax('{{ url_for('main.notifications') }}?since=' + since).done(
10                     function(notifications) {
11                         for (var i = 0; i < notifications.length; i++) {
12                             if (notifications[i].name == 'unread_message_count')
13                                 set_message_count(notifications[i].data);
14                             since = notifications[i].timestamp;
15                         }
16                     }
17                 );
18             }, 10000);
19         });
20         {% endif %}
21     </script>
复制代码

该函数包含在一个模板条件中,因为我只想在用户登录时轮询新消息。对于没有登录的用户,这个函数将不会被渲染。

你已经在第二十章中看到了jQuery的$(function() { ...})模式。 这是注册一个函数在页面加载后执行的方式。 对于这个功能,我需要在页面加载时做的是设置一个定时器来获取用户的通知。 你还看到了setTimeout() JavaScript函数,它在等待特定时间之后运行作为参数给出的函数。 setInterval()函数使用与setTimeout()相同的参数,但不是一次性触发定时器,而是定期调用回调函数。 本处,我的间隔设置为10秒(以毫秒为单位),所以我将以每分钟大约六次的频率查看通知是否有更新。

利用定期计时器和Ajax,该函数轮询新通知路由,并在其完成回调中迭代通知列表。 当收到名为unread_message_count的通知时,通过调用上面定义的函数和通知中给出的计数来调整消息计数徽章。

我处理since参数的方式可能会令人困惑。 我首先将这个参数初始化为0。 参数总是包含在请求URL中,但是我不能像以前那样使用Flask的url_for()来生成查询字符串,因为一次请求中url_for()只在服务器上运行一次,而我需要since参数动态更新多次。 第一次,这个请求将被发送到/notifications?since=0,但是一旦我收到通知,我就会将since更新为它的时间戳。 这可以确保我不会收到重复的内容,因为我总是要求收到自我上次看到的通知以来发生的新通知。 同样重要的是要注意,我在interval函数外声明since变量,因为我不希望它是局部变量,我想要在所有调用中使用相同的变量。

最简单的测试方法是使用两种不同的浏览器A和B。 在两个浏览器上使用不同的用户登录Microblog。 然后从A浏览器向B浏览器上的用户发送一个或多个消息。 B浏览器的导航栏应更新为显示你在10秒钟内发送的消息数量。 而当你点击消息链接时,未读消息数重置为零。


相关教程
          
关于我们--广告服务--免责声明--本站帮助-友情链接--版权声明--联系我们       黑ICP备07002182号