Python Web 前后端分离 后台管理系统 Django+vue(完整代码)

avatar
作者
猴君
阅读量: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

9.打开浏览器访问http://localhost:8080/#/user/login/ 即可登录

    广告一刻

    为您即时展示最新活动产品广告消息,让您随时掌握产品活动新动态!