阅读量:0
1.前后端分离的架构
在前后端分离的架构中,前端和后端分别作为独立的项目进行开发和部署。前端项目通过API与后端项目进行通信。
- 前端:使用Vue.js构建用户界面,调用后端提供的RESTful API获取和发送数据。
- 后端:使用Django构建API,处理业务逻辑和数据存储
2.创建django项目及vue项目
创建app的时候需要进入项目的目录下 win10 cd xmmc
django-admin startproject xmmc django-admin startapp app01
以管理员身份打开命令行界面,进入任意一个想要创建项目的文件夹
vue create vueproject
然后按自己的需求选择,可以去专门搜一下创建vue的教程
3.配置setting
(1)配置数据库
DATABASES = { 'default': { 'ENGINE': 'django.db.backends.mysql', # 加载mysql引擎 'NAME': 'db_goods', # 数据库名称 'USER': 'root', # mysql账户名 'PASSWORD': '123456', # mysql账户密码 'PORT': 3306, # 端口号 'HOST': 'localhost' } }
(2)配置模板文件
TEMPLATES = [ { 'BACKEND': 'django.template.backends.django.DjangoTemplates', 'DIRS': [os.path.join(BASE_DIR, 'templates')], 'APP_DIRS': True, 'OPTIONS': { 'context_processors': [ 'django.template.context_processors.debug', 'django.template.context_processors.request', 'django.contrib.auth.context_processors.auth', 'django.contrib.messages.context_processors.messages', ], }, }, ]
(3)配置静态文件
STATIC_URL = 'static/' STATICFILES_DIRS = [os.path.join(BASE_DIR, 'static')]
(4)注册app(使用创建 django-admin startapp app名称)
(5)解决跨域问题
MIDDLEWARE = [ 'django.middleware.security.SecurityMiddleware', 'django.contrib.sessions.middleware.SessionMiddleware', 'corsheaders.middleware.CorsMiddleware', # 跨域,一定要写在第三行 'django.middleware.common.CommonMiddleware', # 'django.middleware.csrf.CsrfViewMiddleware', 'django.contrib.auth.middleware.AuthenticationMiddleware', 'django.contrib.messages.middleware.MessageMiddleware', 'django.middleware.clickjacking.XFrameOptionsMiddleware', ]
CORS_ORIGIN_ALLOW_ALL = True CORS_ALLOW_CREDENTIALS = True # 允许所有的请求头 CORS_ALLOW_HEADERS = ('*')
4.查看目录结构
web_django/ ├── static/ ├── templates/ ├── user/ │ ├── migrations/ │ ├── __init__.py │ ├── admin.py │ ├── apps.py │ ├── models.py │ ├── tests.py │ ├── urls.py │ ├── views.py ├── web_django/ │ ├── __init__.py │ ├── asgi.py │ ├── settings.py │ ├── urls.py │ ├── wsgi.py ├── webapp/ │ ├── migrations/ │ ├── views/ │ ├── __init__.py │ ├── admin.py │ ├── apps.py │ ├── models.py │ ├── tests.py │ ├── urls.py │ ├── views.py
5.前后端实现登录
(1)编写登录的前端(完整代码)
<template> <div class="login-background"> <div class="login-container"> <el-card class="box-card" style="opacity: 0.9;"> <h2>登录</h2> <el-form :model="ruleForm" status-icon :rules="rules" ref="ruleForm" label-position="left" label-width="70px" class="login-form" > <el-form-item label="用户名" prop="uname"> <el-input v-model="ruleForm.uname"></el-input> </el-form-item> <el-form-item label="密码" prop="password"> <el-input type="password" v-model="ruleForm.password" autocomplete="off" ></el-input> </el-form-item> </el-form> <div class="btn-group"> <el-button type="primary" @click="submitForm('ruleForm')" >登录</el-button > <el-button @click="resetForm('ruleForm')">重置</el-button> <router-link to="/register"> <el-button style="margin-left:10px">注册</el-button> </router-link> </div> </el-card> </div> </div> </template> <script> import axios from 'axios'; export default { data() { return { ruleForm: { uname: "", password: "", }, rules: { uname: [ { required: true, message: "用户名不能为空!", trigger: "blur" }, ], password: [ { required: true, message: "密码不能为空!", trigger: "blur" }, ], }, }; }, methods: { async submitForm(formName) { try { const response = await axios.post('http://127.0.0.1:8005/user/login/', this.ruleForm); // 在这里处理后端响应 console.log(response.data); if (response.data.success) { sessionStorage.setItem('username', JSON.stringify(response.data)) // 登录成功,跳转到 Index 页面 this.$router.push('/components/News'); } else { // 登录失败,显示错误消息或其他处理 console.error('登录失败:', response.data.message); } } catch (error) { console.error('提交表单时发生错误:', error); } }, resetForm(formName) { this.$refs[formName].resetFields(); }, }, }; </script> <style scoped> .login-background { background-image: url('https://pic4.zhimg.com/v2-b730c73ebd78bd5f22293aab0d343f4b_r.jpg?source=1940ef5c'); background-size: cover; background-position: center; height: 100vh; display: flex; justify-content: center; align-items: center; } .box-card { width: 400px; } .login-form { margin: auto; } .btn-group { margin-top: 20px; } </style>
登录效果图
(2)编写登录后端views(视图文件)
from django.http import JsonResponse from django.contrib.auth import authenticate, login from django.contrib.auth.models import User import json def login_view(request): # if request.method == 'GET': if request.method == 'POST': js = request.body.decode('utf8') data = json.loads(js) username = data['uname'] password = data['password'] # 使用 Django 自带的 authenticate 方法验证用户身份 user = authenticate(request, username=username, password=password) if user is not None: # 登录成功,将用户添加到当前会话中 login(request, user) print(user) return JsonResponse({'code': 200, 'success': True, 'message': '登录成功', 'username': str(user)}) else: # 登录失败,返回错误消息 return JsonResponse({'code': 500, 'success': False, 'message': '用户名或密码错误', }) # 如果不是 POST 请求,则返回错误消息 return JsonResponse({'success': False, 'message': '只支持 POST 请求'}) def register_view(request): if request.method == 'POST': # 从请求体中获取JSON数据 js = request.body.decode('utf8') data = json.loads(js) print(data) username = data['uname'] password = data['password'] # 检查用户名是否已经存在 if User.objects.filter(username=username).exists(): return JsonResponse({'code': 400, 'success': False, 'message': '用户名已存在'}) # 创建用户 user = User.objects.create_user(username=username, password=password) # 返回成功消息 return JsonResponse({'code': 200, 'success': True, 'message': '注册成功', 'username': username}) # 如果不是 POST 请求,则返回错误消息 return JsonResponse({'code': 405, 'success': False, 'message': '只支持 POST 请求'})
(3)子视图文件(在user app中创建一个urls)
from . import views from django.urls import path, re_path urlpatterns = [ path('login/', views.login_view, name='login'), path('register/', views.register_view, name='register'), ]
(4)在主路由中配置user app(主路由跟setting在同一个文件夹)
6.管理页面的前后端完整代码
(1)管理页面前端代码(业务范围页面)
<template> <div> <el-row style="height: 50px;"> <el-col :span="1" class="grid"> <el-button type="success" @click="showAddDialog" icon="el-icon-circle-plus-outline" size="mini" round >新增</el-button> </el-col> </el-row> <el-dialog title="新增" :visible.sync="addDialogVisible" width="42%"> <el-form :model="addFormData" :rules="addFormRules" ref="addForm" label-width="120px"> <el-form-item label="标题" prop="title"> <el-input v-model="addFormData.title"></el-input> </el-form-item> <el-form-item label="图片链接" prop="image_url"> <el-input v-model="addFormData.image_url"></el-input> </el-form-item> <el-form-item label="内容" prop="content"> <el-input v-model="addFormData.content"></el-input> </el-form-item> <el-form-item label="图片详情链接" prop="details_image_url"> <el-input v-model="addFormData.details_image_url"></el-input> </el-form-item> </el-form> <span slot="footer" class="dialog-footer"> <el-button @click="addDialogVisible = false">取 消</el-button> <el-button type="primary" @click="submitAddForm">确 定</el-button> </span> </el-dialog> <el-dialog title="编辑" :visible.sync="editDialogVisible" width="40%"> <el-form :model="editFormData" :rules="editFormRules" ref="editForm" label-width="100px"> <el-form-item label="标题" prop="title"> <el-input v-model="editFormData.title"></el-input> </el-form-item> <el-form-item label="图片链接" prop="image_url"> <el-input v-model="editFormData.image_url"></el-input> </el-form-item> <el-form-item label="内容" prop="content"> <el-input v-model="editFormData.content"></el-input> </el-form-item> <el-form-item label="图片详情链接" prop="details_image_url"> <el-input v-model="editFormData.details_image_url"></el-input> </el-form-item> </el-form> <span slot="footer" class="dialog-footer"> <el-button @click="editDialogVisible = false">取 消</el-button> <el-button type="primary" @click="submitEditForm">确 定</el-button> </span> </el-dialog> <el-table :data="tableData.slice((currentPage-1)*pagesize,currentPage*pagesize)" style="width: 100%; margin-top: 10px;" border stripe ref="multipleTable" tooltip-effect="dark" > <el-table-column label="序号" type="index" width="80px" align="center"></el-table-column> <el-table-column prop="title" width="100px" label="标题"></el-table-column> <el-table-column prop="image_url" width="150px" label="图片链接"></el-table-column> <el-table-column prop="content" width="120px" label="内容"></el-table-column> <el-table-column prop="details_image_url" label="图片详情链接"></el-table-column> <el-table-column width="190px" label="操作"> <template slot-scope="scope"> <el-button type="primary" icon="el-icon-edit" size="mini" @click="editBook(scope.row)">编辑</el-button> <el-button icon="el-icon-delete" size="mini" type="danger" @click="confirmDelete(scope.row)" >删除</el-button> </template> </el-table-column> </el-table> <div class="pagination"> <el-pagination @size-change="handleSizeChange" @current-change="handleCurrentChange" :current-page="currentPage" :page-sizes="[5, 10, 20, 40]" :page-size="pagesize" layout="total, sizes,prev, pager, next" :total="tableData.length" prev-text="上一页" next-text="下一页" ></el-pagination> </div> </div> </template> <script> import axios from "axios"; import { MessageBox } from "element-ui"; export default { name: "app", data() { return { currentPage: 1, // 默认显示页面为1 pagesize: 5, // 每页的数据条数 tableData: [], // 需要 data 定义一些,tableData 定义一个空数组,请求的数据都是存放这里面 addDialogVisible: false, activeIndex2: "1", addFormData: { title: "", image_url: "", content: "", details_image_url: "" }, addFormRules: { title: [{ required: true, message: "请输入标题", trigger: "blur" }], image_url: [ { required: true, message: "请输入图片地址", trigger: "blur" } ], content: [{ required: true, message: "请输入内容", trigger: "blur" }], details_image_url: [ { required: true, message: "请输入图片详情", trigger: "blur" } ] }, editDialogVisible: false, editFormData: { id: null, title: "", image_url: "", content: "", details_image_url: "" }, editFormRules: { title: [{ required: true, message: "请输入标题", trigger: "blur" }], image_url: [ { required: true, message: "请输入图片地址", trigger: "blur" } ], content: [{ required: true, message: "请输入内容", trigger: "blur" }], details_image_url: [ { required: true, message: "请输入图片详情", trigger: "blur" } ] } }; }, mounted() { this.getData(); }, methods: { getData() { axios.get(" http://127.0.0.1:8005/web_drf/coreBusinessView/").then( response => { console.log(response.data); this.tableData = response.data; }, error => { console.log("error"); } ); }, handleSizeChange(size) { this.pagesize = size; }, handleCurrentChange(currentPage) { this.currentPage = currentPage; }, showAddDialog() { this.addDialogVisible = true; }, submitAddForm() { this.$refs.addForm.validate(valid => { if (valid) { axios .post( " http://127.0.0.1:8005/web_drf/coreBusinessView/", this.addFormData ) .then(response => { console.log("新增成功", response.data); this.addDialogVisible = false; this.getData(); this.addFormData = { title: "", image_url: "", content: "", details_image_url: "" }; }) .catch(error => { console.error("新增失败", error); }); } }); }, confirmDelete(book) { MessageBox.confirm("确定删除该条记录吗?", "提示", { confirmButtonText: "确定", cancelButtonText: "取消", type: "warning" }) .then(() => { this.deleteBook(book); }) .catch(() => { // 取消删除操作 }); }, deleteBook(book) { const url = ` http://127.0.0.1:8005/web_drf/coreBusinessView/${book.id}/`; console.log(book.id); axios .delete(url) .then(response => { console.log("删除成功"); this.getData(); }) .catch(error => { console.error("删除失败", error); }); }, editBook(book) { this.editFormData = { ...book }; this.editDialogVisible = true; }, submitEditForm() { this.$refs.editForm.validate(valid => { if (valid) { const url = ` http://127.0.0.1:8005/web_drf/coreBusinessView/${this.editFormData.id}/`; axios .put(url, this.editFormData) .then(response => { console.log("编辑成功", response.data); this.editDialogVisible = false; this.getData(); }) .catch(error => { console.error("编辑失败", error); }); } }); } } }; </script> <style> .pagination { margin-top: 20px; text-align: center; } </style>
业务范围管理页面效果图
(2)业务范围管理系统后端代码views
from rest_framework.response import Response from rest_framework.views import APIView from rest_framework import serializers from webapp.models import CoreBusiness class coreBusinessSerializers(serializers.ModelSerializer): class Meta: model = CoreBusiness fields = '__all__' class coreBusinessView(APIView): def get(self, request): coreBusiness = CoreBusiness.objects.all() ser = coreBusinessSerializers(instance=coreBusiness, many=True) print(ser.data) return Response(ser.data) def post(self, request): ser = coreBusinessSerializers(data=request.data) if ser.is_valid(): CoreBusiness.objects.create(**ser.validated_data) return Response(ser.validated_data) else: return Response(ser.errors) class coreBusinessdetailview(APIView): def get(self, request, pk): coreBusiness = CoreBusiness.objects.get(pk=pk) ser = coreBusinessSerializers(instance=coreBusiness, many=False) return Response(ser.data) def put(self, request, pk): ser = coreBusinessSerializers(data=request.data) if ser.is_valid(): CoreBusiness.objects.filter(pk=pk).update(**ser.validated_data) return Response(ser.validated_data) else: return Response(ser.errors) def delete(self, request, pk): CoreBusiness.objects.get(pk=pk).delete() return Response('删除成功')
(3)配置子路由
(4)在主路由中配置该app(主路由跟setting在同一个文件夹)
7.创建数据库表
在任意一个models中都可以创建数据库表
from django.db import models # 联系我们表 class Contact(models.Model): id = models.AutoField(primary_key=True) company_name = models.CharField(max_length=100, verbose_name='公司名称') phone = models.CharField(max_length=20, verbose_name='电话') address = models.CharField(max_length=200, verbose_name='地址') email = models.CharField(max_length=255, verbose_name='邮箱') class Meta: db_table = 'contact'
创建表完成之后进行数据库的迁移,在项目的根目录下的控制台进行
python manage.py makemigrations python manage.py migrate
8.启动vue项目
npm run dev