08. 查詢

08. 查詢

Pony 提供了一種非常方便的方法怖现,可以使用生成器表達(dá)式語法查詢數(shù)據(jù)庫屈嗤。
Pony允許程序員使用原生的Python語法來處理存儲在數(shù)據(jù)庫中的對象吊输,就像存儲在內(nèi)存中一樣。它使開發(fā)變得更加容易茫船。

在編寫查詢時扭屁,你可以使用Python生成器表達(dá)式或lambda匿名函數(shù)。

使用Python生成器表達(dá)式

Pony允許使用生成器表達(dá)式作為編寫數(shù)據(jù)庫查詢的一種非常自然的方式濒生。

Pony 提供了select()函數(shù)幔欧,它接受 Python 生成器礁蔗,將其翻譯成 SQL,并從數(shù)據(jù)庫中返回對象晒骇,翻譯的過程在這個StackOverflow question中描述了。

下面是一個查詢的例子:

query = select(c for c in Customer
               if sum(o.total_price for o in c.orders) > 1000)

或者徒坡,使用屬性提升 attribute lifting瘤缩。

query = select(c for c in Customer
               if sum(c.orders.total_price) > 1000)

在查詢中剥啤,你可以應(yīng)用filter()函數(shù)

query2 = query.filter(lambda person: person.age > 18)

也可以根據(jù)另一個查詢建立新的查詢:

query3 = select(customer.name for customer in query2
                if customer.country == 'Canada')

select()函數(shù)返回一個Query類的實例,然后可以調(diào)用Query對象方法來獲取結(jié)果刻诊,例如:

customer_name = query3.first()

從查詢中可以返回實體牺丙、屬性或元組的任意表達(dá)式。

select((c, sum(c.orders.total_price))
       for c in Customer if sum(c.orders.total_price) > 1000)

使用lambda函數(shù)

除了使用生成器是整,你也可以使用lambda函數(shù)來編寫查詢:

Customer.select(lambda c: sum(c.order.price) > 1000)

從將查詢轉(zhuǎn)換為SQL的角度來看浮入,如果你使用生成器或lambda羊异,沒有什么區(qū)別。

唯一的區(qū)別是易迹,使用lambda只能返回實體實例--沒有辦法返回具體的實體屬性列表或元組列表平道。

用于查詢數(shù)據(jù)庫的Pony ORM函數(shù)

詳情請參閱API參考資料中的查詢和函數(shù)部分一屋。

Pony查詢示例

為了演示Pony查詢,讓我們用Pony ORM發(fā)行版中的例子闸衫。
你可以在交互模式下自己嘗試這些查詢诽嘉,并查看生成的SQL弟翘。

為此稀余,我們可以這樣導(dǎo)入示例模塊:

>>> from pony.orm.examples.estore import *

本模塊提供了一個簡化的電子商務(wù)網(wǎng)店的數(shù)據(jù)模型酥筝,以下是數(shù)據(jù)模型的ER圖

111.png

下面是實體的定義:

from decimal import Decimal
from datetime import datetime

from pony.converting import str2datetime
from pony.orm import *

db = Database()

class Customer(db.Entity):
    email = Required(str, unique=True)
    password = Required(str)
    name = Required(str)
    country = Required(str)
    address = Required(str)
    cart_items = Set('CartItem')
    orders = Set('Order')

class Product(db.Entity):
    id = PrimaryKey(int, auto=True)
    name = Required(str)
    categories = Set('Category')
    description = Optional(str)
    picture = Optional(buffer)
    price = Required(Decimal)
    quantity = Required(int)
    cart_items = Set('CartItem')
    order_items = Set('OrderItem')

class CartItem(db.Entity):
    quantity = Required(int)
    customer = Required(Customer)
    product = Required(Product)

class OrderItem(db.Entity):
    quantity = Required(int)
    price = Required(Decimal)
    order = Required('Order')
    product = Required(Product)
    PrimaryKey(order, product)

class Order(db.Entity):
    id = PrimaryKey(int, auto=True)
    state = Required(str)
    date_created = Required(datetime)
    date_shipped = Optional(datetime)
    date_delivered = Optional(datetime)
    total_price = Required(Decimal)
    customer = Required(Customer)
    items = Set(OrderItem)

class Category(db.Entity):
    name = Required(str, unique=True)
    products = Set(Product)

set_sql_debug(True)
db.bind('sqlite', 'estore.sqlite', create_db=True)
db.generate_mapping(create_tables=True)

當(dāng)你導(dǎo)入這個例子時,它將在文件'estore.sqlite'中創(chuàng)建SQLite數(shù)據(jù)庫茁影,并在其中填充一些測試數(shù)據(jù)募闲,下面你可以看到一些查詢的例子:

# 所有美國客戶
Customer.select(lambda c: c.country == 'USA')

# 每個國家的客戶數(shù)量
select((c.country, count(c)) for c in Customer)

# 最大產(chǎn)品價格
max(p.price for p in Product)

# 最大固態(tài)硬盤價格
max(p.price for p in Product)
            for cat in p. categories if cat.name =='Solid State Drives')

#最貴的三款產(chǎn)品
Product.select().order_by(desc(Product.price))[:3]

# 缺貨產(chǎn)品
Product.select(lambda p: p.quantity ==0)

# 最受歡迎的產(chǎn)品
Product.select().order_by(lambda p: desc(sum(p.order_items.quantity))).first()

# 從未訂購過的產(chǎn)品
Product.select(lambda p: not p.order_items)

# 下過幾次訂單的客戶數(shù)
Customer.select(lambda c: count(c.order) > 1)

# 最有價值的三個客戶
Customer.select().order_by(lambda c: desc(sum(c.orders.total_price)))[:3]

# 訂單已發(fā)貨的客戶
Customer.select(lambda c: SHIPPED in c.order.state)

# 沒有訂單的客戶數(shù)
Customer.select(lambda c: not c.order)

# 同樣的查詢,用LEFT JOIN代替NOT EXISTS靴患。
left_join(c for c in Customer for o in c.order if o is None)

# 訂購不同藥片的客戶數(shù)
選擇(c for c in Customer
         for p in c.order.projects.product.
         if 'Tablets' in p.category.name and count(p) > 1)

你在pony.orm.examples.estore可以找到更多的查詢示例鸳君。

查詢對象方法

詳情請參閱API參考資料中的查詢結(jié)果部分患蹂。

在查詢中使用日期和時間

可以在查詢中用datetimetimedelta進(jìn)行算術(shù)運(yùn)算。

如果表達(dá)式可以用Python計算囱挑,Pony會把計算結(jié)果作為參數(shù)傳遞到查詢中:

select(o for o in Order if o.date_created >= datetime.now() - timedelta(days=3))[:]
SELECT "o". "id", "o". "state", "o". "date_created", "o". "date_shipped",
       "o". "date_delivered", "o". "total_price", "o". "customer".
FROM "訂單" "o"
WHERE "o". "date_created">= ?

如果需要用該屬性進(jìn)行操作沼溜,我們無法事先計算系草,這就是為什么這樣的表達(dá)式會被翻譯成SQL的原因:

select(o for o in Order if o.date_created + timedelta(days=3) >= datetime.now())[:]
SELECT "o"."id", "o"."state", "o"."date_created", "o"."date_shipped",
       "o"."date_delivered", "o"."total_price", "o"."customer"
FROM "Order" "o"
WHERE datetime("o"."date_created", '+3 days') >= ?

Pony生成的SQL會因數(shù)據(jù)庫的不同而不同,上面是SQLite的例子棠隐,下面是同樣的查詢檐嚣,翻譯成PostgreSQL:

SELECT "o". "id", "o". "state", "o". "date_created", "o". "date_shipped",
       "o". "date_delivered", "o". "total_price", "o". "customer".
FROM "order" "o"
WHERE ( "o". "date_created" + INTERVAL '72:0:0:0' DAY TO SECOND) >= %(p1)s

如果你需要使用SQL函數(shù),可以使用raw_sql()函數(shù)來包含這個SQL片段:

select(m for m in DBVoteMessage if m.date >= raw_sql("NOW() - '1 minute'::INTERVAL"))

使用Pony可以使用日期時間屬性嗡贺,如月诫睬、小時等,根據(jù)數(shù)據(jù)庫的不同续徽,會被翻譯成不同的SQL亲澡,提取這個屬性的值,在這個例子中客情,我們得到的是月份屬性:

select(o for o in Order if o.date_created.month ==12)

下面是SQLite的翻譯結(jié)果:

SELECT "o"."id", "o"."state", "o"."date_created", "o"."date_shipped",
       "o"."date_delivered", "o"."total_price", "o"."customer"
FROM "Order" "o"
WHERE cast(substr("o"."date_created", 6, 2) as integer) = 12

而對于PostgreSQL則是:

SELECT "o"."id", "o"."state", "o"."date_created", "o"."date_shipped",
       "o"."date_delivered", "o"."total_price", "o"."customer"
FROM "order" "o"
WHERE EXTRACT(MONTH FROM "o"."date_created") = 12

自動唯一

Pony試圖通過在必要的地方自動添加DISTINCT SQL關(guān)鍵字來避免查詢結(jié)果中的重復(fù)膀斋,因為重復(fù)且有用的查詢結(jié)果很難遇到痹雅。

當(dāng)有人想要檢索具有特定條件的對象時,通常不會期望同一個對象會被多次返回惰匙。

同時铃将,避免重復(fù)的查詢結(jié)果也使查詢結(jié)果更具有可預(yù)測性:你不需要從查詢結(jié)果中篩選出重復(fù)的對象劲阎。

Pony只有在可能存在重復(fù)的情況下才會添加disctinct關(guān)鍵字,讓我們考慮幾個例子:

1. 檢索有條件的對象

Person.select(lambda p: p.age > 20 and p.name == 'John')

在這個例子中龄毡,查詢不返回重復(fù)锡垄,因為結(jié)果中包含了Person的主鍵列,因為這里不可能出現(xiàn)重復(fù)路操,所以沒有必要添加DISTINCT關(guān)鍵字,Pony也不添加:

SELECT "p"."id", "p"."name", "p"."age"
FROM "Person" "p"
WHERE "p"."age" > 20
  AND "p"."name" = 'John'

2. 檢索對象的屬性

select(p.name for p in Person)

這個查詢結(jié)果返回的不是對象搞坝,而是它的屬性魁袜,這個查詢結(jié)果可能包含重復(fù)峰弹,所以Pony會在這個查詢中加入DISTINCT。

SELECT DISTINCT "p". "name"
FROM "Person" "p"

這種查詢的結(jié)果通常用于下拉列表垫桂,在這里不會出現(xiàn)重復(fù)的情況粟按,當(dāng)你想在這里出現(xiàn)重復(fù)的情況時霹粥,想出一個真正的用例并不容易后控。

如果你需要統(tǒng)計同名的人,最好使用聚合查詢:

select((p.name, count(p)) for p in Person)

但如果絕對需要獲取所有的人名捌朴,包括重復(fù)的人名张抄,可以使用Query.without_distinct()方法。

select(p.name for p in Person).without_distinct()

3. 使用聯(lián)接來檢索對象

select(p for p in Person for c in p.cars if c.make in ("Toyota", "Honda"))

這個查詢可能包含重復(fù)的內(nèi)容左驾,所以Pony使用DISTINCT來消除它們诡右。

SELECT DISTINCT "p"."id", "p"."name", "p"."age"
FROM "Person" "p", "Car" "c"
WHERE "c"."make" IN ('Toyota', 'Honda')
  AND "p"."id" = "c"."owner"

如果不使用DISTINCT轻猖,就有可能出現(xiàn)重復(fù),因為查詢使用了兩個表(Person和Car)桅锄,但SELECT部分只使用了一個表。

上面的查詢只返回Person(而不是他們的車)翠肘,因此一般情況下辫秧,在結(jié)果中多次得到同一個人是不可取的盟戏。

我們認(rèn)為,如果沒有重復(fù)邮旷,結(jié)果看起來會更直觀蝇摸。

但如果因為某些原因不需要排除重復(fù)貌夕,你總是可以在查詢中添加without_distinct()

select(p for p in Person for c in p.cars
         if c.make in ("Toyota", "Honda")).without_distinct()

如果查詢結(jié)果中包含每個人擁有的汽車,用戶可能希望看到Person對象重復(fù)险毁,在這種情況下们童,PONY查詢就不同了。

select((p, c) for p in Person for c in p.cars if c.make in ("Toyota", "Honda"))

并且在這種情況下跷跪,Pony不會在SQL查詢中添加DISTINCT關(guān)鍵字完沪。

總結(jié)一下:

  1. "所有查詢默認(rèn)情況下不返回重復(fù)查詢 "這個原則很容易理解覆积,也不會導(dǎo)致意外。
  2. 在大多數(shù)情況下尉姨,這樣的行為是大多數(shù)用戶想要的吗冤。
  3. Pony在查詢不應(yīng)該有重復(fù)的情況下,不會添加DISTINCT覆致。
  4. 方法without_distinct()可以用來強(qiáng)制Pony不消除重復(fù)的查詢煌妈。

可以在查詢中使用的函數(shù)

下面是可以在生成器查詢中使用的函數(shù)列表:

  • avg()
  • abs()
  • exists()
  • len()
  • max()
  • min()
  • count()
  • concat()
  • group_concat()
  • random()
  • raw_sql()
  • select()
  • sum()
  • getattr()

例如:

select(avg(c.orders.total_price) for c in Customer)

SELECT AVG("order-1"."total_price")
FROM "Customer" "c"
  LEFT JOIN "Order" "order-1"
    ON "c"."id" = "order-1"."customer"

select(o for o in Order if o.customer in
       select(c for c in Customer if c.name.startswith('A')))[:]

SELECT "o"."id", "o"."state", "o"."date_created", "o"."date_shipped",
       "o"."date_delivered", "o"."total_price", "o"."customer"
FROM "Order" "o"
WHERE "o"."customer" IN (
    SELECT "c"."id"
    FROM "Customer" "c"
    WHERE "c"."name" LIKE 'A%'
    )

使用getattr()

getattr() 是一個內(nèi)置的Python函數(shù)璧诵,可以用來獲取屬性值:

例如:

attr_name = 'name'
param_value = 'John'
select(c for c in Customer if getattr(c, attr_name) === param_value)

使用原始SQL

Pony允許在查詢中使用原始SQL,關(guān)于如何使用原始SQL有兩種選擇族操。

  • 使用raw_sql()函數(shù)來寫一個生成器或lambda查詢的一部分比被。
  • 使用Entity.select_by_sql()Entity.get_by_sql()方法編寫一個完整的SQL查詢姐赡。

使用raw_sql()函數(shù)

讓我們來探討一下使用raw_sql()函數(shù)的例子柠掂,下面是方案及初始化數(shù)據(jù):

from datetime import date
from pony.orm import *

db = Database('sqlite', ':memory:')

class Person(db.Entity):
    id = PrimaryKey(int)
    name = Required(str)
    age = Required(int)
    dob = Required(date)

db.generate_mapping(create_tables=True)

with db_session:
    Person(id=1, name='John', age=30, dob=date(1986, 1, 1))
    Person(id=2, name='Mike', age=32, dob=date(1984, 5, 20))
    Person(id=3, name='Mary', age=20, dob=date(1996, 2, 15))

raw_sql()結(jié)果可以作為邏輯表達(dá)式處理:

select(p for p in Person if raw_sql('abs("p"."age") > 25'))

raw_sql()結(jié)果可以用來進(jìn)行比較:

q = Person.select(lambda x: raw_sql('abs("x"."age")') > 25)
print(q.get_sql())

SELECT "x"."id", "x"."name", "x"."age", "x"."dob"
FROM "Person" "x"
WHERE abs("x"."age") > 25

另外涯贞,在上面的例子中,我們在一個lambda查詢中使用raw_sql()州疾,并打印出結(jié)果的SQL皇拣。正如你所看到的,raw_sql()部分變成了整個查詢的一部分颗胡。

raw_sql()可以接受$parameters:

x = 25
select(p for p in Person if raw_sql('abs("p"."age") > $x'))

你可以動態(tài)地改變raw_sql()函數(shù)的內(nèi)容毒姨,并且仍然可以使用里面的參數(shù):

x = 1
s = 'p.id > $x'
select(p for p in Person if raw_sql(s)

另一種使用動態(tài)原始SQL內(nèi)容的方式:

x = 1
cond = raw_sql('p.id > $x')
select(p for p in Person if cond)

你可以在原始SQL查詢中使用各種類型:

x = date(1990, 1, 1)
select(p for p in Person if raw_sql('p.dob < $x'))

原始SQL部分里面的參數(shù)可以組合:

x = 10
y = 15
select(p for p in Person if raw_sql('p.age > $(x + y)'))

你甚至可以在里面調(diào)用Python函數(shù):

select(p for p in Person if raw_sql('p.dob < $date.today()'))

raw_sql()函數(shù)不僅可以用于條件部分弧呐,還可以用于返回查詢結(jié)果的部分。

names = select(raw_sql('UPPER(p.name)') for p in Person)[:]
print(names)

['John', 'Mike', 'Mary']

但是當(dāng)你使用raw_sql()函數(shù)返回數(shù)據(jù)時腥沽,你可能需要指定結(jié)果的類型鸠蚪,因為Pony不知道結(jié)果的類型是什么:

dates = select(raw_sql('(p.dob)')) for p in Person)[:]
print(dates)

['1985-01-01', '1983-05-20', '1995-02-15']

如果你想以日期列表的形式得到結(jié)果邓嘹,你需要指定結(jié)果類型:

dates = select(raw_sql('(p.dob)', result_type=date) for p in Person)[:]
print(dates)

[datetime.date(1986, 1, 1), datetime.date(1984, 5, 20), datetime.date(1996, 2, 15)]

Query.filter()中也可以使用raw_sql()函數(shù):

x = 25
select(p for p in Person).filter(lambda p: p.age > raw_sql('$x'))

它可以在Query.filter()中使用,不需要lambda矿筝,在這種情況下棚贾,你必須使用實體名稱的首字母小寫作為別名:

x = 25
Person.select().filter(raw_sql('p.age > $x'))

你可以在一個查詢中使用多個raw_sql()表達(dá)式:

x = '123'
y = 'John'
Person.select(lambda p: raw_sql("UPPER(p.name) || $x")
                        ==raw_sql("UPPER($y || '123')")

同樣的參數(shù)名稱可以用不同的類型和值多次使用妙痹。

x = 10
y = 31
q = select(p for p in Person if p.age > x and p.age < raw_sql('$y'))
x = date(1980, 1, 1)
y = 'j'
q = q.filter(lambda p: p.dob > x and p.name.startwith(raw_sql('UPPER($y)')))
persons = q[:]

你可以在Query.order_by()部分使用raw_sql()

x = 9
Person.select().order_by(lambda p: raw_sql('SUBSTR(p.dob, $x)'))

如果你在之前的過濾器中使用了相同的別名琳轿,則可以不使用lambda耿芹,在這種情況下吧秕,我們使用默認(rèn)的別名--實體名稱的第一個字母。

x = 9
Person.select().order_by(raw_sql('SUBSTR(p.dob, $x)'))

使用select_by_sql()和get_by_sql()方法

雖然Pony可以將幾乎所有用Python編寫的條件翻譯成SQL颠毙,但有時需要使用原始SQL砂碉,例如绽淘,為了調(diào)用存儲過程或使用特定數(shù)據(jù)庫系統(tǒng)的方言功能,需要使用原始SQL壮池。

在這種情況下,Pony允許用戶以原始SQL的形式寫一個查詢厅克,方法是把它放在函數(shù)Entity.select_by_sql()或Entity.get_by_sql()的內(nèi)部橙依,作為一個字符串。

Product.select_by_sql("SELECT * FROM Products")

Entity.select()方法不同女责,Entity.select_by_sql()方法不返回查詢對象抵知,而是返回一個實體實例列表软族。

參數(shù)使用下面的語法傳遞,"name_variable "或"(Python中的表達(dá)式)"掖疮,例如:

x = 1000
y = 500
Product.select_by_sql("SELECT * FROM Product WHERE price > $x OR price = $(y * 2)")

當(dāng)Pony在原始SQL查詢中遇到一個參數(shù)時浊闪,它會從當(dāng)前幀(來自globals和locals)或從可以作為參數(shù)傳遞的字典中獲取變量值吐葵。

Product.select_by_sql("SELECT * FROM Product WHERE price > $x OR price = $(y * 2)",
                       globals={'x': 100}, locals={'y': 200})

變量和更復(fù)雜的表達(dá)式在$符號后指定桥氏,將自動計算并作為參數(shù)傳輸?shù)讲樵冎凶种В@使得SQL注入成為不可能。

Pony會自動將查詢字符串中的$x用"?"揖庄、"%S "或其他參數(shù)樣式代替欠雌,在你的數(shù)據(jù)庫中使用富俄。

如果你需要在查詢中使用符號(例如而咆,在系統(tǒng)表的名稱中)暴备,你必須連續(xù)寫兩個符號:$$们豌。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末望迎,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子混弥,更是在濱河造成了極大的恐慌对省,老刑警劉巖蒿涎,帶你破解...
    沈念sama閱讀 218,682評論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異仓手,居然都是意外死亡嗽冒,警方通過查閱死者的電腦和手機(jī)补履,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,277評論 3 395
  • 文/潘曉璐 我一進(jìn)店門箫锤,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人阳准,你說我怎么就攤上這事馏臭。” “怎么了绕沈?”我有些...
    開封第一講書人閱讀 165,083評論 0 355
  • 文/不壞的土叔 我叫張陵七冲,是天一觀的道長澜躺。 經(jīng)常有香客問我,道長耘戚,這世上最難降的妖魔是什么操漠? 我笑而不...
    開封第一講書人閱讀 58,763評論 1 295
  • 正文 為了忘掉前任浊伙,我火速辦了婚禮,結(jié)果婚禮上吻贿,老公的妹妹穿的比我還像新娘哑子。我一直安慰自己,他們只是感情好帐要,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,785評論 6 392
  • 文/花漫 我一把揭開白布榨惠。 她就那樣靜靜地躺著其爵,像睡著了一般摩渺。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上剂邮,一...
    開封第一講書人閱讀 51,624評論 1 305
  • 那天摇幻,我揣著相機(jī)與錄音,去河邊找鬼。 笑死绰姻,一個胖子當(dāng)著我的面吹牛枉侧,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播狂芋,決...
    沈念sama閱讀 40,358評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼榨馁,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了帜矾?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,261評論 0 276
  • 序言:老撾萬榮一對情侶失蹤屡萤,失蹤者是張志新(化名)和其女友劉穎珍剑,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體死陆,經(jīng)...
    沈念sama閱讀 45,722評論 1 315
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡招拙,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,900評論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了措译。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片别凤。...
    茶點(diǎn)故事閱讀 40,030評論 1 350
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖领虹,靈堂內(nèi)的尸體忽然破棺而出闻妓,到底是詐尸還是另有隱情,我是刑警寧澤掠械,帶...
    沈念sama閱讀 35,737評論 5 346
  • 正文 年R本政府宣布由缆,位于F島的核電站,受9級特大地震影響猾蒂,放射性物質(zhì)發(fā)生泄漏均唉。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,360評論 3 330
  • 文/蒙蒙 一肚菠、第九天 我趴在偏房一處隱蔽的房頂上張望舔箭。 院中可真熱鬧,春花似錦蚊逢、人聲如沸层扶。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,941評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽镜会。三九已至,卻和暖如春终抽,著一層夾襖步出監(jiān)牢的瞬間戳表,已是汗流浹背桶至。 一陣腳步聲響...
    開封第一講書人閱讀 33,057評論 1 270
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留匾旭,地道東北人镣屹。 一個月前我還...
    沈念sama閱讀 48,237評論 3 371
  • 正文 我出身青樓,卻偏偏與公主長得像价涝,于是被迫代替她去往敵國和親女蜈。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,976評論 2 355