Flask 中 url for 别人不理解自己的诗句是什么意思.甚至别人不理解自己的诗句其作用

Flask 的 Context 机制
Yet Another Seeker
Flask 的 Context 机制
2014 年 07 月 21 日
用过 Flask 做 Web 开发的同学应该不会不记得 App Context 和 Request Context 这两个名字——这两个 Context 算是 Flask 中比较特色的设计。
从一个 Flask App 读入配置并启动开始,就进入了 App Context,在其中我们可以访问配置文件、打开资源文件、通过路由规则反向构造 URL。 当一个请求进入开始被处理时,就进入了 Request Context,在其中我们可以访问请求携带的信息,比如 HTTP Method、表单域等。
所以,这两个 Context 也成了 Flask 框架复杂度比较集中的地方,对此有评价认为 Flask 的这种设计比 Django、Tornado 等框架的设计更为晦涩。 我不认同这种评价。对于一个 Web 应用来说,“应用” 和 “请求” 的两级上下文在理念上是现实存在的,如果理解了它们,那么使用 Flask 并不会晦涩;即使是使用 Django、Tornado,理解了它们的 Context 也非常有利于做比官网例子更多的事情(例如编写 Middleware)。
我因为开发 Flask 扩展,对这两个 Context 的具体实现也研究了一番,同时还解决了一些自己之前“知道结论不知道过程”的疑惑,所以撰写本文记录下来。
Thread Local 的概念
从面向对象设计的角度看,对象是保存“状态”的地方。Python 也是如此,一个对象的状态都被保存在对象携带的一个特殊字典中,可以通过 vars 函数拿到它。
Thread Local 则是一种特殊的对象,它的“状态”对线程隔离 —— 也就是说每个线程对一个 Thread Local 对象的修改都不会影响其他线程。这种对象的实现原理也非常简单,只要以线程的 ID 来保存多份状态字典即可,就像按照门牌号隔开的一格一格的信箱。
在 Python 中获得一个这样的 Thread Local 最简单的方法是 threading.local():
Python Shell&&& import threading
&&& storage = threading.local()
&&& storage.foo = 1
&&& print(storage.foo)
&&& class AnotherThread(threading.Thread):
def run(self):
storage.foo = 2
print(storage.foo)
# 这这个线程里已经修改了
&&& another = AnotherThread()
&&& another.start()
&&& print(storage.foo)
# 但是在主线程里并没有修改
这样来说,只要能构造出 Thread Local 对象,就能够让同一个对象在多个线程下做到状态隔离。这个“线程”不一定要是系统线程,也可以是用户代码中的其他调度单元,例如 Greenlet。
Werkzeug 实现的 Local Stack 和 Local Proxy
Werkzeug 没有直接使用 threading.local,而是自己实现了 werkzeug.local.Local 类。后者和前者有一些区别:
后者会在 Greenlet 可用的情况下优先使用 Greenlet 的 ID 而不是线程 ID 以支持 Gevent 或 Eventlet 的调度,前者只支持多线程调度;
后者实现了 Werkzeug 定义的协议方法 __release_local__,可以被 Werkzeug 自己的 release_pool 函数释放(析构)掉当前线程下的状态,前者没有这个能力。
除 Local 外,Werkzeug 还实现了两种数据结构:LocalStack 和 LocalProxy。
LocalStack 是用 Local 实现的栈结构,可以将对象推入、弹出,也可以快速拿到栈顶对象。当然,所有的修改都只在本线程可见。和 Local 一样,LocalStack 也同样实现了支持 release_pool 的接口。
LocalProxy 则是一个典型的代理模式实现,它在构造时接受一个 callable 的参数(比如一个函数),这个参数被调用后的返回值本身应该是一个 Thread Local 对象。对一个 LocalProxy 对象的所有操作,包括属性访问、方法调用(当然方法调用就是属性访问)甚至是二元操作
都会转发到那个 callable 参数返回的 Thread Local 对象上。
LocalProxy 的一个使用场景是 LocalStack 的 __call__ 方法。比如 my_local_stack 是一个 LocalStack 实例,那么 my_local_stack() 能返回一个 LocalProxy 对象,这个对象始终指向 my_local_stack 的栈顶元素。如果栈顶元素不存在,访问这个 LocalProxy 的时候会抛出 RuntimeError。
Flask 基于 Local Stack 的 Context
Flask 是一个基于 Werkzeug 实现的框架,所以 Flask 的 App Context 和 Request Context 也理所当然地基于 Werkzeug 的 Local Stack 实现。
在概念上,App Context 代表了“应用级别的上下文”,比如配置文件中的数据库连接信息;Request Context 代表了“请求级别的上下文”,比如当前访问的 URL。
这两种上下文对象的类定义在 flask.ctx 中,它们的用法是推入 flask.globals 中创建的 _app_ctx_stack 和 _request_ctx_stack 这两个单例 Local Stack 中。因为 Local Stack 的状态是线程隔离的,而 Web 应用中每个线程(或 Greenlet)同时只处理一个请求,所以 App Context 对象和 Request Context 对象也是请求间隔离的。
当 app = Flask(__name__) 构造出一个 Flask App 时,App Context 并不会被自动推入 Stack 中。所以此时 Local Stack 的栈顶是空的,current_app 也是 unbound 状态。
Python Shell&&& from flask import Flask
&&& from flask.globals import _app_ctx_stack, _request_ctx_stack
&&& app = Flask(__name__)
&&& _app_ctx_stack.top
&&& _request_ctx_stack.top
&&& _app_ctx_stack()
&LocalProxy unbound&
&&& from flask import current_app
&&& current_app
&LocalProxy unbound&
这也是一些 Flask 用户可能被坑的地方 —— 比如编写一个离线脚本时,如果直接在一个 Flask-SQLAlchemy 写成的 Model 上调用 User.query.get(user_id),就会遇到 RuntimeError。因为此时 App Context 还没被推入栈中,而 Flask-SQLAlchemy 需要数据库连接信息时就会去取 current_app.config,current_app 指向的却是 _app_ctx_stack 为空的栈顶。
解决的办法是运行脚本正文之前,先将 App 的 App Context 推入栈中,栈顶不为空后 current_app 这个 Local Proxy 对象就自然能将“取 config 属性” 的动作转发到当前 App 上了:
Python Shell&&& ctx = app.app_context()
&&& ctx.push()
&&& _app_ctx_stack.top
&flask.ctx.AppContext object at 0x102eac7d0&
&&& _app_ctx_stack.top is ctx
&&& current_app
&Flask '__main__'&
&&& ctx.pop()
&&& _app_ctx_stack.top
&&& current_app
&LocalProxy unbound&
那么为什么在应用运行时不需要手动 app_context().push() 呢?因为 Flask App 在作为 WSGI Application 运行时,会在每个请求进入的时候将请求上下文推入 _request_ctx_stack 中,而请求上下文一定是 App 上下文之中,所以推入部分的逻辑有这样一条:如果发现 _app_ctx_stack 为空,则隐式地推入一个 App 上下文。
所以,请求中是不需要手动推上下文入栈的,但是离线脚本需要手动推入 App Context。如果没有什么特殊困难,我更建议用 Flask-Script 来写离线任务。
到此为止,就出现两个疑问:
为什么 App Context 要独立出来:既然在 Web 应用运行时里,App Context 和 Request Context 都是 Thread Local 的,那么为什么还要独立二者?
为什么要放在“栈”里:在 Web 应用运行时中,一个线程同时只处理一个请求,那么 _req_ctx_stack 和 _app_ctx_stack 肯定都是只有一个栈顶元素的。那么为什么还要用“栈”这种结构?
我最初也被这两个疑问困惑过。后来看了一些资料,就明白了 Flask 为何要设计成这样。这两个做法给予我们 多个 Flask App 共存 和 非 Web Runtime 中灵活控制 Context 的可能性。
我们知道对一个 Flask App 调用 app.run() 之后,进程就进入阻塞模式并开始监听请求。此时是不可能再让另一个 Flask App 在主线程运行起来的。那么还有哪些场景需要多个 Flask App 共存呢?前面提到了,一个 Flask App 实例就是一个 WSGI Application,那么 WSGI Middleware 是允许使用组合模式的,比如:
wsgifrom werkzeug.wsgi import DispatcherMiddleware
from biubiu.app import create_app
from biubiu.admin.app import create_app as create_admin_app
application = DispatcherMiddleware(create_app(), {
'/admin': create_admin_app()
这个例子就利用 Werkzeug 内置的 Middleware 将两个 Flask App 组合成一个一个 WSGI Application。这种情况下两个 App 都同时在运行,只是根据 URL 的不同而将请求分发到不同的 App 上处理。
需要注意的是,这种用法和 Flask 的 Blueprint 是有区别的。Blueprint 虽然和这种用法很类似,但前者自己没有 App Context,只是同一个 Flask App 内部整理资源的一种方式,所以多个 Blueprint 可能共享了同一个 Flask App;后者面向的是所有 WSGI Application,而不仅仅是 Flask App,即使是把一个 Django App 和一个 Flask App 用这种用法整合起来也是可行的。
如果仅仅在 Web Runtime 中,多个 Flask App 同时工作倒不是问题。毕竟每个请求被处理的时候是身处不同的 Thread Local 中的。但是 Flask App 不一定仅仅在 Web Runtime 中被使用 —— 有两个典型的场景是在非 Web 环境需要访问上下文代码的,一个是离线脚本(前面提到过),另一个是测试。这两个场景即所谓的“Running code outside of a request”。
在非 Web 环境运行 Flask 关联的代码
离线脚本或者测试这类非 Web 环境和和 Web 环境不同 —— 前者一般只在主线程运行。
设想,一个离线脚本需要操作两个 Flask App 关联的上下文,应该怎么办呢?这时候栈结构的 App Context 优势就发挥出来了。
offline_script.pyfrom biubiu.app import create_app
from biubiu.admin.app import create_app as create_admin_app
app = create_app()
admin_app = create_admin_app()
def copy_data():
with app.app_context():
data = read_data()
# fake function for demo
with admin_app.app_context():
write_data(data)
# fake function for demo
mark_data_copied()
# fake function for demo
无论有多少个 App,只要主动去 Push 它的 App Context,Context Stack 中就会累积起来。这样,栈顶永远是当前操作的 App Context。当一个 App Context 结束的时候,相应的栈顶元素也随之出栈。如果在执行过程中抛出了异常,对应的 App Context 中注册的 teardown 函数被传入带有异常信息的参数。
这么一来就解释了两个疑问 —— 在这种单线程运行环境中,只有栈结构才能保存多个 Context 并在其中定位出哪个才是“当前”。而离线脚本只需要 App 关联的上下文,不需要构造出请求,所以 App Context 也应该和 Request Context 分离。
另一个手动推入 Context 的场景是测试。测试中我们可能会需要构造一个请求,并验证相关的状态是否符合预期。例如:
tests.pydef test_app():
app = create_app()
client = app.test_client()
resp = client.get('/')
assert 'Home' in resp.data
这里调用 client.get 时,Request Context 就被推入了。其特点和 App Context 非常类似,这里不再赘述。
为何建议使用 App Factory 模式
从官方文档来看,Flask 有 Singleton 和 App Factory 两种用法。前一种用法和其他的一些 Web 框架(如 Bottle、Sinatra)的门面广告很相似,因为代码精简,所以显得非常的“帅”:
app.pyfrom flask import Flask, render_template
from flask.ext.sqlalchemy import SQLAlchemy
from flask.ext.login import LoginManager
app = Flask(__name__)
db = SQLAlchemy(app)
login_manager = LoginManager()
@app.route('/')
def home():
return render_template('home.html')
但是这种“帅”是有代价的。一个最麻烦的问题就是编写测试的时候:
test_app.pyclass TestApp(unittest.TestCase):
DEBUG = False
TESTING = True
SQLALCHEMY_DATABASE_URI = None
def setUp(self):
self.app = create_app()
self.app.config.from_object(self)
self.client = self.app.test_client()
def test_app(self):
@self.app.route('/test/&int:id_&')
def my_view(id_):
return '#%d' % id_
resp = self.client.get('/test/42')
self.assertEqual(resp.data, '#42')
def test_home(self):
resp = self.client.get('/')
self.assertIn('Welcome', resp.data)
在上面的例子中,我为了测试给 App 新挂载了一个 View 函数。这是很常见的一个测试需求。但是如果 Flask App 实例是单例的,这种做法就会“弄脏”下一个测试的运行。更加麻烦的是,上述例子中如果 test_home 在 test_app 之前运行了,Flask 的开发者防御机制会认为这是一个“已经开始处理 Web 请求了,又挂载了视图”
的失误,从而抛出 RuntimeError。
所以除非是应用简单到不需要 Web 层测试,否则还是尽量使用 App Factory 模式比较好。况且配合 Blueprint 的情况下,App Factory 还能帮助我们良好地组织应用结构:
happytree/app.pyfrom flask import Flask
from werkzeug.utils import import_string
extensions = [
'happytree.ext:db',
'happytree.ext:login_manager',
blueprints = [
'happytree.views:bp',
def create_app():
app = Flask(__name__)
for ext_name in extensions:
ext = import_string(ext_name)
ext.init_app(app)
for bp_name in blueprints:
bp = import_string(bp_name)
app.register_blueprint(bp)
return app
这样就能彻底摆脱 app.py 和 View 模块“互相 Import”的纠结了。
好吧其实这一节和 Context 没啥关系……
这篇文章动笔开始写是 6 月 21 日,到今天发布出来,已经过去了整整一个月。而事实上我开始列提纲准备写这篇文章已经是三四月份的事情了。
_(:з」∠)_
Posted by Jiangge Zhang
2014 年 07 月 21 日
Please enable JavaScript to view the
Copyright & 2013 - Jiangge Zhang -
Powered by怎样才能彻底掌握flask?怎么个学习顺序比较合理? - 知乎1589被浏览136271分享邀请回答/Runscope/httpbin ,它就是Flask写的,你看着网站可以先简化一些不会的东西。直到你知道了怎么路由,怎么返回JSON格式的内容。5. 学习写模板。可以把你做的应用加上模板,实现更复杂的功能,当然这个时候页面很简陋。6. 学习在Flask应用中操作库。建议MongoDB和MySQL都要熟悉一下,这是时候也要学习些HTTP METHOD都有哪些以及在什么场景下该用哪个方法,趁机也了解下HTTP状态码。这个时候HTTP协议可以去学了,建议去读《图解HTTP》,看的轻松。7. 还是学一些前端的内容,前端包含HTML,CSS和Javscript,先从w3cshool开始,这个时候建议买几本对应的书看看。了解Ajax,知道如何让前后端通过Ajax通信。8. 学习前端框架,对于新手,我建议学习bootstrap和jquery这2个库,熟悉了它们前端部分就告一段落。9. 这个时候你已经有能力写一个相对有意思的网站了,你该找点创意做个大事。也就是看起来比较遥远的目标。比如写个小知乎,仿个开发者头条之类的。你得考虑session、管理后台、登录与注册、Oauth2、安全这些大型网站齐备的内容。10. 从9过度到这里还是要花不少时间的,走到这里,网站基本知识就差不多了,那么你要了解一个网站的架构了,比如缓存,文件系统,分布式,服务化,反向代理、CDN、DNS等等,推荐一本好书: ,一定要看看。11. 产品准备好了,你得研究下测试和持续集成,如何快速部署和回滚,如果及时发现问题,出现了性能问题怎么DEBUG和优化等知识。嗯,差不多未来1年你有的忙了。如果你认为用flask写了项目就是会web开发了,naive,我的观点是储备其他知识要先于深入理解flask,建议在9的初期再可以买本《Flask Web开发:基于Python的Web应用开发实战》看看,或者考虑买我的书 ^.^但是最好的学习Flask的办法就是去读它和它的依赖的源代码。但是最好的学习Flask的办法就是去读它和它的依赖的源代码。但是最好的学习Flask的办法就是去读它和它的依赖的源代码。重要的事情说三遍欢迎关注本人的微信公众号获取更多Python相关的内容(也可以直接搜索「Python之美」):
(二维码自动识别)31421 条评论分享收藏感谢收起5610 条评论分享收藏感谢收起查看更多回答1 个回答被折叠()12733人阅读
flask(11)
mysql(8)
运行环境:
Centos6.7 ; python 2.7.11;
写在前面之解决bug:
SQLALCHEMY_DATABASE_URI 思维定式写成SQLALCHEMY_DATABASE_URL,这个bug极其隐蔽;
将session[‘known’] 写成session[‘knowm’]因为是字符串命名写错,idle检查不出来,修复这个bug 也花费了很长时间,要细心!
——————————分割线之预备知识:
1,roles表中为id列添加主键属性,另一张表users为role_id列添加外键属性,这样主键就对应上外键,产生了一旦在roles表中修改完角色名(roles表中的name列的行值),所有通过role_id引用这个角色的用户都能立即看到更新的关系,故取名关系型数据库。
2,NoSQL数据库一般使用集合代替表,使用文档代替记录;使用NoSQL数据库的好处是,数据重复可以提升查询速度。
3,操作数据库有几种方法:
a,可以在数据库命令行写SQL语句,即底层操作数据库。
b,在python中可以用一些数据库驱动比如MySQL-python驱动来操作数据库,驱动对底层繁琐命令进行了封装。
c,在flask中使用SQLAlchemy数据库框架对数据库驱动进一步封装,进一步简化命令。因此SQLAlchemy不是数据库,而是对数据库进行操作的一种框架。
——————————我爱分割线之数据库管理
预备知识结束,那么对数据库进行管理有以下几个步骤:
1,配置数据库。
2,定义数据库模型,并对数据库中的表建立关系。
3 , 数据库的基本操作(命令行中操作):
创建表,插入行,修改行,删除行,查询行
4,视图函数中操作数据库
5,集成python shell
6,flask-migrate 实现数据库迁移。(到现在还没弄明白,数据库迁移怎么体现出来作用,以后弄懂再说)
——————————神奇的分割线之具体步骤
SQLAlchemy的安装
pip install flask-sqlalchemy
MySQL-python 驱动的安装:起初按照网上的yum方法
yum install MySQL-python
虽然显示了已经安装上,但是就是用import导入的时候显示找不到module,后来在虚拟环境下又用pip安装了才可以,具体大家可以Google安装方法。这里给大家提供个思路,yum安装识别不了,可以尝试pip。
1,配置数据库
flask 配置MySQL数据库与sqlite不同,首先你要先自己创建好数据库,有一个数据名称,才能用,而sqlite没有数据库运行SQLAlchemy时会自动给你创建数据库,所以配置数据库之前,你要用其他方法先建一个空的数据库,推荐大家用phpMyAdmin(PS:后来又发现了一个更好用的工具:安装简单操作界面是中文的,就是激活稍微麻烦了点,Navicat for MySQL,强烈安利初学者使用),博主是根据以下链接安装的,亲测靠谱:
这里我提前用phpMyAdmin建了一个名为text1的数据库,然后在hello.py文件中写代码:
from flask.ext.sqlalchemy import SQLAlchemy
app = Flask(__name__)
app.config['SECRET_KEY'] ='hard to guess'
app.config['SQLALCHEMY_DATABASE_URI']='mysql://root:密码@localhost:3306/text1'
app.config['SQLALCHEMY_COMMIT_ON_TEARDOWN']=True
db = SQLAlchemy(app)
2,定义模型,建立关系:hello.py 中
class Role(db.Model):
__tablename__ = 'roles'
id = db.Column(db.Integer,primary_key=True)
name = db.Column(db.String(64),unique=True)
user = db.relationship('User',backref='role',lazy='dynamic')
def __repr__(self):
return '&Role {}& '.format(self.name)
class User(db.Model):
__tablename__ = 'users'
id = db.Column(db.Integer,primary_key = True)
username = db.Column(db.String(64),unique=True,index=True)
role_id = db.Column(db.Integer,db.ForeignKey('roles.id'))
def __repr__(self):
return '&User {}&'.format(self.username)
3,以上步骤之后,可以进行数据库操作了(命令行)
if __name__ == '__main__':
db.create_all()
admin_role =Role(name = 'Admin')
mod_role = Role(name = 'Moderator')
user_role =Role(name = 'User')
user_john = User(username = 'john',role=admin_role)
user_susan = User(username = 'susan',role= user_role)
user_david = User(username = 'david',role = user_role)
db.session.add_all([admin_role,mod_role,user_role,user_john,user_susan,user_david])
运行hello.py 程序,此时打开phpMyAdmin 可以看到数据库text1 中已经有roles表和users表,此时可以尝试在python中敲命令行:
admin_role.name ='Adminstrator'
db.session.add(admin_role)
db.session.delete(mod_role)
db.session.commit()
User.query.filter_by(role=user_role).all() #注意过滤器的使用
4,视图函数中操作:
hello.py文件中:
@app.route('/',methods=['GET','POST'])
def index():
myform = NameForm()
if myform.validate_on_submit():
user = User.query.filter_by(username=myform.name.data).first()
if user is None:
user = User(username=myform.name.data)
db.session.add(user)
session['known'] = False
session['known'] = True
session['name']= myform.name.data
myform.name.data = ''
return redirect(url_for('index'))
return render_template('formindex.html',form=myform,name=session.get('name'),known=session.get('known',False))
在formindex.html 文件中添加:
not known %}
&please to meet you !&
&happy to see you again!&
5,集成Python shell ,如果之前的第三步是在命令行操作,你就会知道每次都要在shell中导入数据库实例和模型,相当麻烦,可以在hello.py中添加:
from flask.ext.script import Shell
def make_shell_context():
return dict(app=app,db=db,User=User,Role=Role)
manager.add_command('shell',Shell(make_context=make_shell_context))
这样在命令行中可以不用导入app之类的,就可以使用app实例。
6,最后是数据库迁移,有点想git中的版本库,但是具体作用表现没弄懂:
没办法,先抄一遍代码吧
安装:pip install flask-migrate
配置(在hello.py中):
from flask.ext.migrate import Migrate,MigrateCommand
migrate = Migrate(app,db)
manager.add_command('db',MigrateCommand)
创建迁移仓库:
(venv) $ python hello.py db init
自动创建迁移脚本:
(venv) $ python hello.py db migrate -m "initial migration"
(venv ) $ pyhton hello.py db upgrade
至此,flask与MySQL数据库的基本操作就告一段落了,see you ~
&&相关文章推荐
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
访问:79927次
积分:2302
积分:2302
排名:第17136名
原创:155篇
转载:23篇
评论:22条
(1)(6)(3)(15)(6)(7)(8)(25)(24)(2)(17)(4)(10)(19)(2)(6)(12)(12)
(window.slotbydup = window.slotbydup || []).push({
id: '4740887',
container: s,
size: '250,250',
display: 'inlay-fix'问题对人有帮助,内容完整,我也想知道答案
问题没有实际价值,缺少关键内容,没有改进余地
url_for(endpoint)方法中传递一个endpoint,我知道这个endpoint写上定义视图的方法名就可以了,比如有:
@app.route('/')
def index:
则可以写成url_for(index)
但我的项目中我是使用的MethodView来定义的视图,方法名就是get,如下:
class PostView(MethodView):
def get(self, oid=None):
下面添加了url规则:
xx.add_url_rule('/post/&oid&/', view_func=PostView.as_view('post'))
象这种情况,我如何在template中使用url_for来生成url呢?
答案对人有帮助,有参考价值
答案没帮助,是错误的答案,答非所问
url_for('post', _method='GET')
url_for('post', _method='other_method')
# 这里的 'post' 就是你调用 PostView.as_view() 时传进去的名字。
PS. url_for() 的 _method 参数是在 flask 0.9 时加上去的。在之前的版本中,url_for() 不支持 MethodView
这里有 Flask 作者对这个问题的解答(就是 Armin Ronacher 给出的那条回复)
又一个PS. 在 Google 里搜"MethodView url_for()",第一条结果就是上面给出的链接。
所以,碰到问题多用 Google 搜一搜,往往能更快把它解决哦。
答案对人有帮助,有参考价值
答案没帮助,是错误的答案,答非所问
问题解决了,问题的关键是不同的view映射不同的url以及有不同的默认参数值,不容易在template里获取,我找到办法:
获取当前endopoint:
{{ request.endpoint }}
获取显式或隐式默认路由参数值:
{% set args=request.view_args.copy() %}
{{ args['参数名'] }}
同步到新浪微博
分享到微博?
你好!看起来你挺喜欢这个内容,但是你还没有注册帐号。 当你创建了帐号,我们能准确地追踪你关注的问题,在有新答案或内容的时候收到网页和邮件通知。还能直接向作者咨询更多细节。如果上面的内容有帮助,记得点赞 (????)? 表示感谢。
明天提醒我
关闭理由:
删除理由:
忽略理由:
推广(招聘、广告、SEO 等)方面的内容
与已有问题重复(请编辑该提问指向已有相同问题)
答非所问,不符合答题要求
宜作评论而非答案
带有人身攻击、辱骂、仇恨等违反条款的内容
无法获得确切结果的问题
非开发直接相关的问题
非技术提问的讨论型问题
其他原因(请补充说明)
我要该,理由是:

我要回帖

更多关于 别人不理解自己的诗句 的文章

 

随机推荐