flask-18 Flask-SQLAlchemy一对多(one-to-many)关系

目录

一、目录结构

1、目录图

2、apps下__init__.py

3、settings.py

4、app.py

 二、模型创建

1、apps/user目录下 models.py

2、apps/artice目录下 models.py

3、生成模型库表

 三、应用

 1、templates下新增article文件夹

2、templates/article下新增 article_add.html

3、templates/article下新增 all.html

4、templates/article下新增 user_article.html

5、apps/article下新增 view.py

6、修改apps下__init__.py

7、修改base.html

8、修改templates/user下center.html

9、启动服务


最为常见的关系就是一对多的关系。因为关系在它们建立之前就已经声明,您可以使用 字符串来指代还没有创建的类(例如如果 Person 定义了一个到 Article 的关系,而 Article 在文件的后面才会声明)。

关系使用 relationship() 函数表示。然而外键必须用类 sqlalchemy.schema.ForeignKey 来单独声明:

class Person(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String(50))
    addresses = db.relationship('Address', backref='person',
                                lazy='dynamic')

class Address(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    email = db.Column(db.String(50))
    person_id = db.Column(db.Integer, db.ForeignKey('person.id'))

db.relationship() 做了什么?这个函数返回一个可以做许多事情的新属性。在本案例中,我们让它指向 Address 类并加载多个地址。它如何知道会返回不止一个地址?因为 SQLALchemy 从您的声明中猜测了一个有用的默认值。 如果您想要一对一关系,您可以把 uselist=False 传给 relationship() 。

那么 backref 和 lazy 意味着什么了?backref 是一个在 Address 类上声明新属性的简单方法。您也可以使用 my_address.person 来获取使用该地址(address)的人(person)。lazy 决定了 SQLAlchemy 什么时候从数据库中加载数据:

  • 'select' (默认值) 就是说 SQLAlchemy 会使用一个标准的 select 语句必要时一次加载数据。
  • 'joined' 告诉 SQLAlchemy 使用 JOIN 语句作为父级在同一查询中来加载关系。
  • 'subquery' 类似 'joined' ,但是 SQLAlchemy 会使用子查询。
  • 'dynamic' 在有多条数据的时候是特别有用的。不是直接加载这些数据,SQLAlchemy 会返回一个查询对象,在加载数据前您可以过滤(提取)它们。

您如何为反向引用(backrefs)定义惰性(lazy)状态?使用 backref() 函数:

class User(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String(50))
    addresses = db.relationship('Address',
        backref=db.backref('person', lazy='joined'), lazy='dynamic')

一、目录结构

1、目录图

2、apps下__init__.py

from flask import Flask
import settings
from apps.user.view import user_bp
from ext import db


def create_app():
    app = Flask(__name__, template_folder='../templates', static_folder='../static')
    # 加载配置
    app.config.from_object(settings.DevelopmentConfig)
    # 将db对象与app进行关联
    db.init_app(app=app)
    # 蓝图 ,将蓝图对象绑定到app上
    app.register_blueprint(user_bp)
    return app


if __name__ == '__main__':
    app = create_app()
    app.run()

3、settings.py

#!/usr/bin/env python
# -*- coding: utf-8 -*-
# @Time    : 2021/12/16 9:53
# @Author  : niubobo
# @File    : settings.py
# @Software: PyCharm
class Config:
    DEBUG = True
    # 数据库配置
    SQLALCHEMY_DATABASE_URI = 'mysql+pymysql://用户:密码@ip:3306/blog'
    SQLALCHEMY_TRACK_MODIFICATIONS = False
    SQLALCHEMY_ECHO = True


class DevelopmentConfig(Config):
    ENV = 'development'


class ProductionConfig(Config):
    ENV = 'production'
    DEBUG = False

4、app.py

from flask_script import Manager
from flask_migrate import Migrate, MigrateCommand
from apps import create_app
from ext import db
from apps.user.models import User
from apps.article.models import Article


app = create_app()
print(app)
manager = Manager(app=app)

# 命令工具
migrate = Migrate(app=app, db=db)
# 添加命令到manager
manager.add_command('db', MigrateCommand)


@manager.command
def init():
    print('初始化')


if __name__ == '__main__':
    manager.run()

 二、模型创建

1、apps/user目录下 models.py

#!/usr/bin/env python
# -*- coding: utf-8 -*-
# @Time    : 2021/12/16 10:01
# @Author  : niubobo
# @File    : models.py
# @Software: PyCharm
from datetime import datetime
from ext import db


class User(db.Model):
    id = db.Column(db.Integer, primary_key=True, autoincrement=True)
    username = db.Column(db.String(15), nullable=False)
    password = db.Column(db.String(64), nullable=False)
    phone = db.Column(db.String(11), unique=True, nullable=True)
    email = db.Column(db.String(30))
    icon = db.Column(db.String(100))
    isdelete = db.Column(db.Boolean, default=False)
    rdatetime = db.Column(db.DateTime, default=datetime.now)
    # 增加一个字段
    articles = db.relationship('Article', backref='user')

    def __str__(self):
        return self.username

2、apps/artice目录下 models.py

#!/usr/bin/env python
# -*- coding: utf-8 -*-
# @Time    : 2021/12/17 13:14
# @Author  : niubobo
# @File    : models.py
# @Software: PyCharm
from datetime import datetime
from ext import db


class Article(db.Model):
    id = db.Column(db.Integer, primary_key=True, autoincrement=True)
    title = db.Column(db.String(50), nullable=False)
    content = db.Column(db.Text, nullable=False)
    pdatetime = db.Column(db.DateTime, default=datetime.now)
    click_num = db.Column(db.Integer, default=0)
    save_num = db.Column(db.Integer, default=0)
    love_num = db.Column(db.Integer, default=0)
    #  外键
    user_id = db.Column(db.Integer, db.ForeignKey('user.id'), nullable=False)

3、生成模型库表

终端输入命令执行:

python app.py db init
 
python app.py db migrate
 
python app.py db upgrade

 三、应用

稍微改造一下前面课程代码进行用户注册

 实现以下:

 1、templates下新增article文件夹

2、templates/article下新增 article_add.html

{% extends 'base.html' %}
{% block title %}
    添加文章
{% endblock %}
{% block middle %}

<form action="{{ url_for('article.publish_article') }}" method="post">
    <p><input type="text" name="title" placeholder="文章标题"></p>
    <p>
        <textarea cols="50" rows="10" name="content" placeholder="输入文章内容">
        </textarea>
    </p>
    <p>
         用户:
        <select name="uid" >
            <option value="0">请选择用户</option>
            {% for user in users %}
                <option value="{{ user.id }}">{{ user.username }}</option>
            {% endfor %}
        </select>
    </p>
    <p><input type="submit" value="添加文章"></p>
</form>
{% endblock %}

3、templates/article下新增 all.html

关键:

{% extends 'base.html' %}
{% block title %}
    文章列表
{% endblock %}
{% block modle_style %}
    <style>
    #container{
        border: 1px solid brown;
        margin-bottom: 10px;
        padding: 5px;
    }
    </style>
{% endblock %}
{% block middle %}
    <div style="border: 10px seagreen; margin-right: 50px; padding: 5px; text-align: right;"><a href="{{ url_for('article.publish_article') }}">发表文章</a></div>

{% for article in articles %}
    <div id="container">
        <p>
            <h3>{{ article.title }}</h3>
            <div>作者:{{ article.user.username }}</div>
        </p>
        <p>{{ article.content }}</p>
    <div>{{ article.pdatetime }}</div>
    </div>

{% endfor %}



{% endblock %}

4、templates/article下新增 user_article.html

关键

{% extends 'base.html' %}
{% block title %}
    用户文章列表
{% endblock %}
{% block modle_style %}
    <style>
    #container{
        border: 1px solid brown;
        margin-bottom: 10px;
        padding: 5px;
    }
    </style>
{% endblock %}
{% block middle %}
{% for article in user.articles %}
    <div id="container">
        <p>
            <h3>{{ article.title }}</h3>
            <div>作者:{{ user.username }}</div>
        </p>
        <p>{{ article.content }}</p>
    <div>{{ article.pdatetime }}</div>
    </div>

{% endfor %}

{% endblock %}

5、apps/article下新增 view.py

#!/usr/bin/env python
# -*- coding: utf-8 -*-
# @Time    : 2021/12/17 13:41
# @Author  : niubobo
# @File    : view.py.py
# @Software: PyCharm
from flask import Blueprint, request, render_template, redirect, url_for
from sqlalchemy import or_, and_
from apps.article.models import Article
from apps.user.models import User
from ext import db

article_bp = Blueprint('article', __name__)


@article_bp.route('/publish', methods=['GET', 'POST'])
def publish_article():
    if request.method == 'POST':
        title = request.form.get('title')
        content = request.form.get('content')
        uid = request.form.get('uid')
        # 添加文章
        article = Article()
        article.title = title
        article.content = content
        article.user_id = uid
        db.session.add(article)
        db.session.commit()
        return redirect(url_for('article.all_article'))
    else:
        users = User.query.filter(User.isdelete == False).all()
        return render_template('article/article_add.html', users=users)


@article_bp.route('/all')
def all_article():
    articles = Article.query.all()
    return render_template('article/all.html', articles=articles)


@article_bp.route('/userArticle')
def user_article():

    id = request.args.get('id')
    user = User.query.get(id)
    have_article = Article.query.filter(Article.user_id == id).first()
    # 这个判断是我加得,该例子可以去掉
    if have_article:
        return render_template('article/user_article.html', user=user)
    else:
        return render_template('article/user_article.html', user=user, msg='该用户还未发表博文!')

6、修改apps下__init__.py

注册到蓝图

from flask import Flask
import settings
from apps.article.view import article_bp
from apps.user.view import user_bp
from ext import db


def create_app():
    app = Flask(__name__, template_folder='../templates', static_folder='../static')
    # 加载配置
    app.config.from_object(settings.DevelopmentConfig)
    # 将db对象与app进行关联
    db.init_app(app=app)
    # 蓝图 ,将蓝图对象绑定到app上
    app.register_blueprint(user_bp)
    app.register_blueprint(article_bp)
    return app


if __name__ == '__main__':
    app = create_app()
    app.run()

7、修改base.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>
        {% block title %} 父模板的title{% endblock %}
    </title>
    <style>
        #head{
            height: 50px;
            background-color: bisque;
        }

        #head ul{
            list-style: none;
            height: 50px;
        }
        #head ul li{
            float: left;
            width: 100px;
            text-align: center;
            font-size: 15px;
            line-height: 50px;
        }

        #middle{
            height: 100%;
            background-color: azure;
        }
        #foot{
            height: 50px;
            line-height: 50px;
            background-color: darkolivegreen;
        }
    </style>
    {%  block modle_style %}{%  endblock %}
    {% block jquery %}{% endblock %}

</head>
<body>
<div id="head">
    <ul>
        <li><a href="{{ url_for('user.user_center') }}">首页</a></li>
        <li><a href="{{ url_for('user.register') }}">注册</a></li>
        <li><a href="{{ url_for('user.login') }}">登录</a></li>
        <li><a href="{{ url_for('article.all_article') }}">博客</a></li>
        <li><a href="">会员</a></li>

    </ul>
</div>

<div id="middle">
    {% block middle %} 中间{% endblock %}
</div>
<div id="foot">
    我是底部
</div>
{% block myjs %}{% endblock %}
</body>
</html>

8、修改templates/user下center.html

{% extends 'base.html' %}
{% block title %}
    用户信息
{% endblock %}

{% block jquery %}
    <script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.1.0/jquery.min.js"></script>
{% endblock %}

{% block middle %}
    <h2>所有用户信息如下:</h2>
    搜索: <input type="text" name="search" placeholder="输入用户名或手机号码"> <input type="button" value="搜索" id="search">
    <br>
    {% if users %}
    <span>当前用户人数:{{ users|length }}人</span>
    <table border="1" cellspacing="0" width="70%">
        <tr>
            <th>序号</th>
            <th>用户名</th>
            <th>手机号</th>
            <th>邮箱</th>
            <th>注册时间</th>
            <th>操作</th>
        </tr>
    {% for user in users %}
        <tr>
        <td>{{ loop.index }}</td>
        <td>{{ user.username }}</td>
        <td>{{ user.phone }}</td>
            <td>{{ user.email }}</td>
            <td>{{ user.rdatetime }}</td>
            <td><a href={{ url_for('user.update_user') }}?id={{ user.id }}">修改</a>
                <a href={{ url_for('user.del_user') }}?id={{ user.id }}">删除</a>
                <a href={{ url_for('article.user_article') }}?id={{ user.id }}">博文</a></td>
           <!-- <td><a href="javascript:;" onclick="update('{{ user.username }}')">修改</a>
                <a href="javascript:;" onclick="del('{{ user.username }}')">删除</a></td>  -->
        </tr>
    {% endfor %}

    </table>
    {% else %}
    <p style="color: red; font-size: 20px;">当前还没有任何用户,抓紧时间注册吧!!</p>
    {% endif %}
{% endblock %}
{% block myjs %}
    <script>
    //检索
    $('#search').click(function () {
        let content = $("input[name='search']").val();
        location.href = '{{ url_for('user.search') }}?search='+content
         // http://ip:端口/search?search=输入的值
    })
    //删除函数
     //   function del(username) {
           // console.log(username)
           // // location 地址栏对象
       //     location.href = '/del?username='+username
     //   }
    //修改函数
   // function update(username) {
    //    location.href = '/update?username='+username
   // }
    </script>
{% endblock %}

9、启动服务

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值