├── config.py ├── picture ├── blog.png └── welcome.png ├── requirements.txt ├── app ├── models.py ├── templates │ ├── archive.html │ ├── read_more.html │ ├── welcome.html │ ├── post.html │ ├── duo_shuo.html │ └── base.html ├── __init__.py ├── views.py └── static │ ├── welcome.css │ └── base.css ├── manage.py ├── LISENCE ├── README.md └── .gitignore /config.py: -------------------------------------------------------------------------------- 1 | MONGO_SETTINGS = {'DB' : 'pure_todo'} -------------------------------------------------------------------------------- /picture/blog.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Andrew-liu/flask_pure/HEAD/picture/blog.png -------------------------------------------------------------------------------- /picture/welcome.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Andrew-liu/flask_pure/HEAD/picture/welcome.png -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | Flask==0.10.1 2 | Flask-Markdown==0.3 3 | Flask-PyMongo==0.3.1 4 | Flask-Script==2.0.5 5 | Flask-WTF==0.11 6 | Jinja2==2.7.3 7 | Markdown==2.6.2 8 | MarkupSafe==0.23 9 | WTForms==2.0.2 10 | Werkzeug==0.10.4 11 | flask-mongoengine==0.7.1 12 | itsdangerous==0.24 13 | mongoengine==0.9.0 14 | pymongo==2.8 15 | -------------------------------------------------------------------------------- /app/models.py: -------------------------------------------------------------------------------- 1 | from app import db 2 | import datetime 3 | 4 | class Post(db.Document): 5 | author = db.StringField(max_length=50) 6 | title = db.StringField(max_length=120, required=True) 7 | tags = db.ListField(db.StringField(max_length=30)) 8 | time = db.DateTimeField(default=datetime.datetime.now()) 9 | content = db.StringField() 10 | -------------------------------------------------------------------------------- /app/templates/archive.html: -------------------------------------------------------------------------------- 1 | 2 | {% extends "base.html" %} 3 | 4 | {% block content %} 5 |
6 | {% for post in posts %} 7 |
8 | 15 |

{{ post.title }}

16 |
17 | {% endfor %} 18 |
19 | 20 | {% endblock %} -------------------------------------------------------------------------------- /manage.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | #!/usr/bin/env python 3 | 4 | from flask.ext.script import Manager, Server 5 | from app import app 6 | from app.models import Post 7 | 8 | manager = Manager(app) 9 | manager.add_command("runserver", 10 | Server(host="127.0.0.1", port=5000, use_debugger=True)) 11 | 12 | @manager.command 13 | def save_post(): 14 | post = Post(author="Andrew liu", 15 | title="Hello World", 16 | tags="test", 17 | content="This is the First Post") 18 | post.save() 19 | 20 | if __name__ == '__main__': 21 | manager.run() 22 | -------------------------------------------------------------------------------- /app/templates/read_more.html: -------------------------------------------------------------------------------- 1 | 2 | {% extends "base.html" %} 3 | 4 | {% block content %} 5 |
6 | {% if post %} 7 |
8 | 13 | 14 |

{{ post.title }}

15 |
16 |

17 | {{ post.content|markdown }} 18 |

19 |
20 | {% include 'duo_shuo.html' %} 21 | {% endif %} 22 |
23 | {% endblock %} -------------------------------------------------------------------------------- /app/__init__.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | #!/usr/bin/env python 3 | 4 | from flask import Flask 5 | from flask.ext.mongoengine import MongoEngine 6 | from flaskext.markdown import Markdown 7 | 8 | app = Flask(__name__) #创建Flask类的实例 9 | app.config.from_object("config") #从config.py读入配置 10 | md = Markdown(app, 11 | extensions=['footnotes'], 12 | entension_configs={'footnotes':('PLACE_MARKER', '```')}, 13 | safe_mode=True, 14 | output_format='html4') 15 | db = MongoEngine(app) #实例化数据库 16 | 17 | #这个import语句放在这里, 防止views, models import发生循环import 18 | from app import views, models 19 | 20 | -------------------------------------------------------------------------------- /app/templates/welcome.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | {% if title %} 4 | {{ title }} - 雪忆 5 | {% else %} 6 | 雪忆 7 | {% endif %} 8 | 9 | 10 | 11 | 12 |
13 |
14 |
15 | 16 |

Andrew Liu 雪 忆

17 |

雪忆, 如雪般单纯, 冷静思考.

18 |
19 |
20 |
21 | 22 | -------------------------------------------------------------------------------- /app/templates/post.html: -------------------------------------------------------------------------------- 1 | 2 | {% extends "base.html" %} 3 | 4 | {% block content %} 5 |
6 | {% for post in posts %} 7 |
8 | 13 | 14 |

{{ post.title }}

15 |
16 |

17 | {{ post.content|markdown}} 18 |

19 | Read more → 20 |
21 | {% endfor %} 22 |
23 | 24 | {% endblock %} -------------------------------------------------------------------------------- /app/templates/duo_shuo.html: -------------------------------------------------------------------------------- 1 | 2 |
3 | 4 | 5 | 16 | -------------------------------------------------------------------------------- /app/views.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | #!/usr/bin/env python 3 | 4 | from app import app 5 | from flask import render_template, url_for 6 | from app.models import Post 7 | 8 | @app.route('/') 9 | def index(): 10 | return render_template('welcome.html', title="Welcome") 11 | 12 | @app.route('/home') 13 | def home(): 14 | posts = Post.objects.all() 15 | return render_template('post.html', title="Home", posts=posts) 16 | 17 | @app.route('/post/') 18 | def read_more(title): 19 | post = Post.objects.get_or_404(title=title) 20 | return render_template('read_more.html', title="Post", post=post) 21 | 22 | @app.route('/archive') 23 | def archive(): 24 | posts = Post.objects.all() 25 | return render_template('archive.html', title='Archive', posts=posts) 26 | 27 | -------------------------------------------------------------------------------- /LISENCE: -------------------------------------------------------------------------------- 1 | copyright (c) 2015 [Andrew Liu](http://andrewliu.tk) 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy of 4 | this software and associated documentation files (the "Software"), to deal in 5 | the Software without restriction, including without limitation the rights to 6 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies 7 | of the Software, and to permit persons to whom the Software is furnished to do 8 | so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in all 11 | copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | SOFTWARE. 20 | -------------------------------------------------------------------------------- /app/static/welcome.css: -------------------------------------------------------------------------------- 1 | /* reset */ 2 | * { 3 | margin: 0; 4 | padding: 0; 5 | } 6 | 7 | #wrapper { 8 | position: absolute; 9 | width: 100%; 10 | height: 100%; 11 | overflow: hidden; 12 | } 13 | 14 | label { 15 | cursor: pointer; 16 | } 17 | label:focus { 18 | outline: none; 19 | } 20 | 21 | /* for show */ 22 | html, body { 23 | height: 100%; 24 | } 25 | 26 | body { 27 | background: url(http://37.media.tumblr.com/f6c67ec2821a91051e4175f8a102e1e2/tumblr_n6rzpcsMk41st5lhmo1_1280.jpg) 50% 50%/cover; 28 | } 29 | 30 | p { 31 | margin-bottom: 15px; 32 | } 33 | 34 | #info { 35 | display: table; 36 | background: rgba(0, 0, 0, 0.4); 37 | height: 100%; 38 | width: 100%; 39 | } 40 | #info #info-content { 41 | display: table-cell; 42 | vertical-align: middle; 43 | text-align: center; 44 | text-transform: uppercase; 45 | color: #fff; 46 | font-size: 12px; 47 | } 48 | #info #info-content h1 { 49 | color: #fff; 50 | border: 3px solid #fff; 51 | text-align: center; 52 | background: rgba(0, 0, 0, 0.1); 53 | font-size: 22px; 54 | font-weight: normal; 55 | padding: 20px; 56 | margin: 10px; 57 | display: inline-block; 58 | } 59 | #info #info-content h1 strong { 60 | display: block; 61 | font-size: 26px; 62 | } 63 | 64 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Overview 2 | 3 | **Flask_Pure** which develop a Blog by Flask, It will update with learing. 4 | 5 | 6 | ![Welcome](https://github.com/Andrew-liu/flask_pure/blob/master/picture/blog.png) 7 | 8 | ![Blog](https://github.com/Andrew-liu/flask_pure/blob/master/picture/welcome.png) 9 | 10 | 11 | # Requirements 12 | 13 | - Mac OS X 10.10.3 14 | - Sublime Text 3 15 | - FLask 0.10.1 16 | - Python 3.4.1 # 请放手Python2.7.8, 拥抱Python3 17 | - virtualenv 1.11.6 18 | 19 | 20 | # Install 21 | 22 | ```c 23 | $ git clone https://github.com/Andrew-liu/flask_pure 24 | ``` 25 | 26 | or 27 | 28 | ```c 29 | 30 | $ git clone git@github.com:Andrew-liu/flask_pure.git 31 | ``` 32 | 33 | # Usage 34 | 35 | You can use the blog simply, just to do below: 36 | 37 | ``` 38 | $ cd flask_pure 39 | $ pip install -r requirements.txt #install all tools 40 | $ python manage.py runserver 41 | 42 | open the website(chrome best) and input 43 | http://127.0.0.1:5000/ 44 | ``` 45 | 46 | 47 | 48 | # More Detail 49 | 50 | 整个博客开发过程持续更新中... 51 | 52 | # Done 53 | 54 | 55 | 1. 博客框架 56 | 2. readMore 57 | 3. 添加Markdown 58 | 4. 多说评论 59 | 5. 归档 60 | 61 | # TO DO 62 | 63 | - Admin后台管理 64 | - 标签分类 65 | - 搜索 66 | - RSS功能 67 | - 分页功能 68 | 69 | 70 | 71 | # License 72 | 73 | Copyright (c) 2015 [Andrew Liu](http://andrewliu.tk) 74 | 75 | Licensed under the MIT License 76 | 77 | -------------------------------------------------------------------------------- /app/templates/base.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | {% if title %} 4 | {{ title }} - 雪忆 5 | {% else %} 6 | 雪忆 7 | {% endif %} 8 | 9 | 10 | 11 | 12 |
13 | 20 |
21 |
22 | 23 | 24 | 37 | 48 | {% block content %}{% endblock %} 49 |
50 | 51 | 52 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Byte-compiled / optimized / DLL files 2 | __pycache__/ 3 | *.py[cod] 4 | 5 | # C extensions 6 | *.so 7 | 8 | # Distribution / packaging 9 | .Python 10 | env/ 11 | build/ 12 | develop-eggs/ 13 | dist/ 14 | downloads/ 15 | eggs/ 16 | lib/ 17 | lib64/ 18 | parts/ 19 | sdist/ 20 | var/ 21 | *.egg-info/ 22 | .installed.cfg 23 | *.egg 24 | 25 | # PyInstaller 26 | # Usually these files are written by a python script from a template 27 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 28 | *.manifest 29 | *.spec 30 | 31 | # Installer logs 32 | pip-log.txt 33 | pip-delete-this-directory.txt 34 | 35 | # Unit test / coverage reports 36 | htmlcov/ 37 | .tox/ 38 | .coverage 39 | .cache 40 | nosetests.xml 41 | coverage.xml 42 | 43 | # Translations 44 | *.mo 45 | *.pot 46 | 47 | # Django stuff: 48 | *.log 49 | 50 | # Sphinx documentation 51 | docs/_build/ 52 | 53 | # PyBuilder 54 | target/ 55 | 56 | .DS_Store 57 | .AppleDouble 58 | .LSOverride 59 | 60 | # Icon must end with two \r 61 | Icon 62 | 63 | 64 | # Thumbnails 65 | ._* 66 | 67 | # Files that might appear on external disk 68 | .Spotlight-V100 69 | .Trashes 70 | 71 | # Directories potentially created on remote AFP share 72 | .AppleDB 73 | .AppleDesktop 74 | Network Trash Folder 75 | Temporary Items 76 | .apdisk 77 | 78 | 79 | # Java 80 | *.class 81 | # Mobile Tools for Java (J2ME) 82 | .mtj.tmp/ 83 | # Package Files # 84 | *.jar 85 | *.war 86 | *.ear 87 | # virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml 88 | hs_err_pid* 89 | 90 | 91 | -------------------------------------------------------------------------------- /app/static/base.css: -------------------------------------------------------------------------------- 1 | @import url(http://fonts.googleapis.com/css?family=Open+Sans:400,800,700,600,300); 2 | 3 | body { 4 | margin:0; 5 | font-family: 'Open Sans', sans-serif; 6 | background: #eee; 7 | } 8 | 9 | hr { 10 | background:#dedede; 11 | border:0; 12 | height:1px; 13 | } 14 | 15 | .header { 16 | overflow: hidden; 17 | display:block; 18 | position:fixed; 19 | top:0; 20 | margin:0; 21 | width:100%; 22 | height:4px; 23 | text-align:center; 24 | } 25 | 26 | .header ul { 27 | margin:0; 28 | padding:0; 29 | } 30 | 31 | .header ul li { 32 | overflow:hidden; 33 | display:block; 34 | float:left; 35 | width:20%; 36 | height:4px; 37 | } 38 | 39 | .header .cor-1 { 40 | background:#f1c40f; 41 | } 42 | 43 | .header .cor-2 { 44 | background:#e67e22; 45 | } 46 | 47 | .header .cor-3 { 48 | background:#e74c3c; 49 | } 50 | 51 | .header .cor-4 { 52 | background:#9b59b6; 53 | } 54 | 55 | .header .cor-5 { 56 | background-color: hsla(10,40%,50%,1); 57 | } 58 | 59 | .wrap { 60 | width: 950px; 61 | margin:25px auto; 62 | } 63 | 64 | nav.menu ul { 65 | overflow:hidden; 66 | float:left; 67 | width: 650px; 68 | padding:0; 69 | margin:0 0 0; 70 | list-style: none; 71 | color:#fff; 72 | background: #1abc9c; 73 | -webkit-box-shadow: 1px 1px 1px 0px rgba(204,204,204,0.55); 74 | -moz-box-shadow: 1px 1px 1px 0px rgba(204,204,204,0.55); 75 | box-shadow: 1px 1px 1px 0px rgba(204,204,204,0.55); 76 | } 77 | 78 | nav.menu ul li { 79 | float:left; 80 | margin:0; 81 | } 82 | 83 | nav.menu ul a { 84 | display:block; 85 | padding:25px; 86 | font-size: 16px; 87 | font-weight:600; 88 | text-transform: uppercase; 89 | color:#fff; 90 | text-decoration: none; 91 | transition: all 0.5s ease; 92 | } 93 | 94 | nav.menu ul a:hover { 95 | background:#16a085; 96 | text-decoration: underline; 97 | } 98 | 99 | .sidebar { 100 | width:275px; 101 | float:right; 102 | } 103 | 104 | .sidebar .widget { 105 | margin:0 0 25px; 106 | padding:25px; 107 | background:#fff; 108 | transition: all 0.5s ease; 109 | border-bottom: 2px solid #fff; 110 | } 111 | 112 | .sidebar .widget:hover { 113 | border-bottom: 2px solid #3498db; 114 | } 115 | 116 | .sidebar .widget h2 { 117 | margin:0 0 15px; 118 | padding:0; 119 | text-transform: uppercase; 120 | font-size: 18px; 121 | font-weight:800; 122 | color:#3498db; 123 | } 124 | 125 | .sidebar .widget p { 126 | font-size: 14px; 127 | } 128 | 129 | .sidebar .widget p:last-child { 130 | margin:0; 131 | } 132 | 133 | .blog { 134 | float:left; 135 | } 136 | 137 | .conteudo { 138 | width:600px; 139 | margin:25px auto; 140 | padding:25px; 141 | background: #fff; 142 | border:1px solid #dedede; 143 | -webkit-box-shadow: 1px 1px 1px 0px rgba(204,204,204,0.35); 144 | -moz-box-shadow: 1px 1px 1px 0px rgba(204,204,204,0.35); 145 | box-shadow: 1px 1px 1px 0px rgba(204,204,204,0.35); 146 | } 147 | 148 | .conteudo img { 149 | margin:0 0 25px -25px; 150 | max-width: 650px; 151 | min-width: 650px; 152 | } 153 | 154 | .conteudo h1 { 155 | margin:0 0 15px; 156 | padding:0; 157 | font-family: Georgia; 158 | font-weight: normal; 159 | color: #666; 160 | } 161 | 162 | .conteudo p:last-child { 163 | margin: 0; 164 | } 165 | 166 | .conteudo .continue-lendo { 167 | color:#000; 168 | font-weight: 700; 169 | text-decoration: none; 170 | transition: all 0.5s ease; 171 | } 172 | 173 | .conteudo .continue-lendo:hover { 174 | margin-left:10px; 175 | } 176 | 177 | .post-info { 178 | float: right; 179 | margin: -10px 0 15px; 180 | font-size: 12px; 181 | text-transform: uppercase; 182 | } 183 | 184 | @media screen and (max-width: 960px) { 185 | 186 | .header { 187 | position:inherit; 188 | } 189 | 190 | .wrap { 191 | width: 90%; 192 | margin:25px auto; 193 | } 194 | .sidebar { 195 | width:100%; 196 | float:right; 197 | margin:25px 0 0; 198 | } 199 | 200 | .sidebar .widget { 201 | padding:5%; 202 | } 203 | 204 | nav.menu ul { 205 | width: 100%; 206 | } 207 | 208 | nav.menu ul { 209 | float:inherit; 210 | } 211 | 212 | nav.menu ul li { 213 | float:inherit; 214 | margin:0; 215 | } 216 | 217 | nav.menu ul a { 218 | padding:15px; 219 | font-size: 16px; 220 | border-bottom:1px solid #16a085; 221 | border-top:1px solid #1abf9f; 222 | } 223 | 224 | .blog { 225 | width:90%; 226 | } 227 | 228 | .conteudo { 229 | float:inherit; 230 | width:101%; 231 | padding:5%; 232 | margin:0 auto 25px; 233 | background: #fff; 234 | border:1px solid #dedede; 235 | } 236 | 237 | .conteudo img { 238 | margin:0 0 25px -5%; 239 | max-width: 110%; 240 | min-width: 110%; 241 | } 242 | 243 | .conteudo .continue-lendo:hover { 244 | margin-left:0; 245 | } 246 | 247 | 248 | } 249 | 250 | @media screen and (max-width: 460px) { 251 | 252 | nav.menu ul a { 253 | padding:15px; 254 | font-size: 14px; 255 | } 256 | 257 | .sidebar { 258 | display:none 259 | } 260 | .post-info { 261 | display:none; 262 | } 263 | 264 | .conteudo { 265 | margin:25px auto; 266 | } 267 | 268 | .conteudo img { 269 | margin:-5% 0 25px -5%; 270 | } 271 | 272 | 273 | } 274 | --------------------------------------------------------------------------------