greyli / bluelog Goto Github PK
View Code? Open in Web Editor NEWThe 2024 version: https://github.com/greyli/greybook
License: MIT License
The 2024 version: https://github.com/greyli/greybook
License: MIT License
如题,书中换主题那一节中提到checkout theme 但是并没有此tag。反馈一下。
问题描述:
文章字数会包括标签的所有字符
问题代码定位:
在 templates/admin/mange_post.html文件下35行:
{{ post.body|length }}
问题原因:
如果是用富文本创建的文章,内容会包含HTML标签,导致如果直接用length函数,字数会因标签字符偏多。
改进:
可以过滤掉HTML标签后再计算字符数。
fakes.py 中13行
from bluelog import db
是否应为
from bluelog.extensions import db
按照您在admin.py中原有的写法,所有的edit_xxx function在表单验证未通过时,已做的修改在html表单上都无法保留。
建议修改成以下写法:
@admin_bp.route('/link/<int:link_id>/edit', methods=['GET', 'POST'])
@login_required
def edit_link(link_id):
link = Link.query.get_or_404(link_id)
form = LinkForm(request.form)
if request.method == "GET":
form.name.data = link.name
form.url.data = link.url
else:
if form.validate_on_submit():
link.name = form.name.data
link.url = form.url.data
db.session.commit()
flash('Link updated.', 'success')
return redirect(url_for('.manage_link'))
return render_template('admin/edit_link.html', form=form)
您好。
filename='css/%s.min.css' % request.cookies.get('theme', 'perfect_blue')
关于这行代码,我不明白的地方有三点,可以请教一下吗?
1.您书中提到要换主题去Bootswatch下载覆盖bootstrap.min.css即可,这里是在链接同一个目录下的perfect_blue.min.css吗?
2.在这里链接perfect_blue.min.css是起到什么效果?
3.perfect_blue.min.css文件我在bootswatch网站上没有找到,这个文件是如何获取的。
先谢谢您了。
moment.js我是自己在网上找到, 以为是这个js有问题, 于是把自己的css和js都删除了, 用作者的js和css结果还是一样,后来又仔细核对代码与作者是否有出入, 检查完没问题, 于是我就在blog.py的index函数加了for post in posts: print(post.stamp)来打印时间看看是不是数据库有问题, 结果时间都打印出来了,说明posts=Post.query.xxxxxxxxxxx时间能拿到, 于是我就用作者的代码来跑一下, 结果作者的代码run 起来也只有第一篇文章有时间, 后来我想了想是否和flask-moment版本有关系,于是从0.11.0降到了作者lock文件里的0.6.0,还是只有第一篇文章有时间, 现在我打印把我的annaconda删除(python3.8.5), 重新安装3.6的再试试
如何在about页面,添加一个头像框放置自己的照片? 需要在哪个html模板上做一些改动呢。
多谢!
管理员登陆后setting里面的about栏的ck_editor没有上传图片的功能。但是新建post的时候,编辑body就有上传图片的功能。
在生成50条回复时用到
replied=Comment.query.get(random.randint(1, Comment.query.count())), post=Post.query.get(random.randint(1, Post.query.count()))
这样会不会导致生成的replied并不是生成的post的的comment呢?
{{ post.comments|length }}
post = Post.query.get_or_404(post_id)
page = request.args.get('page', 1, type=int)
per_page = current_app.config['BLUELOG_COMMENT_PER_PAGE']
pagination = Comment.query.with_parent(post).filter_by(reviewed=True).order_by(Comment.timestamp.asc()).paginate(page, per_page)
comments = pagination.items
{{ comments|length }} Comments
解决方法:
我的实现是在 Post 类中新增了一个方法, 返回审核通过的评论列表:
class Post(db.Model):
__tablename__ = 'posts'
id = db.Column(db.Integer, primary_key=True)
title = db.Column(db.String(60))
body = db.Column(db.Text)
timestamp = db.Column(db.DateTime, default=datetime.now)
category_id = db.Column(db.Integer, db.ForeignKey('categories.id'))
comments = db.relationship('Comment', backref='post', cascade='all, delete-orphan')
def reviewed_comments(self):
return [comment for comment in self.comments if comment.reviewed is True]
这样的话, 在需要显示评论数量的地方就可以使用 {{ post.reviewed_comments()|length }}。
按照作者书中思路和源码一步步搭建。
在测试过程中出现如下问题。
在访问路由 admin/post/manage
的时候报错:jinja2.exceptions.UndefinedError: 'None' has no attribute 'id'
在 templates/admin/mange_post.html
文件下:
1、<td><a href="{{ url_for('front.show_category', category_id=post.category.id) }}">{{ post.category.name }}</a>
2、<td><a href="{{ url_for('blog.show_post', post_id=post.id) }}#comments">{{ post.comments|length }}</a></td>
代码的目的是:渲染 Post 相关的 category 和 comment
1、代码逻辑忽略了 post 有可能没有 comment 和 category 的情况。
2、手动在 shell 创建了几条 POST 的测试数据,但是这些数据没有包含 Category 和 Comment 。
3、于是在渲染的时 ,Post.category , Post.comment 为 None,从而导致模板渲染失败。
1、在这类的代码前添加逻辑 {% if post.category } dosomething {% else %} None{% endif %}
2、由于上面会出现很多重复判断代码,因此可以抽取重复逻辑,用使用宏定义一个渲染函数。
感谢作者优秀的书籍和源码,收获良多~~~~
我有尝试更改对应的min.css中的background_color 但是好像没有用
首先不得不赞美作者几句,您的书籍和源码简直是棒极了!excellent!在闲暇时间阅读您的书籍,并配以github源码进行“食用”,感觉以前使用Flask编写项目时,一直紊乱的项目组织架构及代码设计思路逐渐理顺,恍然大悟的感觉油然而生,同时对您的钦佩之情也如滔滔江水绵延不绝。
当然,阅读您的源码时,遇到不太对劲的地方我会尝试修改或优化,然后提出来。如果无意让您感到吹毛求疵,还请见谅。
下面是这次的主题:「尽量使虚拟数据接近真实的数据」。当然,Faker
生成的sentence和text都是毫无意义的,这个就无所谓了。我留意的是生成评论回复的虚拟数据。
先放上原始代码,位置在bluelog/fakes.py
:
def fake_comments(count=500):
# ...
# replies
for i in range(salt):
comment = Comment(
author=fake.name(),
email=fake.email(),
site=fake.url(),
body=fake.sentence(),
timestamp=fake.date_time_this_year(),
reviewed=True,
replied=Comment.query.get(random.randint(1, Comment.query.count())),
post=Post.query.get(random.randint(1, Post.query.count()))
)
db.session.add(comment)
db.session.commit()
以上代码功能上没有问题,但是不符合以下逻辑:
因此,对以上代码做了以下优化:
fake.date_time_between_dates()
确保评论回复在评论时间之后;def fake_comments(count=500):
# ...
# replies
for i in range(salt):
comment = Comment.query.get(random.randint(1, Comment.query.count()))
reply = Comment(
author=fake.name(),
email=fake.email(),
site=fake.url(),
body=fake.sentence(),
reviewed=True,
# 确保回复的时间在评论的时间之后,并且不超过现在的时间
timestamp=fake.date_time_between_dates(comment.timestamp),
replied=comment, # 关联评论
post=comment.post # 回复与评论是同一篇文章
)
db.session.add(reply)
db.session.commit()
写到这里本来以为结束了。但转念一想似乎还有点问题:
fake.date_time_this_year()
这个生成时间的方法,如果是在1月1日生成会不会有点问题。关于第一点,同上面的修改方式一样了;
关于第二点,经过测试,我把本地时间调到2019年1月1日11点00分,生成的虚拟数据有的超过了该时间点,成了“未来的数据”。而且所有的虚拟数据的timestamp都集中在2019年1月1日,也不是很好。
经过我查阅相关资料,把fake.date_time_this_year()
改为fake.past_datetime()
就可以了,fake.past_datetime()
默认是以一个月前的时间为起点随机生成时间,可以fake.past_datetime('-1y')
这样调用,以一年前的时间为起点随机生成时间。
这样,需要修改的代码如下:
# ...
def fake_posts(count=50):
for i in range(count):
post = Post(
title=fake.sentence(),
body=fake.text(2000),
category=Category.query.get(random.randint(1, Category.query.count())),
# timestamp=fake.date_time_this_year() # modify this
timestamp=fake.past_datetime('-1y')
)
db.session.add(post)
db.session.commit()
def fake_comments(count=500):
for i in range(count):
post = Post.query.get(random.randint(1, Post.query.count()))
comment = Comment(
author=fake.name(),
email=fake.email(),
site=fake.url(),
body=fake.sentence(),
# timestamp=fake.date_time_this_year(), # modify this
timestamp=fake.date_time_between_dates(datetime_start=post.timestamp),
reviewed=True,
post=post
)
db.session.add(comment)
salt = int(count * 0.1)
for i in range(salt):
# unreviewed comments
post = Post.query.get(random.randint(1, Post.query.count()))
comment = Comment(
author=fake.name(),
email=fake.email(),
site=fake.url(),
body=fake.sentence(),
# timestamp=fake.date_time_this_year(), # modify this
timestamp=fake.date_time_between_dates(datetime_start=post.timestamp),
reviewed=False,
post=post
)
db.session.add(comment)
# from admin
post = Post.query.get(random.randint(1, Post.query.count()))
comment = Comment(
author='Mima Kirigoe',
email='[email protected]',
site='example.com',
body=fake.sentence(),
# timestamp=fake.date_time_this_year(), # modify this
timestamp=fake.date_time_between_dates(datetime_start=post.timestamp),
from_admin=True,
reviewed=True,
post=post
)
db.session.add(comment)
db.session.commit()
# replies
for i in range(salt):
comment = Comment.query.get(random.randint(1, Comment.query.count()))
reply = Comment(
author=fake.name(),
email=fake.email(),
site=fake.url(),
body=fake.sentence(),
reviewed=True,
# timestamp=fake.date_time_this_year(),
# replied=Comment.query.get(random.randint(1, Comment.query.count())),
# post=Post.query.get(random.randint(1, Post.query.count()))
# 确保回复的时间在评论的时间之后,并且不超过现在的时间
timestamp=fake.date_time_between_dates(datetime_start=comment.timestamp),
replied=comment, # 关联评论
post=comment.post # 回复与评论是同一篇文章
)
db.session.add(reply)
db.session.commit()
# ...
切换成Black Swan主题时,导航栏的高亮不能显示(Home和About),默认主题没有问题
I use firefox explorer, when I run the flask project, the firefox only show font and links, the CSS can not show normally. Then, I test it in '双核浏览器'(chrome core) and IE explorer, they also can not show normally.
在本地测试环境下上传带图文本后保存,再删除post,发现一同上传的图片没有被删除,不知道在哪里能找到或生成这些图片的索引呢?
对「邻接列表关系」理解上还有一些问题,希望老师解惑
models.py
中这三行代码我的理解如下:
# comment.replied_id 为一个指向评论(父级,也是自身)的外键
replied_id = db.Column(db.Integer, db.ForeignKey('comment.id'))
# comment.replies 为同一评论下的所有“回复”(子级,因为「多」所以变量名采用了复数形式)
replies = db.relationship('Comment', back_populates='replied', cascade='all, delete-orphan')
# comment.replied 为被回复的评论(父级,也是「一」这一侧的关系定义)
replied = db.relationship('Comment', back_populates='replies', remote_side=[id])
之所以有第三行(replied)是「一」这一侧必须要有关系定义,从而SQLAlchemy才能到对应的「多」侧去找外键字段(replied_id)。
comment.replied_id
对回复调用才有返回值,返回该回复对应的评论的 id。(返回父级 id)
comment.replies
对评论调用才有返回值,返回该评论对应的回复对象构成的列表。(返回子级对象集合)
comment.replied
对回复调用才有返回值,返回该回复对应的评论对象。(返回父级对象)
那么问题来了,fakes.py
中:
for i in range(salt):
comment = Comment(
...
# 第一句
replied=Comment.query.get(random.randint(1, Comment.query.count())),
# 第二句
post=Post.query.get(random.randint(1, Post.query.count()))
)
第一句理解为把 Comment(子级/回复)
对象的 replied
属性设置为某个随机的 Comment(父级/评论)
对象。
第二句为什么需要再为这个「回复」设置关联的「文章Post」呢?
「回复」跳过「评论」直接对应到「文章」的目的是什么,会不会出现逻辑错误?
在__init__.py中是这样导入蓝图的
from bluelog.blueprints.auth import auth_bp
一般情况下蓝图有没有默认访问路径,可以通过哪个参数来修改这个访问路径么
您好,
如果我想放弃CKEditor(因为它不支持数学公式)而想使用支持markdown语法的编辑器,该如何做呢?(比如修改哪些模型和模板之类的)
另外,目前看到的开源的后端渲染的就是Editormd,不知道您是否有其它推荐的?
多谢!
bluelog/bluelog/blueprints/admin.py
manage_category()
这个函数没定义参数呢?
作者,在ctrl c,v 您的源码后,图片上传还报400错误,可是csrf那个已经有了,麻烦您有空看看
当使用pipenv install --dev或pip install -r requirements.txt安装python依赖时,报错如下:
building 'psycopg2._psycopg' extension
creating build/temp.linux-x86_64-3.6
creating build/temp.linux-x86_64-3.6/psycopg
gcc -pthread -Wno-unused-result -Wsign-compare -DNDEBUG -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector-strong --param=ssp-buffer-size=4 -grecord-gcc-switches -m64 -mtune=generic -D_GNU_SOURCE -fPIC -fwrapv -fPIC -DPSYCOPG_VERSION=2.8.4 (dt dec pq3 ext) -DPG_VERSION_NUM=90224 -I/home/vagrant/bluelog/env/include -I/usr/include/python3.6m -I. -I/usr/include -I/usr/include/pgsql/server -c psycopg/psycopgmodule.c -o build/temp.linux-x86_64-3.6/psycopg/psycopgmodule.o -Wdeclaration-after-statement
In file included from psycopg/psycopgmodule.c:27:0:
./psycopg/psycopg.h:34:20: fatal error: Python.h: No such file or directory
#include <Python.h>
^
compilation terminated.
It appears you are missing some prerequisite to build the package from source.
You may install a binary package by installing 'psycopg2-binary' from PyPI.
If you want to install psycopg2 from source, please install the packages
required for the build and try again.
For further information please check the 'doc/src/install.rst' file (also at
<http://initd.org/psycopg/docs/install.html>).
error: command 'gcc' failed with exit status 1
把requirements.txt里的psycopg2==2.8.4改成psycopg2-binary就能正常安装了。
我设置了中文显示问题,怎么不生效,还有登录接口调节上面需要怎么改进
请问一下macros.html文件在哪里呢?没有找到
感谢大佬回复:)
部署到Linux时候,gunicorn -b 0.0.0.0:8000 wsgi:app
(env-37) [root@VM_0_6_centos bluelog]# gunicorn -b 0.0.0.0:8000 wsgi:app
[2019-12-12 19:44:37 +0800] [8202] [INFO] Starting gunicorn 20.0.4
[2019-12-12 19:44:37 +0800] [8202] [INFO] Listening at: http://0.0.0.0:8000 (8202)
[2019-12-12 19:44:37 +0800] [8202] [INFO] Using worker: sync
[2019-12-12 19:44:37 +0800] [8240] [INFO] Booting worker with pid: 8240
然后顺着ip访问就出现下面的错误
我感觉关键的错误是
jinja2.exceptions.TemplateNotFound: bootstrap/nav.html 这个日志出现很多次
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "/root/.pyenv/versions/3.7.0/envs/env-37/lib/python3.7/site-packages/gunicorn/workers/sync.py", line 134, in handle
self.handle_request(listener, req, client, addr)
File "/root/.pyenv/versions/3.7.0/envs/env-37/lib/python3.7/site-packages/gunicorn/workers/sync.py", line 190, in handle_request
util.reraise(*sys.exc_info())
File "/root/.pyenv/versions/3.7.0/envs/env-37/lib/python3.7/site-packages/gunicorn/util.py", line 625, in reraise
raise value
File "/root/.pyenv/versions/3.7.0/envs/env-37/lib/python3.7/site-packages/gunicorn/workers/sync.py", line 175, in handle_request
respiter = self.wsgi(environ, resp.start_response)
File "/root/.pyenv/versions/3.7.0/envs/env-37/lib/python3.7/site-packages/flask/app.py", line 2463, in __call__
return self.wsgi_app(environ, start_response)
File "/root/.pyenv/versions/3.7.0/envs/env-37/lib/python3.7/site-packages/flask/app.py", line 2449, in wsgi_app
response = self.handle_exception(e)
File "/root/.pyenv/versions/3.7.0/envs/env-37/lib/python3.7/site-packages/flask/app.py", line 1878, in handle_exception
server_error = handler(server_error)
File "/root/bluelog/bluelog/__init__.py", line 130, in internal_server_error
return render_template('errors/500.html'), 500
File "/root/.pyenv/versions/3.7.0/envs/env-37/lib/python3.7/site-packages/flask/templating.py", line 140, in render_template
ctx.app,
File "/root/.pyenv/versions/3.7.0/envs/env-37/lib/python3.7/site-packages/flask/templating.py", line 120, in _render
rv = template.render(context)
File "/root/.pyenv/versions/3.7.0/envs/env-37/lib/python3.7/site-packages/jinja2/asyncsupport.py", line 76, in render
return original_render(self, *args, **kwargs)
File "/root/.pyenv/versions/3.7.0/envs/env-37/lib/python3.7/site-packages/jinja2/environment.py", line 1008, in render
return self.environment.handle_exception(exc_info, True)
File "/root/.pyenv/versions/3.7.0/envs/env-37/lib/python3.7/site-packages/jinja2/environment.py", line 780, in handle_exception
reraise(exc_type, exc_value, tb)
File "/root/.pyenv/versions/3.7.0/envs/env-37/lib/python3.7/site-packages/jinja2/_compat.py", line 37, in reraise
raise value.with_traceback(tb)
File "/root/bluelog/bluelog/templates/errors/500.html", line 1, in top-level template code
{% extends 'base.html' %}
File "/root/.pyenv/versions/3.7.0/envs/env-37/lib/python3.7/site-packages/jinja2/environment.py", line 1005, in render
return concat(self.root_render_func(self.new_context(vars)))
File "/root/bluelog/bluelog/templates/errors/500.html", line 14, in root
{% include '_sidebar.html' %}
File "/root/bluelog/bluelog/templates/base.html", line 12, in root
type="text/css">
File "/root/.pyenv/versions/3.7.0/envs/env-37/lib/python3.7/site-packages/jinja2/environment.py", line 830, in get_template
return self._load_template(name, self.make_globals(globals))
File "/root/.pyenv/versions/3.7.0/envs/env-37/lib/python3.7/site-packages/jinja2/environment.py", line 804, in _load_template
template = self.loader.load(self, name, globals)
File "/root/.pyenv/versions/3.7.0/envs/env-37/lib/python3.7/site-packages/jinja2/loaders.py", line 113, in load
source, filename, uptodate = self.get_source(environment, name)
File "/root/.pyenv/versions/3.7.0/envs/env-37/lib/python3.7/site-packages/flask/templating.py", line 60, in get_source
return self._get_source_fast(environment, template)
File "/root/.pyenv/versions/3.7.0/envs/env-37/lib/python3.7/site-packages/flask/templating.py", line 89, in _get_source_fast
raise TemplateNotFound(template)
**jinja2.exceptions.TemplateNotFound: bootstrap/nav.html**
当 在/admin/post/manage URL中最后一页删除最后一个条目时会出现PAGE NOT FOUND。
修改如下 :
@admin_bp.route('/post/manage')
@login_required
def manage_post():
page = request.args.get('page', 1, type=int)
pages = Post.query.paginate(page=1, per_page=current_app.config['BLUELOG_MANAGE_POST_PER_PAGE']).pages
if page > pages:
page = pages
return redirect(url_for('.manage_post', page=page))
pagination = Post.query.order_by(Post.timestamp.desc()).paginate(page, per_page=current_app.config['BLUELOG_MANAGE_POST_PER_PAGE'])
posts = pagination.items
return render_template('admin/manage_post.html', page=page, pagination=pagination, posts=posts)
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.