社交web允许用户之间相互联系。

例如:

关注者、好友、联系人、联络人或伙伴。

记录两个用户之间的定向联系,在数据库查询中也要使用这种联系。

一、论数据库关系

一对多关系

数据库使用关系建立记录之间的联系。其中,一对多关系是最常用的关系类型,它把一个记录和一组相关的记录联系在一起。实现这种关系,要在“多”这一层加一个外键,指向“一”这一侧,例如下列代码:

class Role(db.Model):
__tablename__ = 'roles'   id = db.Column(db.Integer,primary_key = True)
#...
users = db.relationship('User', backref='role', lazy='dynamic') class User(UserMixin, db.Model):
__tablename__ = 'users'
#...
role_id = db.Column(db.Integer, db.ForeignKey('roles.id'))

其中,users的数据库表中添加了一个外键role_id 指向了roles表的id

大部分的其他关系类型都可以从一对多类型中衍生。

多对一关系从“多”这一侧看,就是一对多关系。一对一关系类型是简化版的一对多关

多对多关系

解决方法是添加第三张表,这个表称为关联表。多对多关系可以分解成原表和关联表之间的两个一对多关系。

用SQLAlchemy实现图中的关系。

registrations = db.Table('registrations',
db.Column('student_id', db.Integer, db.ForeignKey('students.id')),
db.Column('class_id', db.Integer, db.ForeignKey('classes.id'))
)
class Student(db.Model):
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String)
classes = db.relationship('Class',
secondary=registrations,
backref=db.backref('students', lazy='dynamic'),
lazy='dynamic')
class Class(db.Model):
id = db.Column(db.Integer, primary_key = True)
name = db.Column(db.String)

多对多关系仍使用定义一对多关系的db.relationship() 方法进行定义,但在多对多关系中,必须把secondary 参数设为关联表。多对多关系可以在任何一个类中定义,backref 参数会处理好关系的另一侧。关联表就是一个简单的表,不是模型,SQLAlchemy 会自动接管这个表。

自引用关系

如果关系中的两侧都在同一个表中,这种关系称为自引用关系。

高级多对多关系

使用多对多关系时,往往需要存储所联两个实体之间的额外信息。对用户之间的关注来说,可以存储用户关注另一个用户的日期,这样就能按照时间顺序列出所有关注者。这种
信息只能存储在关联表中,但是在之前实现的学生和课程之间的关系中,关联表完全是由SQLAlchemy 掌控的内部表。

为了能在关系中处理自定义的数据,我们必须提升关联表的地位,使其变成程序可访问的模型。

app/models/user.py:关注关联表的模型实现

class Follow(db.Model):
__tablename__ = 'follows'
follower_id = db.Column(db.Integer,db.ForeignKey('users.id'),primary_key = True)
followed_id = db.Column(db.Integer,db.ForegnKey('users.id'),primary_key = True)
timestamp = db.Column(db.DateTime,default = datetime.utcnow)

app/models/user.py:使用两个一对多关系实现的多对多关系

class User(UserMixin, db.Model):
# ...
followed = db.relationship('Follow',
foreign_keys=[Follow.follower_id],
backref=db.backref('follower', lazy='joined'),
lazy='dynamic',
cascade='all, delete-orphan')
followers = db.relationship('Follow',
foreign_keys=[Follow.followed_id],
backref=db.backref('followed', lazy='joined'),
lazy='dynamic',
cascade='all, delete-orphan')

程序现在要处理两个一对多关系,以便实现多对多关系。由于这些操作经常需要重复执行,所以最好在User 模型中为所有可能的操作定义辅助方法

app/models.py:关注关系的辅助方法

 #关注关系的辅助方法
def follow(self,user):
if not self.is_following(user):
f = Follow(follower=self,followed=user)
db.session.add(f) def unfollow(self,user):
f = self.followed.filter_by(followed_id = user.id).first()
if f:
db.session.delete(f) def is_following(self,user):
return self.followed.filter_by(follow_id = user.id).first() is not None def is_followed(self,user):
return self.followers.filter_by(follow_id = user.id).first() is not None

二、在资料页中显示关注者

app/templates/user.html:在用户资料页上部添加关注信息

{% extends "base.html" %}
{% import "_macros.html" as macros %} {% block title %}微博 - {{ user.username }}{% endblock %} {% block page_content %}
<div class="page-header">
<img class="img-rounded profile-thumbnail" src="{{ user.gravatar(size=256) }}">
<div class="profile-header">
<h1>{{ user.username }}</h1>
{% if user.name or user.location %}
<p>
{% if user.name %}{{ user.name }}<br>{% endif %}
{% if user.location %}
From <a href="http://maps.google.com/?q={{ user.location }}">{{ user.location }}</a><br>
{% endif %}
</p>
{% endif %}
{% if current_user.is_administrator() %}
<p><a href="mailto:{{ user.email }}">{{ user.email }}</a></p>
{% endif %}
{% if user.about_me %}<p>{{ user.about_me }}</p>{% endif %}
<p>创建时间 {{ moment(user.member_since).format('L') }}. 最后访问 {{ moment(user.last_seen).fromNow() }}.</p>
<p>{{ user.posts.count() }} 博客文章.</p>
<p>
{% if current_user.can(Permission.FOLLOW) and user != current_user %}
{% if not current_user.is_following(user) %}
<a href="{{ url_for('.follow', username=user.username) }}" class="btn btn-primary">关注</a>
{% else %}
<a href="{{ url_for('.unfollow', username=user.username) }}" class="btn btn-success">取消关注</a>
{% endif %}
{% endif %}
<a href="{{ url_for('.followers', username=user.username) }}">关注者: <span class="badge">{{ user.followers.count() }}</span></a>
<a href="{{ url_for('.followed_by', username=user.username) }}">被关注: <span class="badge">{{ user.followed.count() }}</span></a>
{% if current_user.is_authenticated and user != current_user and user.is_following(current_user) %}
| <span class="label label-default">关注了你</span>
{% endif %}
</p>
<p>
{% if user == current_user %}
<a class="btn btn-default" href="{{ url_for('.edit_profile') }}">编辑个人资料</a>
{% endif %}
{% if current_user.is_administrator() %}
<a class="btn btn-danger" href="{{ url_for('.edit_profile_admin', id=user.id) }}">编辑个人资料 [管理员]</a>
{% endif %}
</p>
</div>
</div>
<h3>Posts by {{ user.username }}</h3>
{% include '_posts.html' %}
{% if pagination %}
<div class="pagination">
{{ macros.pagination_widget(pagination, '.user', username=user.username) }}
</div>
{% endif %}
{% endblock %}

基于python的web应用开发-添加关注者的更多相关文章

  1. 《Flask Web开发——基于Python的Web应用开发实践》一字一句上机实践(上)

    目录 前言 第1章 安装 第2章 程序的基本结构 第3章 模板 第4章 Web表单 第5章 数据库 第6章 电子邮件 第7章 大型程序的结构   前言 学习Python也有一个半月时间了,学到现在感觉 ...

  2. 基于Python的WEB接口开发与自动化测试 pdf(内含书签)

    基于Python的WEB接口开发与自动化测试 目录 目 录O V目 录章 Python 学习必知 ................................................... ...

  3. 基于Python的Web应用开发实践总结

    基于Python的Web应用开发学习总结 项目地址   本次学习采用的是Flask框架.根据教程开发个人博客系统.博客界面如图所示. 整个学习过程收获很多,以下是学习总结. 1.virtualenv ...

  4. 学习参考《Flask Web开发:基于Python的Web应用开发实战(第2版)》中文PDF+源代码

    在学习python Web开发时,我们会选择使用Django.flask等框架. 在学习flask时,推荐学习看看<Flask Web开发:基于Python的Web应用开发实战(第2版)> ...

  5. FlaskWeb开发:基于Python的Web应用开发实战

    所属网站分类: 资源下载 > python电子书 作者:熊猫烧香 链接:http://www.pythonheidong.com/blog/article/63/ 来源:python黑洞网,专注 ...

  6. 基于Python的Web应用开发实战——3 模板

    要想开发出易于维护的程序,关键在于编写形式简洁且结构良好的代码. 当目前为止,你看到的示例都太简单,无法说明这一点,但Flask视图函数的两个完全独立的作用却被融合在了一起,这就产生了一个问题. 视图 ...

  7. 基于Python的Web应用开发实战——2 程序的基本结构

    2.1 初始化 所有Flaks程序都必须创建一个程序实例. Web服务器使用一种名为Web服务器网关接口(Web Server Gateway Interface,WSGI)的协议,把接收自客户端的所 ...

  8. 基于python的互联网软件测试开发(自动化测试)-全集合

    基于python的互联网软件测试开发(自动化测试)-全集合 1   关键字 为了便于搜索引擎收录本文,特别将本文的关键字给强调一下: python,互联网,自动化测试,测试开发,接口测试,服务测试,a ...

  9. 关于基于.net的WEB程序开发所需要的一些技术归纳

    前提: 最近公司里有一个同事,年龄比我大几岁,但是由于是转行来做开发的,许多的关于.net开发技术不是很入行,所以总是会问我一些东西,基于自己以前的一些 经验,总是会愿意给他讲一些总结性的东西,希望他 ...

随机推荐

  1. [转发]读取txt防止读到乱码--自动根据文件编码进行读取

    以下是摘抄 /// <summary> /// 获取文件的编码格式 /// </summary> public class EncodingType { /// <sum ...

  2. spring @Autowired和jdk的@Resource区别

    当一个接口只有一个实例时,使用这两个注解的效果是一样的. 当含有两个实例时,非得使用 @Autowired 那么定义的引用类型必须和service实现类定义的名字相同,参照下图 定义第一个servic ...

  3. C#提取字符串中的数字字符串

    1               }

  4. HTTP-FLV直播初探

    目前几种视频流的简单对比: 协议 httpflv rtmp hls dash 传输方式 http流 tcp流 http http 视频封装格式 flv flv tag Ts文件 Mp4 3gp web ...

  5. HTML5技术分享 ES2017继发与并发

    大家都知道,async函数的返回值是 Promise 对象,这比 Generator 函数的返回值是 Iterator 对象方便多了.你可以用then方法指定下一步的操作. 进一步说,async函数完 ...

  6. Redis Save 与 BGSAVE 的区别

    一,save保存数据到磁盘的方式: Redis Save 命令执行一个同步保存操作,将当前 Redis 实例的所有数据快照(snapshot)以 RDB 文件的形式保存到硬盘. 语法redis Sav ...

  7. Python:多线程编程

    1.IO编程 IO(input/output).凡是用到数据交换的地方,都会涉及io编程,例如磁盘,网络的数据传输.在IO编程中,stream(流)是一种重要的概念,分为输入流(input strea ...

  8. Memcached 及 Redis 架构分析和区别比较

    Memcached和Redis作为两种Inmemory的key-value数据库,在设计和思想方面有着很多共通的地方,功能和应用方面在很多场合下(作为分布式缓存服务器使用等) 也很相似,在这里把两者放 ...

  9. SurfaceView 及相关概念

    ============================================================= SurfaceView=========================== ...

  10. 深入理解ES6之——JS类的相关知识

    基本的类声明 类声明以class关键字开始,其后是类的名称:剩余部分的语法看起来像对象字面量中的方法简写,并且在方法之间不需要使用逗号. class Person { //等价于prototype的构 ...