> For the complete documentation index, see [llms.txt](https://flask-yushu.gitbook.io/yushu/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://flask-yushu.gitbook.io/yushu/10.-yu-shu-ye-wu-chu-li/10.1-zui-jin-de-li-wu.md).

# 10.1 最近的礼物

我们的首页会显示最近的赠送书籍列表。这个列表有三个限制条件： 1.数量不超过30 2.按照时间倒序排列，最新的排在最前面 3.去重，同一本书籍的礼物不重复出现

## 1.首先编写复杂SQL对应的ORM代码

由于是最近的礼物，所以应该编写在models/gift.py中

```python
    @classmethod
    def recent(cls):
        # 链式调用 主体是Query ，遇到all(),first()就会终止生成一条sql
        # 建造者模式
        # select distinct * from gift group by isbn order by create_time limit 30
        recent_gifts = Gift.query\
            .filter_by(launched=False)\
            .group_by(Gift.isbn)\
            .order_by(Gift.create_time)\
            .limit(30)\
            .distinct().all()
        return recent_gifts
```

为什么要定义成类方法呢。

* 对象代表一个礼物，是具体的
* 类代表礼物这个事物，他是抽象的，不是具体的一个

## 2.业务的四种编写方案

1.编写在models的对应的gift.py里。 2.编写在视图函数里。（看你认为当前这段的业务有没有意义） 3.在models里建立新的RecentGift模块。 4.建立service层。（不推荐，Service层全都是静态方法，没有理解面向对象的意义）

## 3.编写视图函数

我们编写的recent函数获取到的gift列表里的每一个gift，都只有isbn编号。但是我们需要把图书的信息都返回回去。这就需要拿isbn编号去YushBook可去查询出书籍的详情信息然后再使用BookViewModel进行封装。

但是上面这段逻辑，不应该写在视图函数的for循环中，他是Gift的行为，应该封装到Gift的模型中去。

```python
    @property
    def book(self, isbn):
        yushu_book = YuShuBook()
        yushu_book.search_by_isbn()
        return yushu_book.first
```

不能在Gift模型中直接返回BookViewModel，因为我们的模型只负责处理原始数据，所有的处理ViewModel都应该放到视图函数里面进行。

web/main.py

```python
@web.route('/')
def index():
    recent_gifts = Gift.recent()
    books = [BookViewModel(gift.book) for gift in recent_gifts]
    return render_template('index.html', recent=books)
```

> 之所以能够在调用的地方用一个很简单的列表推导式就完成了这么复杂的逻辑，就是因为我们封装的非常良好。这里面涉及到了几个对象的相互调用-bookviewmodel，gift，yushubook；这才是在真正的写面向对象的代码，面向对象就是几个对象在相互调用，各自的逻辑是非常清晰的（单一职责模式）

### 良好的封装是优秀代码的基础


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://flask-yushu.gitbook.io/yushu/10.-yu-shu-ye-wu-chu-li/10.1-zui-jin-de-li-wu.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
