学python后端的时候,先学的Django,但是看到了他的数据库查询方式是这样的
id__gt=1 # id > 1?
这个方式我好久都没缓过来,强迫症好难受,(听说这种写法是matalab风,以后我不知道要不要学这个),你好歹用个dict,像mongodb那样,{'id':{'$gt':1}}
缓过来之后去接触Flask,感觉简单的多,可是又到了数据库查询那块,虽然比Django好看很多,但是总感觉哪里不对
>>> Movie.query.filter_by(title='Mahjong').first()
# 获取 title字段值为 Mahjong 的记录
>>> Movie.query.filter(Movie.title=='Mahjong').first()
# 等同于上面的查询,但使用不同的过滤方法
这种语法看着没问题,但我总感觉这是对宏的拙劣模拟,既然是filter,为什么不这样
>>> Movie.query.filter(lambda elmt:elmt.title == 'Mahjong').first()
还是硬着头皮学吧,希望语法来个更新
纠错1. 这种方法原来是关键字参数
>>> Movie.query.filter_by(title='Mahjong').first()
# 获取 title字段值为 Mahjong 的记录
但是这个肯定不是
>>> Movie.query.filter(Movie.title=='Mahjong').first()
# 等同于上面的查询,但使用不同的过滤方法
24RGB
2
感觉用 lambda
表达式的话就只能把所有数据都取出来再过滤了,用关键字参数应该可以将条件写入查询
看来我没有认识到python有关键字参数这个东西,总感觉是宏或其他元编程手段
为什么不手写SQL?
使用orm不就是为了方便简单吗,如果所有的语法都像这样
Movie.query.filter(lambda elmt:elmt.title == 'Mahjong').first()
Movie.query.filter({'id':{'$gt':1}}).first()
对比
Movie.query.filter(Movie.title=='Mahjong').first()
Movie.query.filter(Movie.title > 1).first()
哪个更简单方便,orm已经是封装了很多层了,只把最简单最直接pythonic的方法暴露给使用者
class Column(object):
def __init__(self, name):
self.name = name
def __eq__(self, other):
return {self.name: other}
def __gt__(self, other):
return {self.name: other}
class AA:
a = Column("a")
b = Column("b")
def test(*kwargs):
print(kwargs)
test(AA.a == 1)
test(AA.b > 10)
cireu
5
难道不是SQL就那几个残疾查询方法,lambda可以嵌入任意Python表达式的原因吗
看到这里其实我有个疑问,为什么这里的ORM执着于把方法和数据绑定在一个类里,
倘若我这样做跟ORM一样吗
(filter (fn [movie]
(= (:name movie) "Mahjong")) movies)
另外我认为用lambda表达式可以避免写这些怪异的语法,不用为and,or查询提供新语法
http://www.cherishlau.site/2018/03/29/flask-sqlalchemy-use-or-and/
cireu
8
lambda可以随便写(turing complete),SQL查询规则就那几条。不用这种DSL你怎么逐步把lambda翻译过去?
说到底还是SQL语言的设计问题,不是框架的问题。SQL设计真那么棒怎么还要ORM一套一套的搞?
能详细讲解一点吗。如果我用lambda会碰到SQL的哪些问题??
cireu
10
def query_fn(_movie):
# More, more and more side effect codes here!
pass
Movie.query(query_fn)
这种情况你怎么处理?Python里一个lambda是不透明的结构,你的代码本身在执行前没法判断这个lambda会执行什么内容。如果query函数本身就不合法呢(比如没有描述query,而是跑去执行副作用代码了)
xiyang
11
因为orm实质是转换为sql语句去查,就像 @24RGB 所说的,如果你用lambda,其实是把所有数据查出来,然后再用python的lambda来筛选所需要的数据,而把方法绑定到一个类里,是为了方便转化 Model.column > 12
这种形式,它会转换为一个字典或者元组,而不是正常情况下的a > b
布尔值,然后用这个值组合成SQL
关于and和or也是一样的,它会返回特殊格式的值,然后把这个值组合成SQL,而不是直接可以使用
1 个赞
看到这里,我想到一种办法,创建一个返回lambda的函数,并保证这个函数无副作用
不过好像在这种情况下作用不大
cireu
15
Just do it, submit PR or fork one for yourself
你只要用了 lambda,就注定翻译不进SQL吧,没看明白你的槽点😅
nykma
17
Laravel :
DB::table('users')
->where('name', '=', 'John')
->orWhere(function ($query) {
$query->where('votes', '>', 100)
->where('title', '<>', 'Admin');
})
->get();
Elixir Ecto:
def with_minimum(age, height_ft) do
from u in "users",
where: u.age > ^age and u.height > ^(height_ft * 3.28),
select: u.name
end
Lambda 怎么不行了🤔️没看懂
卧草,还有这种东西
Lambda 怎么不行了🤔️没看懂
我没看懂,为什么我觉得用lambda好点,因为那样在Python就可以不用写丑陋的DSL了。说起DSL还是lisp方言的写法优美一点