Python学习笔记--Flask小项目之仿豆瓣电影界面

知识点

  1. 如何通过评分计算出星级
  2. 使用宏封装每一个影片标签,减少代码
  3. 使用继承的方式编写模板
  4. 也是用宏封装整个电影标签和电视剧标签,通过url_for实现点击更多跳转到指定的页面

效果图

在这里插入图片描述

  • 由于只是模仿,因此影片详情,还有一些页面滑动的样式就先忽略了

前期准备

  1. CSS文件
  2. 星星的图片3张(满星,半颗星,灰色星星)
  3. 影片的封面(也可以用豆瓣图片的url地址)

创建项目

  1. 创建视图文件app.py
  2. 创建静态资源文件目录"/static/css"、 “/static/img”,将CSS文件放入css文件夹,在图片放入img文件夹
  3. 创建模板目录"/templates"
    在这里插入图片描述

创建视图

编辑app.py

from flask import Flask
from flask import render_template
from flask import request


app = Flask(__name__)
app.config['TEMPLATES_AUTO_RELOAD'] = True


# 电影
movies = [
    {
        'id': '11211',
        'thumbnail': 'https://img3.doubanio.com/view/movie_poster_cover/lpst/public/p2499792043.webp',
        'title': u'王牌特工2:黄金圈',
        'rating': u'7.3',
        'comment_count': 12000,
        'authors': u'科林·费尔斯 / 塔伦·埃格顿 / 朱丽安·摩尔'
    },
    {
        'id': '34532',
        'title': u'羞羞的铁拳',
        'thumbnail': u'https://img1.doubanio.com/view/movie_poster_cover/lpst/public/p2499793218.webp',
        'rating': u'7.6',
        'comment_count': 39450,
        'authors': u'艾伦/马丽/沈腾'
    },
    {
        'id': '394558',
        'title': u'情圣',
        'thumbnail': u'https://img3.doubanio.com/view/movie_poster_cover/mpst/public/p2409022364.jpg',
        'rating': u'6.3',
        'comment_count': 38409,
        'authors': u'肖央 / 闫妮 / 小沈阳'
    },
    {
        'id': '9384089',
        'title': u'全球风暴',
        'thumbnail': u'https://img3.doubanio.com/view/movie_poster_cover/lpst/public/p2501863104.webp',
        'rating': u'7.4',
        'comment_count': 4555,
        'authors': u'杰拉德·巴特勒/吉姆·斯特'
    },
    {
        'id': '26921827',
        'title': u'大卫贝肯之倒霉特工熊',
        'thumbnail': u'https://img3.doubanio.com/view/movie_poster_cover/mpst/public/p2408893200.jpg',
        'rating': u'4.3',
        'comment_count': 682,
        'authors': u'汤水雨 / 徐佳琪 / 杨默'
    },
    {
        'id': '26287884',
        'title': u'追龙',
        'thumbnail': u'https://img3.doubanio.com/view/movie_poster_cover/lpst/public/p2499052494.webp',
        'rating': u'7.5',
        'comment_count': 33060,
        'authors': u'查理兹·塞隆 / 阿特·帕金森 / 拉尔夫·费因斯'
    }
]

# 电视剧
tvs = [
    {
        'id': '235434',
        'title': u'鬼吹灯之精绝古城',
        'thumbnail': u'https://img3.doubanio.com/view/movie_poster_cover/lpst/public/p2404604903.jpg',
        'rating': u'8.4',
        'comment_count': 49328,
        'authors': u'靳东 / 陈乔恩 / 赵达 / 付枚 / 金泽灏 /'
    },
    {
        'id': '9498327',
        'title': u'孤芳不自赏',
        'thumbnail': u'https://img1.doubanio.com/view/movie_poster_cover/lpst/public/p2407425119.jpg',
        'rating': u'3.7',
        'comment_count': 8493,
        'authors': u'钟汉良 / 杨颖 / 甘婷婷 / 孙艺洲 / 亓航 /'
    },
    {
        'id': '26685451',
        'title': u'全球风暴',
        'thumbnail': u'https://img3.doubanio.com/view/movie_poster_cover/lpst/public/p2501769525.webp',
        'rating': u'8.2',
        'comment_count': 345,
        'authors': u' 卢克·崔德威 / 琼安·弗洛加特 / 露塔·格德米纳斯 / 安东尼·海德 / 卡罗琳·古多尔 /'
    },
    {
        'id': '235434',
        'title': u'其他人',
        'thumbnail': u'https://img3.doubanio.com/view/movie_poster_cover/lpst/public/p2371503632.jpg',
        'rating': u'7.6',
        'comment_count': 25532,
        'authors': u'杰西·普莱蒙 / 莫莉·香侬 / 布莱德利·惠特福德 / Maude Apatow / 麦迪逊·贝蒂 /'
    },
    {
        'id': '48373095',
        'title': u'全员单恋',
        'thumbnail': u'https://img1.doubanio.com/view/movie_poster_cover/lpst/public/p2367986708.jpg',
        'rating': u'6.4',
        'comment_count': 2483,
        'authors': u'伊藤沙莉 / 中川大志 / 上原实矩 / 森绘梨佳 / 樱田通 /'
    },
    {
        'id': '292843',
        'title': u'废纸板拳击手',
        'thumbnail': u'https://img1.doubanio.com/view/movie_poster_cover/lpst/public/p2380194237.jpg',
        'rating': u'8.2',
        'comment_count': 23456,
        'authors': u'托马斯·哈登·丘奇 / 泰伦斯·霍华德 / 波伊德·霍布鲁克 / 瑞斯·维克菲尔德 / 马尔洛·托马斯 /'
    }
]


@app.route("/")
def index():
	“”“首页“””
    context = {
        "movies": movies,
        "tvs": tvs
    }
    return render_template("index.html", **context)


@app.route("/list/")
def move_list():
	“”“更多”“”
    category = request.args.get("category")
    items = None
    if category == int(1):
        items = movies
    else:
        items = tvs
    return render_template("list.html", items=items)



if __name__ == '__main__':
    app.run()
  • 由于没有数据库,因此定义movies和tvs这两个字典的数据,代替从数据库读取数据的操作
  • index函数是首页的路由
  • move_list是在首页右边的更多按钮,点击更多之后,路由会传入1或者2(在模板中实现);当判断为1时,就是从电影点的更多,否则就是从电视剧点的更多,根据这个判断要传入的是电影的清单还是电视剧的清单。

创建模板

1. 创建宏

在templates目录下创建macro.html模板文件。

第一个宏(itemGroup)

写入第一个宏(itemGroup),它主要负责封装影片封面、名字、评分、星级,因此给它3个参数:

  • thumbnail: 封面
  • title: 名字
  • ratings: 评分(星级可以通过评分计算出来,所以不需要)
{% macro itemGroup(thumbnail, title, ratings) %}
    <div class="item-group">
                <img src="{{ thumbnail }}" alt="" class="thumbnail">
                <p class="item-title">{{ title }}</p>
                <p class="item-rating">
                    {# 星级的计算方式 #}
                    {# ratings先取整 #}
                    {# ratings/2 然后取整就可以得到满星的数量 #}
                    {# ratings%2 为1时就是有半颗星,不为1就是没有半颗星 #}
                    {# 最后 5-满星-半星=灰色星星 #}
                    {% set rating = ratings|int %}
                    {% set lights = (rating/2)|int %}
                    {% set halfsb = (rating%2)|int %}
                    {% set grays = 5 - lights - halfsb %}
                    
                    {# 用循环的方式将星星展示出来 #}
                    {# 先循环满星 #}
                    {% for light in range(0, lights) %}
                        <img src="{{ url_for("static", filename="img/rate_light.png") }}" alt="">
                    {% endfor %}

					{# 半颗星 #}
                    {% for half in range(0,halfsb) %}
                        <img src="{{ url_for("static", filename="img/rate_half.jpg") }}" alt="">
                    {% endfor %}
                    
                    {# 灰色星星 #}
                    {% for gray in range(0,grays) %}
                        <img src="{{ url_for("static", filename="img/rate_gray.png") }}" alt="">
                    {% endfor %}

					{# 最后显示评分 #}
                    {{ ratings }}
                </p>
            </div>
{% endmacro %}

第二个宏(listGroup)

第二个宏稍稍有点复杂,它主要负责将首页的整块电影或电视剧模块封装起来,也就是这块
在这里插入图片描述
它也需要3个参数

  • module_title:模块的名称(电影或者电视剧)
  • items:电影列表或者电视剧列表,数据在app.py里已经定义好了。
  • category:这个参数用于判断是在电影这块点的更多按钮,还是在电视剧点的更多按钮
{% macro listGroup(module_title, items, category=category) %}
    <div class="item-list-group">
        <div class="item-list-top">
            <span class="module-title">{{ module_title }}</span>
            <a href="{{ url_for("move_list", category=category) }}" class="more-btn">更多</a>
        </div>
        <div class="list-group">
            {# 调用上面的宏 #}
            {% for item in items[0:3] %}
                {{ itemGroup(item.thumbnail, item.title, item.rating) }}
            {% endfor %}
        </div>
    </div>
{% endmacro %}

这里有个重点,这个a标签是用来跳转到电影或者电视剧的更多页面,因此它用到了url_for方法,第一参数是视图文件(app.py)的move_list函数,然后会将category作为查询参数以?category=X 的方式传入到move_list中,接着move_list就可以根据接收到的值来判断应该传些什么内容到模板里

<a href="{{ url_for("move_list", category=category) }}" class="more-btn">更多</a>

2. 创建父模板

在templates目录下创建base.html模板文件。

{% from "imitate_douban/macro.html" import itemGroup %}
{% from "imitate_douban/macro.html" import listGroup %}

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>
    {% block title %}

    {% endblock %}
    </title>

    {#    加载CSS文件   #}
    <link rel="stylesheet" href="{{ url_for('static', filename='css/base.css') }}">
    <link rel="stylesheet" href="{{ url_for('static', filename='css/item.css') }}">
</head>
<body>
    {% block header_title %}
        <h1>豆瓣小程序</h1>
    {% endblock %}

    <div class="container">
        <div class="search-group">
            <input type="text" class="search-input">
        </div>

        {% block content %}

        {% endblock %}

    </div>
</body>
</html>
  • 由于子模板都需要用到宏,因此父模板可以提前把宏先导入,然后由于css样式也是相同的,因此也可以将CSS文件也导入。
  • 需要用到用到block的地方有:
    • head标签下的title
    • 内容的主题header_title
    • 最后是内容content

3. 创建首页模板

在templates目录下创建index.html模板文件。

{% extends "imitate_douban/base.html" %}

{% block title %}
    首页
{% endblock %}

{% block content %}
    {{ listGroup("电影", movies, 1) }}
    <hr>
    {{ listGroup("电视剧", tvs, 2) }}
{% endblock %}
  • 在子模板中用extends继承父模板,然后根据父模板的block重写页面的内容
  • 这里关键的地方是block content,这里重写了父模板并且调用了listGroup这个宏并且传入了3个参数

4. 创建“更多”页面模板

在templates目录下创建base.html模板文件。

{% extends "imitate_douban/base.html" %}

{% block title %}
    电影
{% endblock %}

{% block header_title %}
    <h1>电影列表</h1>
{% endblock %}

{% block content %}
    {% for item in items %}
        {{ itemGroup(item.thumbnail, item.title, item.rating) }}
    {% endfor %}
{% endblock %}
  • 这个模板和上面的首页模板同理,不过在重写block content时调用的宏不一样,因为这个页面是要展示所有的影片,而首页只是展示3个,因此这里应该是循环items并将每个影片信息用itemGroup显示出来。

总结

以上的内容如果不用继承和宏的方式也可以实现,但是每个影片都需要重复写多次,这样代码就会看起来很多。但用上了宏和继承之后,只需要写一次,然后通过调用和循环的方式就可以将所有内容都展示出来。

  • 3
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值