Flask之旅FlaskWeb开发:基于Python的Web应用开发实战学习笔记_第1页
Flask之旅FlaskWeb开发:基于Python的Web应用开发实战学习笔记_第2页
Flask之旅FlaskWeb开发:基于Python的Web应用开发实战学习笔记_第3页
Flask之旅FlaskWeb开发:基于Python的Web应用开发实战学习笔记_第4页
Flask之旅FlaskWeb开发:基于Python的Web应用开发实战学习笔记_第5页
已阅读5页,还剩24页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

1、Flask之旅FlaskWeb开发:基于Python的Web应用开发实战学习笔记1虚拟环境2016-6-8书上介绍了virtualenv,每个venv都会拷贝一份packages到项目/venv目录。plainviewplaincopy1. virtualenvvenv2. venvScriptsactivate.bat3. (venv)$pipfreeze>requirements.txt4. (venv)$pipinstall-rrequirements.txt5. piplist-outdated6. pipinstall-upgarade<Package1><P

2、ackageN>比较了一下conda管理环境,可能conda更胜一筹:点击打开链接或者用virtualenvwrapper:点击打开链接plainviewplaincopy1. gittag列出所有打tag的分支2. gitcheckout<tag_name>切换至Utag3. gitreset-hard不保留修改.gitignore:指定哪些文件或目录不作同步,比如./venv/,*.pyc,数据库文件.sqlite3,.mysql推荐IDE:PyCharm2016.1导入已有的virtualenv:File->Setting->ProjectInterprat

3、er->选择项目目录下的/venv/Python特点:- >newFlaskProject- >jumpbetweenViewfuncionandTemplates- >Git2基本结构初始化:pythonviewplaincopy1. #-*-coding:utf-8-*-2. fromflaskimportFlask3. app=Flask(_name_)Flask类的构造函数只有一个必须指定的参数,即程序主模块或包的名字。在大多数程序中,Python的_name_变量就是所需的值。Flask用这个参数决定程序的根目录,以便稍后能够找到相对于程序根目录的资源文件位置

4、路由(route)和视图函数(viewfunction):定义路由的最简便方式,是使用程序实例提供的app.route修饰器,把修饰的函数注册为路由pythonviewplaincopy1. app.route('/')2. defindex():3. return'<h1>HelloWorld!</h1>'修饰器是Python语言的标准特性,可以使用不同的方式修改函数的行为。惯常用法是使用修饰器把函数注册为事件的处理程序。动态路由:地址中可以包含可变部分,Flask支持在路由中使用int、float和path类型。path类型也是字符串

5、,但不把斜线视作分隔符pythonviewplaincopy1. app.route('/user/<name>')2. defuser(name):3. return'<h1>Hello,%s!</h1>'%name4. app.route('/user/<int:id>')#不能有空格!默认端口是5000,可以改成其它的(flask_script.Manager也有此功能)#有些端口不能用,查询已占用的端口:netstat-ano;netstat-aon|findstr"6000&qu

6、ot;tasklist|findstr"<PID>"taskkill/f/t/imXXX.exepythonviewplaincopy1.app.run(debug=True,port=7777)1. 公认端口(WellKnownPorts):从0至U1023,紧密绑定(binding)于一些服务。通常这些端口的通讯明确表明了某种服务协议。80端口实际上总是HTTP通讯。2. 注册端口(RegisteredPorts):从1024到49151。它们松散地绑定于一些服务。这些端口同样用于许多其它目的。例如:许多系统处理动态端口从1024左右开始。3. 动态和/或私

7、有端口(Dynamicand/orPrivatePorts):从49152至U65535。理论上,不应为服务分配这些端口。实际上,机器通常从1024起分配动态端口。请求-响应循环Context上下文全局变量:?current_app程序上下文当前激活程序的程序实例?g程序上下文处理请求时用作临时存储的对象。每次请求都会重设这个变量?request请求上下文请求对象,封装了客户端发出的HTTP请求中的内容?session请求上下文用户会话,用于存储请求之间需要“记住”的值的词典URL映射是URL和视图函数之间的对应关系。Flask使用app.route修饰器或者非修饰器形式的app.add_ur

8、l_rule()生成映射。pythonviewplaincopy1. app.url_map2. Map(<Rule'/'(HEAD,OPTIONS,GET)->index>,3. <Rule'/static/<filename>'(HEAD,OPTIONS,GET)->static>,4. <Rule'/user/<name>'(HEAD,OPTIONS,GET)->user>)HEAD、Options>GET是请求方法,由路由进行处理。Flask为每个路由都指

9、定了请求方法,这样不同的请求方法发送到相同的URL上时,会使用不同的视图函数进行处理。HEAD和OPTIONS方法由Flask自动处理请求Hook:在请求钩子函数和视图函数之间共享数据一般使用上下文全局变量g1. before_first_request?:注册一个函数,在处理第一个请求之前运行。2. before_request?:注册一个函数,在每次请求之前运行。3. after_request?:注册一个函数,如果没有未处理的异常抛出,在每次请求之后运行。4. teardown_request?:注册一个函数,即使有未处理的异常抛出,也在每次请求之后运行响应(视图函数返回)?make_r

10、esponse()函数可接受1-3个参数(html,状态码,header)pythonviewplaincopy1. response=make_response('<h1>Thisdocumentcarriesacookie!</h1>',200)2. response.set_cookie('answer','42')3. returnresponse?重定向的特殊响应类型,302:returnredirect('http:')?特殊的响应由abort函数生成,用于处理错误:abort(404)Flas

11、k扩展原书更正:Importingflask.ext.scriptisdeprecated,useflask_scriptinstead.4. 模板template业务逻辑和表现逻辑要分开按功能分(模板不需要重用时),或按Division分(大部分模板需要重用时)Jinja2模板引擎模板是一个包含响应文本的文彳其中包含用占位变量.表示的动态部分,其具体值只在请求的上下文中才能知道。使用真实值替换变量,再返回最终得到的响应字符串,这一过程称为渲染。pythonviewplaincopy1. app.route('/user/<name>')2. defuser(nam

12、e):3. returnrender_template('user.html',name=name)模板变量Jinja2能识别所有类型的变量,甚至是一些复杂的类型,例如列表、字典和对象htmlviewplaincopy1. <p>Avaluefromadictionary:mydict'key'.</p>2. <p>Avaluefromalist:mylist3.</p>3. <p>Avaluefromalist,withavariableindex:mylistmyintvar.</p>4

13、. <p>Avaluefromanobject'smethod:myobj.somemethod().</p>可以使用过滤器修改变量。千万别在不可信的值上使用safe过滤器,例如用户在表单中输入的文本htmlviewplaincopy1.Hello,name|capitalize完整的过滤器列表?safe渲染值时不转义。默认情况下,出于安全考虑,Jinja2会转义所有变量?capitalize把值的首字母转换成大写,其他字母转换成小写?lower把值转换成小写形式?upper把值转换成大写形式?title把值中每个单词的首字母都转换成大写?trim把值的首尾空格

14、去掉?striptags渲染之前把值中所有的HTML标签都删掉控制结构%.%,可用来改变模板的渲染流程if,for,macro,import,include需要在多处重复使用的模板代码片段可以写入单独的文件,再包含%include'common.html'%在所有模板中另一种重复使用代码的强大方式是模板继承,block标签定义的元素可在衍生模板中修改htmlviewplaincopy1. <html>2. <head>3. %blockhead%4. <title>%blocktitle%endblock%-MyApplication<

15、/title>5. %endblock%6. </head>7. <body>8. %blockbody%9. %endblock%10. </body>11. </html>extends指令声明这个模板衍生自base.html。在extends指令之后,基模板中的3个块被重新定义,模板引擎会将其插入适当的位置。注意新定义的head块,在基模板中其内容不是空的,所以使用super()获取原来的内容(向已经有内容的块中添加新内容)。htmlviewplaincopy1. %extends"base.html"%2. %b

16、locktitle%Index%endblock%3. %blockhead%4. super()5. <style>6. </style>7. %endblock%8. %blockbody%9. <h1>Hello,World!</h1>10. %endblock%使用Flask-BootstrapBootstrap是客户端框架,因此不会直接涉及服务器。服务器需要做的只是提供引用了Bootstrap层叠样式表(CSS)和JavaScript文件的HTML响应,并在HTML、CSS和JavaScript代码中实例化所需组件。这些操作最理想的执行

17、场所就是模板。Flask-Bootstrap基模板中定义的块:doc,head,title,styles,body,navbar,content,scriptsBootstrap官方文档CDN本地加速:修改Base.html,引用本地的css文件,里面元素跟Bootstrap重名的,则会覆盖官方里相同元素htmlviewplaincopy1. %blockhead%2. super()3. <linkrel="shortcuticon"href="url_for('static',filename='favicon.ico')

18、"type="image/x-icon">4. <linkrel="icon"href="url_for('static',filename='favicon.ico')"type="image/x-icon">5.<linkrel="stylesheethref="/6. <linkrel="stylesheet"href="/7. %endblock%8.9. %blockscripts%1

19、0. super()11. <scriptsrc="/12. <scriptsrc="/13. moment.include_moment()14. moment.lang("zh-CN")15. %endblock%自定义错误页面pythonviewplaincopy1. app.errorhandler(404)2. defpage_not_found(e):3. returnrender_template('404.html'),404url_for()链接辅助函数使用url_for()生成动态地址时,将动态部分作为关键

20、字参数传入。例如,url_for('user',name='john',_external=True)的返回结果是http:/localhost:5000/user/john使用Flask-Moment本地化日期和时间。查阅文档htmlviewplaincopy1. %blockscripts%2. super()3. moment.include_moment()4. <!-使用中文,默认是英语的->5. moment.lang("zh-CN")6. %endblock%4WebForm表单app.config字典可用来存储框架

21、、扩展和程序本身的配置变量。使用标准的字典句法就能把配置值添加到app.config对象中。这个对象还提供了一些方法,可以从文件或环境中导入配置值。Form基类由Flask-WTF扩展定义,所以从flask.ext.wtf中导入。字段和验证函数可以直接从WTForms包中导入。pythonviewplaincopy1. fromflask_wtfimportForm2. fromwtformsimportStringField,SubmitField3. fromwtforms.validatorsimportDataRequired4. classNameForm(Form):5. name

22、=StringField('Whatisyourname?',validators=DataRequired()6. submit=SubmitField('Submit')WTForms支持的HTML标准字段:StringField,TextAreaField,PasswordField。WTForms内建的验证函数:Email,DataRequired.Placeholder提示:pythonviewplaincopy1.password=PasswordField('Password',validators=DataRequired(),r

23、ender_kw="placeholder":u"密码”)重定向和用户会话刷新页面后会再次提交表单。大多数情况下,这并不是理想的处理方式。很多用户都不理解浏览器发出的这个警告。基于这个原因,最好别让Web程序把POST请求作为浏览器发送的最后一个请求。这个技巧称为Post/重定向/Get模式。pythonviewplaincopy1. app.route('/',methods='GET','POST')2. defindex():3.form=NameForm()4.ifform.validate_on_submi

24、t():5. session'name'=.data6. returnredirect(url_for('index')7. returnrender_template('index.html',form=form,name=session.get('name')使用get()获取字典中键对应的值以避免未找到键的异常情况,因为对于不存在的键,get()会返回默认值None。Flash消息仅调用flash()函数并不能把消息显示出来,程序使用的模板要渲染这些消息。最好在base.html中渲染Flash消息,因为这

25、样所有页面都能使用这些消息。Flask把get_flashed_messages()函数开放给模板,用来获取并渲染消息5数据库2016-6-9使用SQL还是NoSQLSQL数据库擅于用高效且紧凑的形式存储结构化数据。这种数据库需要花费大量精力保证数据的一致性。NoSQL数据库放宽了对这种一致性的要求,从而获得性能上的优势。MySQLQ&A:安装MySQLinWindows报错:需要预先把WindowsDefender打开,或者configuremysqlserver时,不要勾选"WindowsFirewall”可能要先安装:MicrosoftVisualC+Compilerf

26、orPython2.7本地安装MySQLdb:pipinstallmysql-pythonWindow764位下安装可能还会报cl.exe错workaround:先condainstallmysql-python,再手动复制以下目录及文件至UvenvLibSite-packages下:Anaconda2Libsite-packagesMySQLdbAnaconda2Libsite-packagesMySQL_python-1.2.5.dist-infoAnaconda2Libsite-packages_mysql*MySQL创建connection之后,还需要创建"schema”-对

27、应SQLAlchemy里的adatabase”MySQLdb中文乱码的处理:conn=MySQLdb.connect(host='localhost',user='root',passwd='XXX',db='app_englishgo',charset='utf8')显示:title.encode('gbk')接收输入:unicode(request.form'title')SQLAlchemy和MongoEngine:数据库抽象层代码包(ORM、ODM),你可以使用这些抽象包直接

28、处理高等级的Python对象,而不用处理如表、文档或查询语言此类的数据库实体。使用Flask-SQLAlchemy管理数据库MySQLmysql:username:passwordhostname:port/databaseSQLite(Windows)sqlite:/c:/absolute/path/to/databaseRelationship关系型数据库pythonviewplaincopy1.classRole(db.Model):2.#.3. users=db.relationship('User',backref='role')#面向对象视角4. c

29、lassUser(db.Model):5. #.6. role_id=db.Column(db.Integer,db.ForeignKey('roles.id')#定义外键SQLAlchemy完整的命令、过滤器、查询执行列表参见SQLAlchemy文档SQLAlchemyengine设置编码,防止中文乱码:pythonviewplaincopy1. engine=create_engine('sqlite:/C:Temptestsqlalchemy.db',encoding='utf8',convert_unicode=True,echo=Tru

30、e)2. #echo:显示出内部过程及SQL语句。debug或学习时打开3. #encoding:防止乱码pythonviewplaincopy1. 'mysql:/uid:pwdlocalhost/mydb?charset=utf8'集成Pythonshell每次启动shell会话都要导入数据库实例和模型。为避免重复导入,我们可以做些配置,让Flask-Script的shell命令自动导入特定的对象。为shell命令注册一个make_context回调函数新数据库迁移flask-migrate由于模型中经常会新加一行或几行column(比如用来保存账户的确认状态),此时要修改

31、models.py,并执行一次新数据库迁移MySQLWorkbench自动产生EER,可以清楚地看到各个表格之间关系:一对多Foreign_Key、Index等1) config.py:pythonviewplaincopy1. classDevelopmentConfig(Config):2. DEBUG=True3. #SQLALCHEMY_DATABASE_URI=os.environ.get('DEV_DATABASE_URL')or'sqlite:/'+os.path.join(basedir,'data-dev.sqlite')4.

32、SQLALCHEMY_DATABASE_URI='mysql:/USER:PASSWORDlocalhost:3306/flaskr'2) pythonmanage.pydeploy选择connection->database3) MySQLWorkbench:Database->ReverseEngineer->->一路NextOpastsidlNT(ll)bodyItKTtimestampDATETIMErolejdINTCll)authorjdIMT(ll)bodV-htrlTbXTpassword_hashVARCHARC128)confirme

33、dTINYINr(i)aboutmeTEXT1stseenDATETIMElocationVAFLCHAR(64)memhersinceDATETIMEidlNT(ll)nameVAR£HAR(64)H-bodyTEKTbody_htmlTEXTPRIMARYtimestampDATETIMEixusersusemaneixusersemailroleidpostjdIMT(ll)usernameV7RCHAR.(6;_usersaval3r_ha;hMARCH岷02)T"lcomments一干IXAdiscedTINYINT(l)authorJdINTfll>icH

34、isrrii)VLCHAR(64)M-H-rolesidlMT(ll)nameVARCHAR(64)defeultTINYINTfl)permiionsINT(ll)PRIMARYnameijrolesdefault二IalembicversioniersionnumVARGH.AR(32)followstimestampDATFTIMEPRIMARYlbIowedid6E-mail使用Flask-Mail提供电子邮件支持pythonviewplaincopy1. app.config'MAIL_SERVER'=''2. app.config'MAIL_

35、PORT'=253. app.config'MAIL_USE_TLS'=True4. app.config'MAIL_USERNAME'=os.environ.get('MAIL_USERNAME')5. app.config'MAIL_PASSWORD'=os.environ.get('MAIL_PASSWORD')6. app.config'FLASKY_MAIL_SUBJECT_PREFIX'='Flasky'7. app.config'FLASKY_MAIL_

36、SENDER'='FlaskyAdmin<flasky>8. app.config'FLASKYADMIN'=os.environ.get('FLASKYADMIN')10. mail=Mail(app)11.12. defsendmail(mail):13. msg=Message('testsubject',sender='ezhqing',recipients='XXX')14. msg.body='textbody'15. msg.html='<b&

37、gt;HTML</b>body'16. withapp.app_context():17. mail.send(msg)千万不要把账户密令直接写入脚本,特别是当你计划开源自己的作品时。让脚本从本机环境中导入敏感信息Windows用户可按照下面的方式设定环境变量:plainviewplaincopy1. (venv)$setMAIL_USERNAME=<yourmailusername>2. (venv)$setMAIL_PASSWORD=<mailpassword>所有的在cmd命令行下对环境变量的修改只对当前窗口有效,不是永久性的修改。也就是说当关

38、闭此cmd命令行窗口后,将不再起作用。永久性修改环境变量的方法有两种:一种是直接修改注册表(overkillpythonscript),另一种是通过我的电脑->属性-高级,来设置系统的环境变量异步发送电子邮件为了避免处理请求过程中不必要的延迟,我们可以把发送电子邮件的函数移到后台线程(Threading)中很多Flask扩展都假设已经存在激活的程序上下文和请求上下文。Flask-Mail中的send()函数使用current_app,因此必须激活程序上下文。不过,在不同线程中执行mail.send()函数时,程序上下文要使用app.app_context()人工创建。7大型程序的结构项目

39、结构plainviewplaincopy1. |-flasky2. |-app/Flask程序一般都保存在名为app的程序包中3. ktemplates/templates和static文件夹是程序包的一部分4. 卜static/5. |-main/程序包中创建了一个子包,用于保存蓝本。/main/_init_.py脚本的末尾导入views.py&errors.py,避免循环导入依赖6. |-_init_.py程序工厂函数create_app(),注册蓝本7. kerrors.py错误处理路由.注册程序全局的错误处理程序,必须使用app_errorhandler8. |-forms.p

40、y表单对象9. |-views.py路由。蓝本中的全部端点会加上一个命名空间,如url_for('main.index')10. |-_init_.py11. |-email.py电子邮件支持函数12. |-models.py数据库模型13. kmigrations/数据库迁移脚本14. |-tests/单元测试15. |-_init_.py文件可以为空,因为unittest包会扫描所有模块并查找测试16. |-test*.py17. |-venv/虚拟环境18. |-requirements.txt列出了所有依赖包,便于在其他电脑中重新生成相同的虚拟环境19. |-confi

41、g.py存储配置。开发、测试和生产环境要使用不同的数据库20. |-manage.py用于启动程序以及其他的程序任务requirements.txt文件,用于记录所有依赖包及其精确的版本号。以便要在另一台电脑上重新生成虚拟环境创建:(venv)$pipfreeze>requirements.txt恢复:(venv)$pipinstall-rrequirements.txt重组后的程序和单脚本版本使用不同的数据库,可使用如下命令创建数据表或者升级到最新修订版本:(venv)$pythonmanage.pydbupgrade8用户认证Flask的认证扩展Flask-Login:管理已登录用户

42、的用户会话。Werkzeug:计算密码散列值并进行核对。itsdangerous:生成并核对加密安全令牌。创建认证蓝本对于不同的程序功能,我们要使用不同的蓝本(main,auth),这是保持代码整齐有序的好方法因为Flask认为模板的路径是相对于程序模板文件夹而言的。为避免与main蓝本和后续添加的蓝本发生模板命名冲突,可以把蓝本使用的模板保存在单独的文件夹中使用Flask-Login认证用户LoginManager对象的session_protection属性可以设为None、'basic'或'strong',以提供不同的安全等级防止用户会话遭篡改。设为

43、9;strong'时,Flask-Login会记录客户端IP地址和浏览器的用户代理信息,如果发现异动就登出用户。为了保护路由只让认证用户访问,Flask-Login提供了一个login_required修饰器current_user由Flask-Login定义,且在视图函数和模板中自动可用模板中加入用户登录后白信息和提示效果base.html:TClocalhost:5000%网=1FlaskyHomeLogOul)ohnHello,john!1. <ulclass="navnavbar-navnavbar-right">2. %ifcurrent_us

44、er.is_authenticated%3. <li><ahref="url_for('auth.logout')"title="邮件current_user.email:9+'.'">LogOutcurrent_user.username</a></li>4. %else%5. <li><ahref="url_for('auth.login')">LogIn</a></li>6. %endi

45、f%7. </ul>按照第4章介绍的“Post/重定向/Get模式",Login的POST请求最后也做了重定向,不过目标URL有两种可能。用户访问未授权的URL时会显示登录表单,Flask-Login会把原地址保存在查询字符串的next参数中,这个参数可从request.args字典中读取。如果查询字符串中没有next参数,则重定向到首页app/auth/views.pypythonviewplaincopy1. user=User.query.filter_by(email=form.email.data).first()2. ifuserisnotNoneanduse

46、r.verify_password(form.password.data):3. login_user(user,form.remember_me.data)4. returnredirect(request.args.get('next')orurl_for('main.index')用户注册表单app/auth/forms.py这个表单使用WTForms提供的Regexp验证函数,确保username字段只包含字母、数字、下划线和点号。密码要输入两次。此时要验证两个密码字段中的值是否一致,这种验证可使用WTForms提供的另一验证函数实现,即EqualTo如

47、果表单类中定义了以validate_开头且后面跟着字段名的方法,这个方法就和常规的验证函数一起调用发送确认邮件使用itsdangerous生成确认令牌pythonviewplaincopy1. >>>fromitsdangerousimportTimedJSONWebSignatureSerializerasSerializer2. >>>s=Serializer(app.config'SECRET_KEY',expires_in=3600)3. >>>token=s.dumps('confirm':23)4

48、. >>>token5.'eyJhbGciOiJIUzI1NiIsImV4cCI6MTM4MTcxODU1OCwiaWF0IjoxMzgxNzE0OTU4fQ.ey.'6. >>>data=s.loads(token)7. >>>data8. u'confirm':23对蓝本来说,before_request钩子只能应用到属于蓝本的请求上。若想在蓝本中使用针对程序全局请求的钩子,必须使用before_app_request修饰器9. UserRole角色2016-6-10角色在数据库中的表示赋予角色角色验证1

49、0. UserProfile资料2016-6-10用户资料页面htmlviewplaincopy<-Cjlocalhost:SOOD/user/johnAccountChangePasswordChangeEmailLogOutFlaskyHomeProfilejohnjack押rmFmmNanjing.ChinaHeamiriigFlaskMembe-rsince0/1D.i'2Dl6_Lastseenafewsecondsago.EditProfile资料编辑器用户头像国内被墙,改用其它方法:静态jpg头像目录:c:gitflaskyappstaticavatar001.jp

50、gXXX.jpgbase.html:htmlviewplaincopy1. <liclass="dropdown">2. <ahref="#"class="dropdown-toggle"data-toggle="dropdown">3. <imgheight="24px"src="url_for('static',filename='avatar/')current_user.avatar_hash">mo

51、dels.py:pythonviewplaincopy1. defgravatar(self,size=100,default='identicon',rating='g'):2. importrandom3. return'%.3d.jpg'%random.randint(1,XXX)user.html:htmlviewplaincopy1. <divclass="page-header">2. <imgclass="img-roundedprofile-thumbnail"src=&q

52、uot;url_for('static',filename='avatar/')current_user.avatar_hash"">_posts.html:htmlviewplaincopy1. <liclass="post">2. <divclass="post-thumbnail">3. <ahref="url_for('.user',username=post.author.username)">4. <imgh

53、eight="40px"class="img-roundedprofile-thumbnail"src="url_for('static',filename='avatar/')post.author.avatar_hash">_commments.html:htmlviewplaincopy1. <divclass="comment-thumbnail">2. <ahref="url_for('.user',username=com

54、ment.author.username)">3. <imgheight="40px'class="img-roundedprofile-thumbnail"src="url_for('static',filename='avatar/')post.author.avatar_hash">效果:Followerskimbtrly872daysagoMorbinonlectus.Fuseelacuspurus,aliquetat.feugiatnon,pretiumquislec

55、tus.Morbivestibulum.velitidpretiumiaculis.diameratfermentumjusto,neccondimentumnequesapienplaceratante.Nullamvarius.EdiitAdminIPermalinkI1CominentsdianaG32daysageMaecenasIe。odio,condimentumidLluctusnecmolestiesedjustoEditAdhimIPermalinkI2Coniirientskathryn782SysagoDoneequksorciegetorcivemculacondime

56、ntunnincargueNuNaacenlmEditAdminIPermalinkI1Comnients扩展TODO:加入性别、用户自选头像。11Blogarticles博客文章2016-6-12实现功能,即允许用户阅读、撰写博客文章。本章新技术:重用模板、分页显示长列表以及处理富文本。生成虚拟信息用于测试,其中功能相对完善的是ForgeryPypythonviewplaincopy1. pythonmanage.pyshell2. >>>User.generate_fake()3. >>>Post.generate_fake(200)添加分页导航pagi

57、nate()方法的返回值是一个Pagination类对象,这个类在Flask-SQLAlchemy中定义。这个对象包含很多属性,用于在模板中生成分页链接使用Markdown和Flask-PageDown支持富文本文章?PageDown:使用JavaScript实现的客户端Markdown至UHTML的转换程序。?Flask-PageDown:为Flask包装的PageDown,把PageDown集成至UFlask-WTF表单中。?Markdown:使用Python实现的服务器端Markdown至UHTML的转换程序。?Bleach:使用Python实现的HTML清理器。博客文章的固定链接博客文

58、章编辑器12followers关注者2016-6-12再论数据库关系一对多关系:是最常用的关系类型,它把一个记录和一组相关的记录联系在一起。实现这种关系时,要在“多”这一侧加入一个外键,指向“一”这一侧联接的记录。多对多关系:这种问题的解决方法是添加第三张表,这个表称为关联表。多对多关系可以分解成原表和关联表之间的两个一对多关系若想显示所关注用户发布的所有文章,第一步显然先要获取这些用户,然后获取各用户的文章,再按一定顺序排列,写入单独列表。可是这种方式的伸缩性不好,随着数据库不断变大,生成这个列表的工作量也不断增长,而且分页等操作也无法高效率完成。获取博客文章的高效方式是只用一次查询。完成这

59、个操作的数据库操作称为联结。联结操作用到两个或更多的数据表,在其中查找满足指定条件的记录组合,再把记录组合插入一个临时表中,这个临时表就是联结查询的结果。创建函数更新数据库这一技术经常用来更新已部署的程序,因为运行脚本更新比手动更新数据库更少出错。13 Usercomments评论评论属于某篇博客文章,因此定义了一个从posts表到comments表的一对多关系。使用这个关系可以获取某篇特定博客文章的评论列表。comments表还和users表之间有一对多关系。通过这个关系可以获取用户发表的所有评论,还能间接知道用户发表了多少篇评论管理评论,我们要在导航条中添加一个链接,具有权限的用户才能看到。14 RIA(API,REST)2016-6-12资源就是一切资源是REST架构方式的核心概念。在REST架构中,资源是程序中你要着重关注的

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论