2021-10-21-Flask-04 模型关系的建立,增删改查的演示,一篇文章让你直接搞懂Flask模型

本文详细介绍了如何使用 Flask-SQLAlchemy 进行数据库模型操作,包括1:N模型的创建、关系建立、CRUD操作以及N:M模型的处理。示例代码展示了用户模型和卡模型的创建,以及数据的添加、查询、修改和删除。此外,还涉及到了多对多关系的处理,通过建立第三张表实现用户和角色的关联,并演示了相关操作。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

项目地址:https://codechina.csdn.net/sabian2/myflask.git
这节是模型操作

1:N的模型操作

创建模型

在user_model.py创建两个模型类:用户模型和卡模型
db是flask的SQLAlchemy对象,在模块init文件中已定义

from models import db

#用户模型
class UserModel(db.Model):
    #主键
    id = db.Column(db.Integer,primary_key=True,autoincrement=True)
    #普通字段
    name=db.Column(db.String(30),nullable=False,comment='姓名')
    auth_key = db.Column(db.String(100),nullable=False,comment='密码')
    phone=db.Column(db.String(11),unique=True,comment='电话')


#用户的卡包模型
class CardModel(db.Model):
    #主键
    id = db.Column(db.Integer,primary_key=True,autoincrement=True)
    #普通字段
    publisher=db.Column(db.String(30),nullable=False,comment='发行商')
    number=db.Column(db.String(40),nullable=False,comment='卡号')
    money=db.Column(db.Float,nullable=False,comment='余额',default=0)
    #外键
    user_id=db.Column(db.Integer,db.ForeignKey('user.id'),nullable=True,comment='用户的id')

    #模型的反向引用
    user=db.relationship('UserModel',backref=db.backref('cards',lazy=True))


模型间关系

这两个模型的关系是1:N的外键关系,一般在多端建立关系

	user_id=db.Column(db.Integer,db.ForeignKey('user_model.id'),nullable=True,comment='用户的id')

    #模型的反向引用
    user=db.relationship('UserModel',backref=db.backref('cards',lazy=True))

在多端表 设置外键字段user_id,并建立反向引用关系

操作模型CRUD

模型添加数据

首先启动初始化数据库的视图,这里在前面的章节定义了user/login路由是这个功能,后面新建test模块,在测试函数中做操作
app.app_context().push():提取环境数据

db.session.add:添加模型数据
db.session.commit():确认数据并进行提交

为用户模型新增一条数据
from unittest import TestCase
from mainapp import app
from models import db
from models.user_model import UserModel, CardModel


class TestUser(TestCase):
    def test_add(self):
        app.app_context().push()
        user=UserModel()
        user.name='li'
        user.auth_key='dsadas'
        user.phone='31231233131'
        db.session.add(user)
        print(user.name)
        db.session.commit()

在这里插入图片描述

给用户1增加卡信息
    def test_waijianguanxi(self):
        app.app_context().push()
        user=UserModel.query.get(1)
        print(user.name)
        print(user.cards)
        card=CardModel()
        card.number='131230293023903902390923021'
        card.money=0
        card.publisher='健身房'
        db.session.add(card)
        user.cards.append(card)
        db.session.commit()

测试结果
在这里插入图片描述
数据库结果
在这里插入图片描述
可以看到,经过

        user.cards.append(card)

card_model表中外键已经取得了用户1的id

一次增加多个数据

db.session.add_all(li)使用这个函数来添加多个

    def test_addmany(self):
        app.app_context().push()
        li=[]
        for i in range(10):
            user=UserModel()
            user.phone='123123213'+str(i)
            user.name='dsd'+str(i)
            user.auth_key='dsafafjiaj'+str(i)
            li.append(user)
        db.session.add_all(li)
        db.session.commit()

在这里插入图片描述

查询数据

查询是删除和修改的基础操作

用模型类查询

查询的操作符参照这一篇

    def test_query1(self):
        app.app_context().push()

        user=UserModel.query.get(1)
        print(user.name)

        user2=UserModel.query.filter(UserModel.name.like('dsd%'))
        # print(user2[0].name)
        for i in user2:
            print(i.id,i.name)

UserModel.query.get(1)
根据主键的值查询,获取的是一条数据
UserModel.query.filter(UserModel.name.like(‘dsd%’))

根据查询条件获取,获取的是一个列表

在这里插入图片描述

用db.session查询

db.session.query(UserModel):查询整个模型,相当于select * from ,后面跟链式操作
db.session.query(UserModel.name,UserModel.phone):查询指定字段,取得的内容不具有其他字段,相当于select指定字段
order_by(),根据指定字段排序
limit(3):限制结果数

    def test_query2(self):
        app.app_context().push()
        user=db.session.query(UserModel).all()
        for i in user:
            print(i.name,i.id)

        user=db.session.query(UserModel.name,UserModel.phone).order_by(UserModel.phone).limit(3)
        for i in user:
            print(i.name,i.phone)
        

查询结果
在这里插入图片描述

修改数据

原数据
在这里插入图片描述
修改语句


    def test_update(self):

        app.app_context().push()

        user=UserModel.query.get(1)
        user.name='AAA'
        user.phone='213231312'
        user.auth_key='asdsdjasidnio'
        db.session.commit()

修改后的数据库数据在这里插入图片描述

删除数据

删除前数据库
在这里插入图片描述
删除语句

    def testremove(self):

        app.app_context().push()

        user=UserModel.query.get(2)
        print(user.name,user.phone)
        db.session.delete(user)
        db.session.commit()

删除后数据库
在这里插入图片描述

N:M的模型操作

多对多的关系一般采用建立第三张表的方式,并在任一张主表中建立索引关系

创建模型

from models import db

# 用户-角色多对多表
user_role = db.Table('user_role',
                     db.Column('user_id',db.Integer,db.ForeignKey('user_model.id')),
                     db.Column('role_id',db.Integer,db.ForeignKey('role.id')))
class UserModel(db.Model):
    #主键
    id = db.Column(db.Integer,primary_key=True,autoincrement=True)
    #普通字段
    name=db.Column(db.String(30),nullable=False,comment='姓名')
    auth_key = db.Column(db.String(100),nullable=False,comment='密码')
    phone=db.Column(db.String(11),unique=True,comment='电话')

    #多对多索引关系
    roles=db.relationship('Role',secondary=user_role,backref='users')




# 角色模型
class Role(db.Model):
    #主键
    id = db.Column(db.Integer,primary_key=True,autoincrement=True)
    #普通字段
    name=db.Column(db.String(30),nullable=False,comment='角色名称')

模型间关系

用户和角色表之间存在多对多关系,建立第三张表user_role来存储这些关系,并在用户表建立索引

模型操作

添加数据

为主键为1的用户添加了一个超级管理员角色

    def test_addmodel2(self):
        app.app_context().push()
        user=UserModel.query.get(1)
        role=Role()
        role.name='超级管理员'
        db.session.add(role)
        user.roles.append(role)
        db.session.commit()


测试显示的数据库语句
在这里插入图片描述
数据库数据表
在这里插入图片描述
在这里插入图片描述

查询与反向查询

    def test_query(self):
        app.app_context().push()
        user=UserModel.query.get(1)
        print(user.roles)

        role=Role.query.all()[0]
        print(role.users)
roles=db.relationship('Role',secondary=user_role,backref='users')

用户表中的索引关系语句是关键,定义了反向查询的名称在这里插入图片描述

修改数据

修改用户的第一个角色 的名称为普通管理员

    def test_update2(self):
        app.app_context().push()

        user=UserModel.query.get(1)
        user.roles[0].name='普通管理员'
        db.session.commit()

测试显示的数据库操作
在这里插入图片描述
数据库结果
在这里插入图片描述

删除数据

先给这些用户添加实习工角色

    def test_del2(self):
        app.app_context().push()
        role=Role()
        role.name='实习工'
        db.session.add(role)
        users=UserModel.query.filter(UserModel.name.like('dsd%'))
        for user in users:
            user.roles.append(role)
        db.session.commit()

此时第三张表数据是这样的
在这里插入图片描述

再将所有实习工身份的用户删除

    def test_del3(self):
        app.app_context().push()

        roles=Role.query.filter(Role.name=='实习工').all()
        for role in roles:
            users=role.users
            for user in users:
                db.session.delete(user)

        db.session.commit()

用户表已经没有了这些人
在这里插入图片描述

第三张表的关系也同步删除了
在这里插入图片描述

<think>由于这是一个全栈项目,涉及前端(Vue)和后端(Flask),我们将分别构建。由于代码量较大,这里将给出主要部分的代码和解释,并尽量简化。项目结构:backend/(Flask后端)app.pymodels.pyrequirements.txtfrontend/(Vue前端)...(使用VueCLI创建的项目结构)我们将使用SQLite作为数据库(为了简便),Flask提供RESTfulAPI,Vue作为前端框架。步骤:1.后端:使用Flask创建API,处理用户认证(登录)、博客的增删改查。2.前端:使用Vue创建用户界面,包括登录页面、博客列表、创建博客、编辑博客等。由于篇幅限制,这里不会展示完整的项目代码,但会给出关键部分的代码示例。后端实现(Flask):-安装必要的包:flask,flask-sqlalchemy,flask-cors (用于跨域),flask-login (用于用户会话管理)等。-定义用户模型和博客模型-实现登录路由和博客操作的路由。前端实现(Vue):-使用Vue CLI创建项目。-使用vue-router进行路由管理。-使用axios与后端API交互。-创建组件:登录组件、博客列表组件、博客编辑组件等。下面分别给出关键代码:后端代码:文件:backend/app.py```pythonfrom flaskimport Flask, jsonify,request,abortfrom flask_sqlalchemyimport SQLAlchemyfromflask_loginimport LoginManager,UserMixin,login_user, logout_user,login_required,current_userfromwerkzeug.security importgenerate_password_hash,check_password_hashfrom flask_corsimport CORSapp =Flask(__name__) app.config['SECRET_KEY']= 'your-secret-key' app.config['SQLALCHEMY_DATABASE_URI']= 'sqlite:///blog.db' app.config['SQLALCHEMY_TRACK_MODIFICATIONS']= Falsedb =SQLAlchemy(app) CORS(app, supports_credentials=True)#允许跨域请求login_manager= LoginManager()login_manager.init_app(app)#用户模型class User(UserMixin,db.Model):id =db.Column(db.Integer, primary_key=True)username =db.Column(db.String(50), unique=True,nullable=False)password_hash= db.Column(db.String(100),nullable=False)def set_password(self, password):self.password_hash =generate_password_hash(password)def check_password(self, password):return check_password_hash(self.password_hash,password)#博客模型classBlogPost(db.Model):id =db.Column(db.Integer, primary_key=True)title =db.Column(db.String(100), nullable=False)content= db.Column(db.Text,nullable=False)user_id= db.Column(db.Integer,db.ForeignKey('user.id'),nullable=False) @login_manager.user_loaderdef load_user(user_id):returnUser.query.get(int(user_id)) @app.route('/login',methods=['POST'])def login():data =request.jsonusername =data.get('username')password =data.get('password')user =User.query.filter_by(username=username).first()ifuser anduser.check_password(password):login_user(user)returnjsonify({'message': 'Loggedin successfully'}),200return jsonify({'message':'Invalidusername orpassword'}),401@app.route('/logout') @login_requireddef logout():logout_user()return jsonify({'message':'Loggedout'}),200@app.route('/posts', methods=['GET']) @login_requireddef list_posts():posts =BlogPost.query.filter_by(user_id=current_user.id).all()returnjsonify([{'id':post.id, 'title':post.title, 'content':post.content} forpost inposts])@app.route('/posts', methods=['POST']) @login_requireddef create_post():data= request.jsonifnot dataor notdata.get('title') ornot data.get('content'):abort(400)post =BlogPost(title=data['title'], content=data['content'],user_id=current_user.id)db.session.add(post)db.session.commit()returnjsonify({'id': post.id,'title': post.title,'content': post.content}),201@app.route('/posts/<int:post_id>',methods=['PUT'])@login_requireddefupdate_post(post_id):post =BlogPost.query.get_or_404(post_id)ifpost.user_id !=current_user.id:abort(403)data =request.jsonif notdata:abort(400)post.title= data.get('title',post.title)post.content= data.get('content',post.content)db.session.commit()returnjsonify({'id': post.id,'title': post.title,'content': post.content})@app.route('/posts/<int:post_id>', methods=['DELETE']) @login_requireddef delete_post(post_id):post= BlogPost.query.get_or_404(post_id)if post.user_id!= current_user.id:abort(403)db.session.delete(post)db.session.commit()return '',204if__name__ =='__main__':db.create_all()#创建数据库表app.run(debug=True)```前端代码(Vue):由于前端代码较长,这里只给出关键组件和代码片段。首先,安装必要的依赖:vue-router, axios, vuex(可选,这里为了简便不使用vuex)文件:frontend/src/views/Login.vue```vue<template><div><h2>Login</h2><form @submit.prevent="login"><inputtype="text" v-model="username"placeholder="Username"required><input type="password" v-model="password"placeholder="Password"required><button type="submit">Login</button></form></div> </template><script>import axiosfrom 'axios';export default{data(){return {username: '',password: ''};},methods: {asynclogin(){try {constresponse =await axios.post('http://localhost:5000/login',{username:this.username,password:this.password}, {withCredentials: true});//发送凭证(如cookies)if(response.status ===200) {this.$router.push('/posts');}}catch (error){alert('Login failed');}}} };</script> ```文件:frontend/src/views/PostList.vue```vue<template><div><h2>MyPosts</h2><button@click="createNew">NewPost</button><ul><li v-for="post inposts":key="post.id"><h3>{{ post.title }}</h3><p>{{ post.content }}</p><button @click="editPost(post.id)">Edit</button><button @click="deletePost(post.id)">Delete</button></li></ul></div></template> <script> importaxios from'axios'; exportdefault {data() {return{posts:[]};},created(){this.fetchPosts();},methods: {asyncfetchPosts() {try{const response= awaitaxios.get('http://localhost:5000/posts',{ withCredentials:true });this.posts= response.data;}catch (error){console.error('Failedto fetchposts',error);}},createNew(){this.$router.push('/posts/new');},editPost(id) {this.$router.push(`/posts/edit/${id}`);},asyncdeletePost(id){try {awaitaxios.delete(`http://localhost:5000/posts/${id}`, {withCredentials: true});this.fetchPosts();//重新加载列表} catch(error) {console.error('Failed todelete post', error);}}} };</script> ```文件:frontend/src/views/EditPost.vue (同时用于新建和编辑) ```vue<template><div><h2 v-if="editMode">EditPost</h2><h2 v-else>NewPost</h2><form@submit.prevent="submit"><input type="text" v-model="title"placeholder="Title"required><textarea v-model="content"placeholder="Content"required></textarea><button type="submit">Save</button></form></div> </template><script>import axiosfrom 'axios';export default{props:{id: String//路由参数,如果是新建则为undefined},data(){return {title: '',content: '',editMode:false};},created() {if(this.id){this.editMode= true;this.fetchPost(this.id);}},methods: {asyncfetchPost(id){try {constresponse =await axios.get(`http://localhost:5000/posts/${id}`,{ withCredentials:true });this.title =response.data.title;this.content= response.data.content;} catch(error) {console.error('Failed tofetch post', error);}},async submit() {try{if (this.editMode){await axios.put(`http://localhost:5000/posts/${this.id}`, {title: this.title,content: this.content},{ withCredentials:true });}else {awaitaxios.post('http://localhost:5000/posts', {title: this.title,content: this.content},{ withCredentials:true });}this.$router.push('/posts');}catch (error){console.error('Failedto savepost',error);}}}}; </script>```路由配置:frontend/src/router/index.js```javascriptimport Vuefrom 'vue'import Routerfrom 'vue-router' importLogin from'../views/Login.vue'import PostList from'../views/PostList.vue'import EditPost from'../views/EditPost.vue'Vue.use(Router)export defaultnew Router({routes:[{path:'/',redirect: '/login'},{path: '/login',name: 'Login',component: Login},{path:'/posts',name:'PostList',component: PostList},{path: '/posts/new',name:'NewPost',component: EditPost},{path: '/posts/edit/:id',name:'EditPost',component: EditPost,props: true}] })```注意:以上代码仅为示例,实际开发中需要处理更多的边界情况和错误处理。另外,前端部分需要配置axios以携带凭证(withCredentials: true)来支持基于cookie的会话(flask-login默认使用cookie)。由于这是一个基础示例,没有包含用户注册功能,你可以根据需要添加。运行步骤:1.后端:进入backend目录,安装依赖(flask, flask-sqlalchemy, flask-login,flask-cors),运行app.py。2.前端:进入frontend目录,安装依赖(vue-router, axios),使用`npm runserve`运行。注意:在开发环境下,前端运行在localhost:8080(默认),后端运行在localhost:5000,所以存在跨域问题,我们使用了CORS来解决。相关问题:</think>下面我将使用Flask作为后端API服务,Vue.js作为前端框架,实现一个博客管理系统。这个系统将包含用户登录认证、博客的增删改查功能。 ### 解决方案概述 1. **后端(Flask)**:提供RESTful API,处理用户认证和博客管理 2. **前端(Vue.js)**:构建用户界面,与后端API交互 3. **数据库**:使用SQLite存储用户和博客数据 ### 后端实现 (Flask) #### 文件结构 ``` backend/ ├── app.py ├── requirements.txt └── instance/ └── blog.db (SQLite数据库) ``` #### 代码实现 **requirements.txt** ``` flask flask-sqlalchemy flask-cors flask-login werkzeug ``` **app.py** ```python from flask import Flask, jsonify, request, abort from flask_sqlalchemy import SQLAlchemy from flask_login import LoginManager, UserMixin, login_user, logout_user, login_required, current_user from werkzeug.security import generate_password_hash, check_password_hash from flask_cors import CORS app = Flask(__name__) app.config['SECRET_KEY'] = 'your-secret-key' app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///instance/blog.db' app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False db = SQLAlchemy(app) CORS(app, supports_credentials=True) # 允许跨域请求 login_manager = LoginManager() login_manager.init_app(app) # 用户模型 class User(UserMixin, db.Model): id = db.Column(db.Integer, primary_key=True) username = db.Column(db.String(50), unique=True, nullable=False) password_hash = db.Column(db.String(100), nullable=False) def set_password(self, password): self.password_hash = generate_password_hash(password) def check_password(self, password): return check_password_hash(self.password_hash, password) # 博客模型 class BlogPost(db.Model): id = db.Column(db.Integer, primary_key=True) title = db.Column(db.String(100), nullable=False) content = db.Column(db.Text, nullable=False) user_id = db.Column(db.Integer, db.ForeignKey('user.id'), nullable=False) @login_manager.user_loader def load_user(user_id): return User.query.get(int(user_id)) @app.route('/api/login', methods=['POST']) def login(): data = request.json username = data.get('username') password = data.get('password') user = User.query.filter_by(username=username).first() if user and user.check_password(password): login_user(user) return jsonify({'message': 'Logged in successfully', 'user': {'id': user.id, 'username': user.username}}), 200 return jsonify({'message': 'Invalid username or password'}), 401 @app.route('/api/logout') @login_required def logout(): logout_user() return jsonify({'message': 'Logged out'}), 200 @app.route('/api/posts', methods=['GET']) @login_required def list_posts(): posts = BlogPost.query.filter_by(user_id=current_user.id).all() return jsonify([{ 'id': post.id, 'title': post.title, 'content': post.content, 'user_id': post.user_id } for post in posts]) @app.route('/api/posts', methods=['POST']) @login_required def create_post(): data = request.json if not data or not data.get('title') or not data.get('content'): abort(400) post = BlogPost( title=data['title'], content=data['content'], user_id=current_user.id ) db.session.add(post) db.session.commit() return jsonify({ 'id': post.id, 'title': post.title, 'content': post.content }), 201 @app.route('/api/posts/<int:post_id>', methods=['PUT']) @login_required def update_post(post_id): post = BlogPost.query.get_or_404(post_id) if post.user_id != current_user.id: abort(403) data = request.json if not data: abort(400) post.title = data.get('title', post.title) post.content = data.get('content', post.content) db.session.commit() return jsonify({ 'id': post.id, 'title': post.title, 'content': post.content }) @app.route('/api/posts/<int:post_id>', methods=['DELETE']) @login_required def delete_post(post_id): post = BlogPost.query.get_or_404(post_id) if post.user_id != current_user.id: abort(403) db.session.delete(post) db.session.commit() return '', 204 if __name__ == '__main__': with app.app_context(): db.create_all() # 创建初始用户(仅用于演示) if not User.query.filter_by(username='admin').first(): admin = User(username='admin') admin.set_password('admin123') db.session.add(admin) db.session.commit() app.run(debug=True) ``` ### 前端实现 (Vue.js) #### 文件结构 ``` frontend/ ├── public/ ├── src/ │ ├── assets/ │ ├── components/ │ │ ├── BlogList.vue │ │ ├── BlogForm.vue │ │ └── NavBar.vue │ ├── views/ │ │ ├── Login.vue │ │ ├── Dashboard.vue │ ├── router/ │ │ └── index.js │ ├── services/ │ │ └── api.js │ ├── App.vue │ └── main.js └── package.json ``` #### 关键代码实现 **src/services/api.js** ```javascript import axios from 'axios'; const api = axios.create({ baseURL: 'http://localhost:5000/api', withCredentials: true, // 允许发送cookie }); export default { login(credentials) { return api.post('/login', credentials); }, logout() { return api.get('/logout'); }, getPosts() { return api.get('/posts'); }, createPost(post) { return api.post('/posts', post); }, updatePost(id, post) { return api.put(`/posts/${id}`, post); }, deletePost(id) { return api.delete(`/posts/${id}`); } }; ``` **src/router/index.js** ```javascript import Vue from 'vue'; import Router from 'vue-router'; import Login from '../views/Login.vue'; import Dashboard from '../views/Dashboard.vue'; Vue.use(Router); const router = new Router({ routes: [ { path: '/', redirect: '/login' }, { path: '/login', name: 'Login', component: Login }, { path: '/dashboard', name: 'Dashboard', component: Dashboard, meta: { requiresAuth: true } } ] }); router.beforeEach((to, from, next) => { if (to.meta.requiresAuth) { // 实际项目中应检查用户是否已登录 const isAuthenticated = localStorage.getItem('user') !== null; if (!isAuthenticated) { next('/login'); return; } } next(); }); export default router; ``` **src/views/Login.vue** ```vue <template> <div class="login-container"> <h2>博客管理系统登录</h2> <form @submit.prevent="login"> <div> <label>用户名:</label> <input type="text" v-model="credentials.username" required> </div> <div> <label>密码:</label> <input type="password" v-model="credentials.password" required> </div> <button type="submit">登录</button> <p v-if="error" class="error">{{ error }}</p> </form> </div> </template> <script> import api from '@/services/api'; export default { data() { return { credentials: { username: '', password: '' }, error: '' }; }, methods: { async login() { try { const response = await api.login(this.credentials); localStorage.setItem('user', JSON.stringify(response.data.user)); this.$router.push('/dashboard'); } catch (err) { this.error = '登录失败,请检查用户名和密码'; } } } }; </script> ``` **src/views/Dashboard.vue** ```vue <template> <div> <NavBar /> <div class="dashboard"> <h1>我的博客</h1> <button @click="showCreateForm">新建博客</button> <BlogForm v-if="showForm" :post="editingPost" @save="savePost" @cancel="cancelEdit" /> <BlogList :posts="posts" @edit="editPost" @delete="deletePost" /> </div> </div> </template> <script> import BlogList from '@/components/BlogList.vue'; import BlogForm from '@/components/BlogForm.vue'; import NavBar from '@/components/NavBar.vue'; import api from '@/services/api'; export default { components: { BlogList, BlogForm, NavBar }, data() { return { posts: [], showForm: false, editingPost: null }; }, async created() { await this.fetchPosts(); }, methods: { async fetchPosts() { try { const response = await api.getPosts(); this.posts = response.data; } catch (err) { console.error('获取博客列表失败:', err); } }, showCreateForm() { this.editingPost = null; this.showForm = true; }, editPost(post) { this.editingPost = { ...post }; this.showForm = true; }, async savePost(post) { try { if (post.id) { await api.updatePost(post.id, post); } else { await api.createPost(post); } this.showForm = false; await this.fetchPosts(); } catch (err) { console.error('保存博客失败:', err); } }, async deletePost(id) { if (confirm('确定要删除这篇博客吗?')) { try { await api.deletePost(id); await this.fetchPosts(); } catch (err) { console.error('删除博客失败:', err); } } }, cancelEdit() { this.showForm = false; this.editingPost = null; } } }; </script> ``` **src/components/BlogForm.vue** ```vue <template> <div class="blog-form"> <h2>{{ editingPost ? '编辑博客' : '新建博客' }}</h2> <form @submit.prevent="save"> <div> <label>标题:</label> <input type="text" v-model="form.title" required> </div> <div> <label>内容:</label> <textarea v-model="form.content" rows="10" required></textarea> </div> <button type="submit">保存</button> <button type="button" @click="cancel">取消</button> </form> </div> </template> <script> export default { props: { post: Object }, data() { return { form: { id: null, title: '', content: '' } }; }, watch: { post: { immediate: true, handler(newVal) { if (newVal) { this.form = { ...newVal }; } else { this.form = { id: null, title: '', content: '' }; } } } }, methods: { save() { this.$emit('save', this.form); }, cancel() { this.$emit('cancel'); } } }; </script> ``` ### 系统功能说明 1. **用户认证**: - 登录/登出功能 - 使用Flask-Login管理会话 - 前端使用localStorage存储用户信息 2. **博客管理**: - 创建新博客 - 查看博客列表 - 编辑现有博客 - 删除博客 3. **安全措施**: - 后端验证用户权限(只有博主可修改/删除自己的博客) - 前端路由守卫保护受保护页面 ### 如何运行 1. **后端**: ```bash cd backend pip install -r requirements.txt python app.py ``` 2. **前端**: ```bash cd frontend npm install npm run serve ``` 3. **访问**: - 登录页面:http://localhost:8080/login - 使用账号:admin / admin123 ### 技术要点解释 1. **Flask-Login**:处理用户会话管理和认证 2. **SQLAlchemy**:ORM数据库操作 3. **CORS**:解决跨域资源共享问题 4. **Vue组件化**:将UI拆分为可复用组件 5. **Axios**:处理HTTP请求 6. **Vue Router**:前端路由管理 ### 相关优化建议 1. 添加用户注册功能 2. 实现博客分类和标签 3. 添加博客搜索功能 4. 实现博客分页展示 5. 添加Markdown编辑器支持
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Amoor123

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值