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

Play_Sai 2024-07-08 17:33:02 阅读 63

1.前后端分离的架构

在前后端分离的架构中,前端和后端分别作为独立的项目进行开发和部署。前端项目通过API与后端项目进行通信。

前端:使用Vue.js构建用户界面,调用后端提供的RESTful API获取和发送数据。后端:使用Django构建API,处理业务逻辑和数据存储

2.创建django项目及vue项目

创建app的时候需要进入项目的目录下  win10 cd xmmc

<code>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)解决跨域问题

<code>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">code>

<div class="login-container">code>

<el-card class="box-card" style="opacity: 0.9;">code>

<h2>登录</h2>

<el-form

:model="ruleForm"code>

status-icon

:rules="rules"code>

ref="ruleForm"code>

label-position="left"code>

label-width="70px"code>

class="login-form"code>

>

<el-form-item label="用户名" prop="uname">code>

<el-input v-model="ruleForm.uname"></el-input>code>

</el-form-item>

<el-form-item label="密码" prop="password">code>

<el-input

type="password"code>

v-model="ruleForm.password"code>

autocomplete="off"code>

></el-input>

</el-form-item>

</el-form>

<div class="btn-group">code>

<el-button type="primary" @click="submitForm('ruleForm')"code>

>登录</el-button

>

<el-button @click="resetForm('ruleForm')">重置</el-button>code>

<router-link to="/register">code>

<el-button style="margin-left:10px">注册</el-button>code>

</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(视图文件)

<code>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'),code>

path('register/', views.register_view, name='register'),code>

]

(4)在主路由中配置user app(主路由跟setting在同一个文件夹)

6.管理页面的前后端完整代码

(1)管理页面前端代码(业务范围页面)

<code><template>

<div>

<el-row style="height: 50px;">code>

<el-col :span="1" class="grid">code>

<el-button

type="success"code>

@click="showAddDialog"code>

icon="el-icon-circle-plus-outline"code>

size="mini"code>

round

>新增</el-button>

</el-col>

</el-row>

<el-dialog title="新增" :visible.sync="addDialogVisible" width="42%">code>

<el-form :model="addFormData" :rules="addFormRules" ref="addForm" label-width="120px">code>

<el-form-item label="标题" prop="title">code>

<el-input v-model="addFormData.title"></el-input>code>

</el-form-item>

<el-form-item label="图片链接" prop="image_url">code>

<el-input v-model="addFormData.image_url"></el-input>code>

</el-form-item>

<el-form-item label="内容" prop="content">code>

<el-input v-model="addFormData.content"></el-input>code>

</el-form-item>

<el-form-item label="图片详情链接" prop="details_image_url">code>

<el-input v-model="addFormData.details_image_url"></el-input>code>

</el-form-item>

</el-form>

<span slot="footer" class="dialog-footer">code>

<el-button @click="addDialogVisible = false">取 消</el-button>code>

<el-button type="primary" @click="submitAddForm">确 定</el-button>code>

</span>

</el-dialog>

<el-dialog title="编辑" :visible.sync="editDialogVisible" width="40%">code>

<el-form :model="editFormData" :rules="editFormRules" ref="editForm" label-width="100px">code>

<el-form-item label="标题" prop="title">code>

<el-input v-model="editFormData.title"></el-input>code>

</el-form-item>

<el-form-item label="图片链接" prop="image_url">code>

<el-input v-model="editFormData.image_url"></el-input>code>

</el-form-item>

<el-form-item label="内容" prop="content">code>

<el-input v-model="editFormData.content"></el-input>code>

</el-form-item>

<el-form-item label="图片详情链接" prop="details_image_url">code>

<el-input v-model="editFormData.details_image_url"></el-input>code>

</el-form-item>

</el-form>

<span slot="footer" class="dialog-footer">code>

<el-button @click="editDialogVisible = false">取 消</el-button>code>

<el-button type="primary" @click="submitEditForm">确 定</el-button>code>

</span>

</el-dialog>

<el-table

:data="tableData.slice((currentPage-1)*pagesize,currentPage*pagesize)"code>

style="width: 100%; margin-top: 10px;"code>

border

stripe

ref="multipleTable"code>

tooltip-effect="dark"code>

>

<el-table-column label="序号" type="index" width="80px" align="center"></el-table-column>code>

<el-table-column prop="title" width="100px" label="标题"></el-table-column>code>

<el-table-column prop="image_url" width="150px" label="图片链接"></el-table-column>code>

<el-table-column prop="content" width="120px" label="内容"></el-table-column>code>

<el-table-column prop="details_image_url" label="图片详情链接"></el-table-column>code>

<el-table-column width="190px" label="操作">code>

<template slot-scope="scope">code>

<el-button type="primary" icon="el-icon-edit" size="mini" @click="editBook(scope.row)">编辑</el-button>code>

<el-button

icon="el-icon-delete"code>

size="mini"code>

type="danger"code>

@click="confirmDelete(scope.row)"code>

>删除</el-button>

</template>

</el-table-column>

</el-table>

<div class="pagination">code>

<el-pagination

@size-change="handleSizeChange"code>

@current-change="handleCurrentChange"code>

:current-page="currentPage"code>

:page-sizes="[5, 10, 20, 40]"code>

:page-size="pagesize"code>

layout="total, sizes,prev, pager, next"code>

:total="tableData.length"code>

prev-text="上一页"code>

next-text="下一页"code>

></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

<code>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中都可以创建数据库表

<code>from django.db import models

# 联系我们表

class Contact(models.Model):

id = models.AutoField(primary_key=True)

company_name = models.CharField(max_length=100, verbose_name='公司名称')code>

phone = models.CharField(max_length=20, verbose_name='电话')code>

address = models.CharField(max_length=200, verbose_name='地址')code>

email = models.CharField(max_length=255, verbose_name='邮箱')code>

class Meta:

db_table = 'contact'

创建表完成之后进行数据库的迁移,在项目的根目录下的控制台进行

python manage.py makemigrations

python manage.py migrate

8.启动vue项目

npm run dev

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



声明

本文内容仅代表作者观点,或转载于其他网站,本站不以此文作为商业用途
如有涉及侵权,请联系本站进行删除
转载本站原创文章,请注明来源及作者。