at 14:01:52 ❯ python manage.py createsuperuser # 创建超级用户的命令c
用户名 (leave blank to use 'mac'): mmm
电子邮件地址:
Password: # 密码输入时,是看不到的
Password (again):
密码长度太短。密码必须包含至少 8 个字符。
这个密码太常见了。
密码只包含数字。
Bypass password validation and create user anyway? [y/N]: y
Superuser created successfully.
django-admin startproject django14(项目名)
python manage.py startapp goods(APP名)
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'rest_framework', # drf框架
'corsheaders', # 跨域APP
'branch' # 自己的APP, 随着自己创建的APP名改变而改变
]
# 中间件
MIDDLEWARE = [
'django.middleware.security.SecurityMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'corsheaders.middleware.CorsMiddleware', # 添加跨域中间件
'django.middleware.common.CommonMiddleware',
# 'django.middleware.csrf.CsrfViewMiddleware', # 关闭csrf验证
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
]
CORS_ORIGIN_ALLOW_ALL = True # 允许所有源访问
# 指定图片上传的根路径时,media目录需要手动创建
MEDIA_URL = 'media/(文件名)' # 配置后期图片资源展示的url前缀
MEDIA_ROOT = os.path.join(BASE_DIR, 'media(文件名)') # 指定图片上传的根路径
python manage.py startapp app名
from django.contrib import admin
from django.urls import path, include
from django.conf import settings # 图片
from django.conf.urls.static import static # 图片
urlpatterns = [
path('admin/', admin.site.urls),
path('', include('branch.urls')), # 实现路由分发
] + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
# 上传的图片想要展示,需要做路由映射
部门:部门名称
class Branch(models.Model):
name = models.CharField(max_length=20, verbose_name='部门', unique=True) # unique=True 去重
员工:员工名称、所属部门、职位、年龄、入职日期、证件照片
class Staff(models.Model):
name = models.CharField(max_length=20, verbose_name='员工名称')
title = models.CharField(max_length=10, verbose_name='职位')
age = models.IntegerField(verbose_name='年龄')
time = models.DateField(auto_now_add=True, verbose_name='入职日期')
image = models.ImageField(upload_to='image/%y/%m/%d', verbose_name='证件照片')
branch = models.ForeignKey(to=Branch, on_delete=models.CASCADE, verbose_name='所属部门')
DateField(auto_now_add=True, verbose_name=‘创建日期’)
DateField(auto_now=True, verbose_name=‘更新日期’)
生成迁移文件
python manage.py makemigrations
生成表
python manage.py migrate
序列化器为了 简化 代码的编写过程
需要在自己在 子应用中,创建 序列化文件, 如 goods/serializers.py
from rest_framework.serializers import ModelSerializer
from branch.models import *
class BranchModelSerializer(ModelSerializer):
class Meta:
model = Branch
fields = '__all__'
class StaffModelSerializer(ModelSerializer):
class Meta:
model = Staff
fields = '__all__'
具体的实现过程, 在子应用中的
views.py
, 如goods/views.py
POST cate/ 表单数据
GET cate/
from rest_framework.response import Response
from rest_framework.views import APIView
from branch.serializers import *
# Create your views here.
# 分类
class BranchAPIView(APIView):
# 添加 POST cate/ 表单数据
def post(self, request):
# 1. 获取参数
data = request.data
# 2. 创建序列化器对象
ser = BranchModelSerializer(data=data)
# 3. 校验
ser.is_valid(raise_exception=True)
# 4. 保存
ser.save()
# 5. 返回响应
return Response(ser.data, status=201)
# 展示 GET cate/
def get(self, request):
# 1. 查询所有数据
branchs = Branch.objects.all()
# 2. 创建序列化器对象
ser = BranchModelSerializer(branchs, many=True)
# 3. 返回响应
return Response(ser.data)
删除 DELETE cate/id/
class BranchDestroyAPIView(APIView):
def delete(self, request, pk):
Branch.objects.filter(id=pk).delete()
return Response(status=204)
POST goods/ 表单参数
GET goods/?cate_id=1
class StaffAPIView(APIView):
# 添加 POST goods/ 表单参数
def post(self, request):
# 1. 获取参数
data = request.data
# 2. 创建序列化器对象
ser = StaffModelSerializer(data=data)
# 3. 校验
ser.is_valid(raise_exception=True)
# 4. 保存
ser.save()
# 5. 返回响应
return Response(ser.data, status=201)
# 展示 GET goods/?cate_id=1
def get(self, request):
# 1. 接收参数:分类id
branch_id = request.GET.get('branch_id') # 部门id
# 2. 根据外键:分类id,查询分类对应的商品
staffs = Staff.objects.filter(branch_id=branch_id)
# 3. 创建序列化器对象
ser = StaffModelSerializer(staffs, many=True)
# 4. 返回响应
return Response(ser.data)
访问上传的图片,网址:
http://127.0.0.1:8000/ + meida/ + 真正的图片路径
删除商品 DELETE goods/id/
class GoodsDestroyAPIView(APIView):
def delete(self, request, pk):
Goods.objects.filter(id=pk).delete()
return Response(status=204)
搜索:
- 前端发送参数
- 后端接收参数
- 根据参数进行过滤查询
- 将结果使用序列化器解析
- 将结果返回给前端
- 前端接收结果,循环展示
from django.db.models import Q # 查询 # 视图
from rest_framework.views import APIView # API
from rest_framework.response import Response # 返回
from goods.serializers import * # 导app名.序列化器
class SearchAPIView(APIView):
def get(self, request):
# 1. 接收参数
text = request.GET.get('text') # 获取text输入框, 和前端vue一致
# 2. 根据分类名或商品名的关键字进行模糊查询
goods = Goods.objects.filter(Q(name__contains=text) | Q(cate__name__contains=text) )
# 3. 创建序列化器解析
ser = GoodsModelSerializer(goods, many=True)
# 4. 返回结果
return Response(ser.data)
在子路由goods/urls.py
中,对当前app的视图做路由匹配
from django.urls import path
from goods.views import *
urlpatterns = [
# 127.0.0.1:8000/branch/
path('branch/', BranchAPIView.as_view()), # 部门的添加和展示
# 127.0.0.1:8000/staff/
path('staff/', StaffAPIView.as_view()), # 员工的添加和展示
# 127.0.0.1:8000/show/1/
path('show/<int:pk>/', ShowAPIView.as_view()) # 删除详细
# 127.0.0.1:8000/branch/?text=人工智能
path('search/', SearchAPIView.as_view()), # 搜索
]
vue init webpack vue14 # 需要联网下载项目模板
vue init webpack vue14 --offline # 离线创建项目,必须是本地之前已经有过项目模板时,才能使用
> Use cached template at ~/.vue-templates/webpack
? Project name (vue14) # 项目名称,可以默认回车
? Project description (A Vue.js project) # 项目描述,可以默认回车
? Author # 项目作者, 默认回车即可
? Vue build (Use arrow keys) # 代表项目打包编译配置项,默认回车即可
❯ Runtime + Compiler: recommended for most users
Runtime-only: about 6KB lighter min+gzip, but templates (or any Vue-specific HTML) are ONLY allowed in .
vue files - render functions are required elsewhere
? Install vue-router? (Y/n) y # 是否安装路由模块,必须输入 y,代表安装
? Use ESLint to lint your code? (Y/n) n # 是否开启 eslint规则检查代码规范性,不建议开启,输入n
? Set up unit tests ? (Y/n) n # 建议 输入n
? Setup e2e tests with Nightwatch? (Y/n) n # 建议输入n
? Should we run `npm install` for you after the project has been created? (recommended) (Use arrow keys) # 询问使用哪种方式安装 基本依赖包, 建议使用上下键 选择 第三项
Yes, use NPM
Yes, use Yarn
❯ No, I will handle that myself
提示如下信息,说明项目创建成功
# Project initialization finished!
# ========================
To get started:
cd vue14
npm install (or if using yarn: yarn)
npm run dev
# 先进入项目
cd vue14
# 使用 cnpm 联网安装基本依赖包
cnpm install
# 使用cnpm 联网安装 axios
cnpm install axios --save
node_modules
文件夹复制到 当前的 Vue项目中使用webstrom打开Vue项目, 接下来启动项目
npm run dev
在 src/main.js
中添加 axios配置
import axios from 'axios' // 导入axios模块
axios.defaults.baseURL = 'http://127.0.0.1:8000/' // 设置axios请求的默认域名
Vue.prototype.$axios = axios // 全局挂载axios
<template>
<div>
//1. 使用v-model获取表单数据
部门名称:<input type="text" v-model="name">
// 2. 点击按钮,触发对应的方法
<button @click="add">添加</button>
</div>
</template>
<script>
export default {
name: "branch",
data() {
return {
name:''
}
},
methods:{
// 3. 在方法中,先构建表单数据,再使用axios提交数据
add(){ // 添加
let data = new FormData();
data.append('name',this.name)
this.$axios.post('branch/', data)
.th在这里插入代码片en(resp=>{ // 成功
console.log(resp.data)
})
.catch(err=>{ // 失败返回
console.log(err.response.data)
})
}
}
}
// 出错后,可以使用console.log(resp.data)进行找错
</script>
change
事件,来获取图片内容<template>
<div>
员工名称:<input type="text" v-model="name"><br>
职位:<input type="text" v-model="title"><br>
年龄:<input type="text" v-model="age"><br>
入职日期:<input type="text" v-model="time"><br>
//1.4 选中图片时,触发change事件,执行对应的方法
证件照片:<input type="file" @change="getImage"><br>
// getImage获取的名字
所属部门:
<select v-model="branch">
// 1.3 在下拉框的选项中循环展示
<option :value="branch.id" v-for="branch in branchs">{{branch.name}}</option>
</select>
// 2. 点击添加按钮,触发方法
<button @click="add">添加</button>
</div>
</template>
<script>
<script>
export default {
name: "staff",
data(){return{
name:'',
title:'',
age:'',
time:'',
image:'',
branch:'',
branchs:[] // 空列表
}},
methods:{
// 1.1 使用axios的get请求,请求所有分类
get_branch(){
this.$axios.get('branch/') // 前端分类的路由
.then(resp=>{
this.branchs = resp.data // 列表
})
},
// 1.5 在当前的方法中,获取图片对象,赋值给 image变量
getImage(e){ // 图片
// 当文件选择框 选中文件时,会触发change事件, 执行对应的方法, 该方法会有一个形参e, e就代表当前的单元素
this.image = e.target.files[0]
},
// 3. 在方法中,打包表单数据,然后使用axios的post请求提交数据,接收响应
add(){ // 添加
let data = new FormData();
data.append('name',this.name)
data.append('title',this.title)
data.append('age',this.age)
data.append('time',this.time)
data.append('image',this.image)
data.append('branch',this.branch)
this.$axios.post('staff/', data) // 前端商品的路由
.then(resp=>{
console.log(resp.data) // 成功返回
})
.catch(err=>{
console.log(err.response.data) // 失败返回
})
}
},
mounted() {
// 1.2 在生命周期的钩子函数中挂载,让请求,自动执行
this.get_branch();
}
}
</script>
<style scoped>
</style>
<template>
<div>
<h3 v-for="branch in branchs"> // 分类在列表里
{{branch.id}} //非跳转
//对每个分类名,使用 超链接,点击跳转到商品列表页面,传递 分类id-->
<router-link :to="{name:'staff_show', query:{'bid': branch.id}}">{{branch.name}}</router-link> <!--要跳转的-->
</h3>
</div>
</template>
<script>
export default {
name: "branch_show",
data(){return{
branchs:[] // 空列表
}},
methods:{
get_staff(){
this.$axios.get('branch/') // 类的路由
.then(resp=>{
this.branchs = resp.data // 列表
})
}
},
mounted() { // 钩子挂载
this.get_staff();
}
}
</script>
<style scoped>
</style>
<template>
<div>
<h3 v-for="staff in staffs"> //循环列表
{{staff.id}}
<router-link :to="{name:'show', query:{'staff_id': staff.id}}">{{staff.name}}</router-link>
//跳转标签 要跳转的页面 传输的id 本页的id 展示出来的name
</h3>
</div>
</template>
<script>
export default {
name: "staff_show",
data(){return{
branch_id:'', // 定义id
staffs:[] // 列表
}},
methods:{
// 2. 定义方法,请求数据
get_staff(){
this.$axios.get('staff/?branch_id=' + this.branch_id)
.then(resp=>{
this.staffs = resp.data
})
}
},
mounted() {
// 1. 先获取分类id
this.branch_id = this.$route.query.bid
// 3. 挂载执行方法
this.get_staff();
}‘’‘
}
</script>
<style scoped>
</style>
<template>
<div>
//<!--1.获取用户输入关键字-->
<input type='text' v-model='text'> //查询输入框
//<!--2.点击按钮,执行搜索方法-->
<button @click="search">
搜索
</button>
//<!--4.循环展示所有商品-->
<h3 v-for="g in goods"> //随意命名 in 空列表
{{g.id}} == {{g.name}}=={{g.gender}}=={{g.cate_name}} <!--类里的name-->
</h3>
</div>
</template>
<script>
export default {
name: "Search",
data() {
return {
text: '', // 要查询的输入框
goods: [], // 空列表
}
},
methods: {
// 3. 在方法中,请求对应数据,不能挂载,点击按钮,才执行方法
search() {
this.$axios.get('search/?text=' + this.text)
.then(resp => {
this.goods = resp.data # 列表
})
}
}
</script>
class ShowAPIView(APIView):
def get(self, request, pk):
# try:
emp = Staff.objects.get(id=pk)
#except Exception as e:
# return Response({'msg': '找不到'}, status=404)
ser = StaffModelSerializer(emp) # emp 随意命名 见名识意
return Response(ser.data)
def delete(self, request, pk):
Staff.objects.filter(id=pk).delete()
return Response(status=204)
<template>
<div>
<h3>
{{ emp.id }} ||
{{ emp.name }} ||
{{ emp.title}} ||
{{ emp.age }} ||
{{ emp.time }} ||
//<!-- 图片 后端的端口 + g.图片 style设置宽高 -->
<img :src="emp.image" style="width: 250px;height: 400px">
</h3>
//<!--删除1. 点击删除按钮,触发方法, 同时传递分类的id作为参数 -->
<a href="" @click.prevent="del">删除</a> <!--prevent禁止跳转-->
//<!--括号里的意思是通过id指定删除-->
</div>
</template>
<script>
export default {
name: "show",
data(){return{
id: '', // 传参
emp:{ // 字典
name: '',
title: '',
age: '',
time: '',
image: '',
branch: ''
}
}},
methods: {
getEmp(){ // 获取
this.$axios.get(`show/${this.id}/`) // 根据商品id删除
.then(resp => {
console.log(resp.data)
this.emp.name = resp.data.name
this.emp.title = resp.data.title
this.emp.age = resp.data.age
this.emp.time = resp.data.time
this.emp.image = "http://127.0.0.1:8000/" + resp.data.image
this.emp.branch = resp.data.branch
})
},
// 删除2: 在方法中,发送 delete请求,根据id,删除分类, 删除成功,刷新页面
del(){
this.$axios.delete(`show/${this.id}/`) // 前端路由`/${id删除}/`
.then(resp => {
this.$router.push('branch_show/?branch_id=' + this.emp.branch)
}) // press_list 要跳转的页面
}
},
mounted() {
this.id = this.$route.query.staff_id // 挂载
this.getEmp() // 路由
}
}
</script>
<style scoped>
</style>
本篇仅供参考严禁侵权