下面将为你详细讲解“Django与Vue的完美结合——实现前后端的分离开发之后在整合的方法”。
1.前言
Django和Vue都是非常流行的Web开发框架,Django是一款开源的Python Web框架,Vue是一款渐进式JavaScript框架,常用于构建单页面应用(SPA)。在Web开发中,前端与后端的分离已经成为了主流趋势,而Django和Vue的完美结合,就是基于前后端分离的开发方式实现的。
2.前后端分离开发示例
通过一个实例来介绍前后端分离开发并实现前后端分离的方式。
2.1前端开发
1.安装Vue
npm install vue --save
2.新建Vue项目
vue init webpack frontend
3.在Vue项目中使用Axios请求后端接口
import axios from 'axios'
const BASE_URL = '/api/'
export function getUsers() {
return axios.get(`${BASE_URL}users/`)
}
export function getUser(id) {
return axios.get(`${BASE_URL}users/${id}/`)
}
2.2后端开发
1.安装Django
pip install django
2.新建Django项目
django-admin startproject backend
3.新建Django应用
cd backend/
python manage.py startapp users
4.编写Django视图
from django.http import JsonResponse
from django.shortcuts import get_object_or_404
from .models import User
def get_users(request):
users = User.objects.all()
data = [{'id': user.id, 'name': user.name, 'email': user.email} for user in users]
return JsonResponse(data, safe=False)
def get_user(request, user_id):
user = get_object_or_404(User, id=user_id)
data = {'id': user.id, 'name': user.name, 'email': user.email}
return JsonResponse(data, safe=False)
2.3前后端分离后的优势
前端与后端的分离开发方式有如下优势:
1.提高开发效率,各自开发负责自己的领域,降低了开发人员之间的耦合程度。
2.前端可以选择合适的框架进行开发,可以选择好用的UI组件库进行开发,提高了前端的体验。
3.后端与前端的数据交互更加清晰明了。
3.整合前后端示例
借助Webpack将前端资源打包,然后将打包后的资源嵌入Django模板中,在templates文件夹下新建一个index.html文件,可以像下面这样嵌入Webpack打包后的JavaScript和CSS文件:
{% load static %}
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1.0">
<title>Vue-Django Demo</title>
<link href="https://cdn.bootcdn.net/ajax/libs/font-awesome/5.13.1/css/all.min.css" rel="stylesheet">
<link href="{% static 'css/app.39428fbe.css' %}" rel="stylesheet">
</head>
<body>
<div id="app"></div>
<script src="{% static 'js/manifest.4099bc10.js' %}"></script>
<script src="{% static 'js/vendor.e1d11a23.js' %}"></script>
<script src="{% static 'js/app.3db97568.js' %}"></script>
</body>
</html>
其中{% static %}
是Django模板标签,用于获取静态文件的路径,静态文件可以放在static
文件夹中。
4.整合前后端完整代码
下面是整合前后端的示例代码:
4.1前端代码
// frontend/src/main.js
import Vue from 'vue'
import App from './App.vue'
import router from './router'
import store from './store'
import '@/assets/css/base.css'
Vue.config.productionTip = false
new Vue({
router,
store,
render: h => h(App)
}).$mount('#app')
// frontend/src/router/index.js
import Vue from 'vue'
import VueRouter from 'vue-router'
import Home from '@/views/Home.vue'
import Users from '@/views/Users.vue'
import UserDetail from '@/views/UserDetail.vue'
Vue.use(VueRouter)
const routes = [
{
path: '/',
name: 'home',
component: Home
},
{
path: '/users',
name: 'users',
component: Users
},
{
path: '/user/:id',
name: 'user-detail',
component: UserDetail
}
]
const router = new VueRouter({
routes
})
export default router
// frontend/src/store/index.js
import Vue from 'vue'
import Vuex from 'vuex'
import { getUsers, getUser } from '@/api/users'
Vue.use(Vuex)
export default new Vuex.Store({
state: {
users: [],
currentUser: null
},
getters: {
users: state => state.users,
currentUser: state => state.currentUser
},
mutations: {
setUsers(state, users) {
state.users = users
},
setCurrentUser(state, user) {
state.currentUser = user
}
},
actions: {
async getUsers({ commit }) {
const response = await getUsers()
const users = response.data
commit('setUsers', users)
},
async getUser({ commit }, id) {
const response = await getUser(id)
const user = response.data
commit('setCurrentUser', user)
}
}
})
// frontend/src/api/users.js
import axios from 'axios'
const BASE_URL = '/api/'
export function getUsers() {
return axios.get(`${BASE_URL}users/`)
}
export function getUser(id) {
return axios.get(`${BASE_URL}users/${id}/`)
}
// frontend/src/components/UserList.vue
<template>
<div>
<h2>用户列表</h2>
<ul class="list-group">
<li v-for="user in users" :key="user.id" class="list-group-item">
<router-link :to="{ name: 'user-detail', params: { id: user.id } }">{{ user.name }}</router-link>
</li>
</ul>
</div>
</template>
<script>
import { mapGetters } from 'vuex'
export default {
name: 'UserList',
computed: {
...mapGetters(['users'])
},
created() {
this.$store.dispatch('getUsers')
}
}
</script>
// frontend/src/components/UserDetail.vue
<template>
<div>
<h2>{{ user.name }}</h2>
<p>{{ user.email }}</p>
</div>
</template>
<script>
import { mapGetters } from 'vuex'
export default {
name: 'UserDetail',
computed: {
...mapGetters(['currentUser']),
user() {
return this.currentUser ? this.currentUser : {}
}
},
created() {
this.getUser()
},
methods: {
getUser() {
const id = this.$route.params.id
this.$store.dispatch('getUser', id)
}
}
}
</script>
// frontend/src/views/Users.vue
<template>
<div>
<UserList />
</div>
</template>
<script>
import UserList from '@/components/UserList.vue'
export default {
name: 'Users',
components: {
UserList
}
}
</script>
// frontend/src/views/Home.vue
<template>
<div class="home">
<h1>VUE - DJANGO DEMO</h1>
<p>这是一个使用Vue和Django实现的Web应用程序。代码已经托管在Github上,欢迎您的传送。</p>
<p><a href="https://github.com/Kevin-07/vue-django-demo/">查看 Github 代码</a></p>
</div>
</template>
<style>
.home {
margin-top: 50px;
text-align: center;
}
</style>
// frontend/src/App.vue
<template>
<div id="app">
<nav class="navbar navbar-expand-lg navbar-light bg-light">
<router-link class="navbar-brand" to="/">Vue-Django Demo</router-link>
<button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarNav" aria-controls="navbarNav" aria-expanded="false" aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span>
</button>
<div class="collapse navbar-collapse" id="navbarNav">
<ul class="navbar-nav mr-auto">
<li class="nav-item">
<router-link class="nav-link" to="/">首页</router-link>
</li>
<li class="nav-item">
<router-link class="nav-link" to="/users">用户列表</router-link>
</li>
</ul>
</div>
</nav>
<div class="container mt-3">
<router-view></router-view>
</div>
</div>
</template>
<script>
export default {
name: 'App'
}
</script>
<style>
/* Put your own stylesheet here */
</style>
// frontend/src/assets/css/base.css
body {
margin: 0;
padding: 0;
}
ul {
margin: 0;
padding: 0;
list-style-type: none;
}
a {
color: black;
text-decoration: none;
}
a:hover {
color: black;
text-decoration: none;
}
.list-group-item {
cursor: pointer;
}
4.2后端代码
# backend/backend/settings.py
INSTALLED_APPS = [
'users.apps.UsersConfig',
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
]
MIDDLEWARE = [
'django.middleware.security.SecurityMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.common.CommonMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
]
ROOT_URLCONF = 'backend.urls'
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [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',
],
},
},
]
WSGI_APPLICATION = 'backend.wsgi.application'
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.sqlite3',
'NAME': BASE_DIR / 'db.sqlite3',
}
}
LANGUAGE_CODE = 'zh-hans'
TIME_ZONE = 'Asia/Shanghai'
USE_I18N = True
USE_L10N = True
USE_TZ = True
static_url = '/static/'
MEDIA_URL = '/media/'
STATICFILES_DIRS = [
BASE_DIR / 'frontend' / 'dist' / 'static',
]
STATIC_ROOT = BASE_DIR / 'static'
MEDIA_ROOT = BASE_DIR / 'media'
# backend/backend/urls.py
from django.contrib import admin
from django.urls import path
from django.conf.urls.static import static
from django.conf import settings
from django.views.generic import TemplateView
urlpatterns = [
path('admin/', admin.site.urls),
]
api_patterns = ([
path('users/', include('users.urls')),
])
urlpatterns += api_patterns
urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
urlpatterns += static(settings.STATIC_URL, document_root=settings.STATIC_ROOT)
urlpatterns += [
path('', TemplateView.as_view(template_name='index.html')),
]
# backend/users/models.py
from django.db import models
class User(models.Model):
name = models.CharField(max_length=50)
email = models.EmailField()
def __str__(self):
return self.name
# backend/users/views.py
from django.http import JsonResponse
from django.shortcuts import get_object_or_404
from .models import User
def get_users(request):
users = User.objects.all()
data = [{'id': user.id, 'name': user.name, 'email': user.email} for user in users]
return JsonResponse(data, safe=False)
def get_user(request, user_id):
user = get_object_or_404(User, id=user_id)
data = {'id': user.id, 'name': user.name, 'email': user.email}
return JsonResponse(data, safe=False)
# backend/users/urls.py
from django.urls import path
from .views import get_users, get_user
urlpatterns = [
path('users/', get_users),
path('users/<int:user_id>/', get_user),
]
# backend/users/admin.py
from django.contrib import admin
from .models import User
class UserAdmin(admin.ModelAdmin):
list_display = ['id', 'name', 'email']
admin.site.register(User, UserAdmin)
# backend/users/apps.py
from django.apps import AppConfig
class UsersConfig(AppConfig):
name = 'users'
5.总结
通过上述示例可知,Django与Vue的完美结合,在前后端分离的基础上,结合Webpack将前端资源打包,然后将打包后的资源嵌入Django模板中,可以实现前后端的无缝衔接。在开发过程中,可以对前端和后端分别进行优化和管理,提高开发效率。同时,前后端分离的方式还可以实现前后端的部署与维护分离,对于复杂的应用程序具有较好的可维护性和扩展性。
本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:django与vue的完美结合_实现前后端的分离开发之后在整合的方法 - Python技术站