目录
路飞项目
企业项目类型
# 1 面向互联网用户:商城类项目
-微信小程序商城
-线上线下结合
# 2 面向互联网用户:二手交易类的
-咸鱼
-转转
-交友平台
# 3 公司内部项目,给某些用户定制项目:python写的重点
-运维管理,监控平台,资产管理
-oa系统
-打卡系统工资核算系统
-第三方公司做的:
-问卷网
-给医院 互联网,内部的项目
-银行 内部系统:信用卡审核系统,电话销售
-政府 :社保卡,
-钢材市场,商户
- 微信小程序订餐
-二维火 餐饮行业
-零售行业
-问卷网
-考试系统
-django+simpleui:二次定制
# 4 个人博客
# 5 内容收费站
-掘金
# 6 房屋租赁
-青客
-蛋壳
-自如
项目开发流程
整体流程
-项目立项
-需求调研分析
# 互联网项目
-需求调研和分析:产品经理设计出来的
-在这个阶段,产品经理负责进行需求调研和分析的工作,通过对目标用户、市场定位、竞品分析等的调研,明确项目的功能需求和业务逻辑
# 传统软件
-需求调研和分析:市场人员,开发 跟客户对接
-项目经理,产品经理在这个阶段,市场人员和开发人员与客户进行沟通和对接,了解客户的需求,并将其转化为具体的需求说明。
在此过程中,需要确保对客户需求的准确理解和详尽记录,形成需求说明书作为后续开发的依据
-原型设计:产品经理 根据需求说明书
通过设计出可交互的原型图,以便更好地展示项目的功能和用户界面,以及对项目进一步迭代和改进提供参考
-Axure,墨刀
-懂业务
-分任务开发
# 在这个阶段,项目团队根据项目的需求和规划进行任务分配,并开始各自负责的开发工作
-前端团队
# 根据原型图设计切图,负责设计项目的界面及视觉效果
-UI设计
-前端写代码(pc,小程序,移动端)
-后端团队
-架构,数据库设计
-分任务开发:用户,商品板块
-联调测试
#在各小组分别完成任务后,进行联合调试和测试。
-项目测试
-项目上线到测试库,测试环境
-测试人员,点击
-项目上线
-运维,维护
-用户有新需求,改bug
-上线新版本 v4.0.1
针对于开发流程
-开新项目,先开会,设计技术选型
-产品,原型图做好了
-老大在项目管理平台(禅道)分配任务给我
-进入到管理平台就能看到任务,相关功能的原型图
-需求,原型图,实现的效果
-开发---有不明白的需求,找产品对接----》自测
-提交到版本仓库(git,svn)
-所有都开发完了,分支合并
-跟前端联调
-发版:
-如果是老项目
-老大在项目管理平台(禅道)分配任务给我
-进入到管理平台就能看到任务,相关功能的原型图
-需求,原型图,实现的效果
-开发---有不明白的需求,找产品对接----》自测
-提交到版本仓库(git,svn)
-所有都开发完了,分支合并
-跟前端联调
-发版:
禅道:https://www.zentao.net/
路飞项目需求
# 线上销售课程的
-商城
-知识付费类
# 需求
-首页功能
-轮播图接口
-推荐课程接口(没写)
-用户功能
-用户名密码登录
-手机号验证码登录
-发送手机验证码
-验证手机号是否注册过
-注册接口
-课程列表功能
-课程列表接口
-排序,过滤,分页
-课程详情
-课程详情接口
-视频播放功能
-视频托管(第三方,自己平台)
-下单功能
-支付宝支付:生成支付链接,付款,回调修改订单状态
-购买成功功能
pip永久换源
# Windows
1、文件管理器文件路径地址栏敲:%APPDATA% 回车,快速进入 C:\Users\电脑用户\AppData\Roaming 文件夹中
2、新建 pip 文件夹并在文件夹中新建 pip.ini 配置设置文件
3、在pip.ini文件中输入以下内容
[global]
index-url = https://mirrors.aliyun.com/pypi/simple
[install]
use-mirrors =true
mirrors =https://mirrors.aliyun.com/pypi/simple
trusted-host =mirrors.aliyun.com
# mac配置或linux
1、在用户根目录下 ~ 下创建 .pip 隐藏文件夹,如果已经有了可以跳过
-- 打开terminal,敲 cd
-- mkdir ./.pip
2、进入 .pip 隐藏文件夹并创建 pip.conf 配置文件
-- cd ~/.pip && touch pip.conf
3、新增 pip.conf 配置文件内容
[global]
index-url = https://pypi.tuna.tsinghua.edu.cn/simple
[install]
use-mirrors = true
mirrors = https://pypi.tuna.tsinghua.edu.cn/simple
trusted-host = pypi.tuna.tsinghua.edu.cn
虚拟环境
# 作用
1、使不同应用开发环境相互独立
2、环境升级不影响其他应用,也不会影响全局的python环境
3、防止出现包管理混乱及包版本冲突
# 什么是虚拟环境,为什么要有它?它解决了什么问题
-写了个项目,使用djagno2.x版本---> django2.x装在了解释器上
-后来又有个项目,使用使用djagno3.x版本---> django3.x装在解释器上
-以后要打开第一个项目运行,需要卸载django3,安装django2
-每个项目都用自己独立的环境,装的模块相互不影响 =>虚拟环境
# 虚拟环境搭建方案:
1.Virtualenv:第三方,用的多
2.pipenv:官方的
使用Pipenv创建
Pipenv(官方工具):
Pipenv是Python官方推荐的虚拟环境管理工具,它集成了pip、venv和其他功能,并提供更便捷的方式来创建和管理虚拟环境。
以下是使用Pipenv创建虚拟环境的步骤:
# 安装Pipenv
命令如下:
pip install pipenv
创建虚拟环境:在项目文件夹中,使用下面的命令创建并激活虚拟环境:
pipenv shell
安装依赖包:在激活的虚拟环境中,可以使用Pipenv来安装项目所需的依赖包。例如:
pipenv install django==3.0
注意:
Pipenv会自动将依赖包保存到Pipfile文件中,并生成一个对应的Pipfile.lock文件来锁定依赖包的版本。
退出虚拟环境:您可以使用以下命令退出虚拟环境:
exit
# 总结:
无论是使用Virtualenv还是Pipenv,都可以解决多项目不同Python版本和依赖包的隔离问题。
Virtualenv是第三方库,使用广泛且成熟稳定;
而Pipenv是Python官方推荐的工具,提供更便捷的方式来管理虚拟环境和依赖包
使用Virtualenv创建
pycharm创建
见下图
-一般放在项目路径下:venv文件夹
-lib文件夹---》site-package--》虚拟环境装的模块,都会放在这里
-scripts--》python,pip命令
其他项目如何使用这个虚拟环境
# 本地创建了虚拟环境,其他项目如何使用这个虚拟环境
-pycharm>设置>项目>Python解释器>添加本地解释器>系统解释器>...>找到创建的虚拟环境>venv\Scripts\python.exe--->关联上即可
见下图
cmd创建
使用命令方式,创建管理虚拟环境
# 一 安装模块
cmd以管理员身份
1.pip3 install virtualenv # 装它就可以使用虚拟环境
-virtualenv.exe # 是用来创建虚拟环境的,在python38 Scripts中可查看
2.pip3 install virtualenvwrapper-win # 方便我们使用命令操作虚拟环境
-virtualenvwrapper.bat # 更方便的操作虚拟环境(win的批处理文件)
-virtualenvwrapper.sh # mac,linux下
# 二 配置环境变量
1.在d盘根路径创建一个文件夹:D:\Virtualenvs # 以后命令创建的虚拟环境,都放在这个文件夹下便于管理
2.配置环境变量:
控制面板 => 系统和安全 => 系统 => 高级系统设置 => 环境变量 => 系统变量 => 点击新建 => 填入变量名与值 =>确定
变量名:WORKON_HOME 变量值:自定义存放虚拟环境的绝对路径
WORKON_HOME: D:\Virtualenvs
# 三 关掉cmd窗口,重启
创建虚拟环境到配置的WORKON_HOME路径下
# 选取默认Python环境创建虚拟环境:
-- mkvirtualenv 虚拟环境名称
# 基于某Python环境创建虚拟环境:
-- mkvirtualenv -p python2.7 虚拟环境名称
-- mkvirtualenv -p python38 虚拟环境名称
eg:mkvirtualenv -p python2.7 lqz
在终端工作的命令
# 1、创建虚拟环境到配置的WORKON_HOME路径下
# 选取默认Python环境创建虚拟环境:
-- mkvirtualenv 虚拟环境名称
# 基于某Python环境创建虚拟环境:
-- mkvirtualenv -p python2.7 虚拟环境名称
-- mkvirtualenv -p python3.6 虚拟环境名称
# 2、查看已有的虚拟环境
-- workon
# 3、使用某个虚拟环境
-- workon 虚拟环境名称
# 4、进入|退出 该虚拟环境的Python环境
-- python | exit()
# 5、为虚拟环境安装模块
-- pip或pip3 install 模块名
# 6、退出当前虚拟环境
-- deactivate
# 7、删除虚拟环境(删除当前虚拟环境要先退出)
-- rmvirtualenv 虚拟环境名称 或者直接删文件夹是一样的
后端项目
后端项目创建
# 1 使用命令创建luffy项目虚拟环境
mkvirtualenv -p python38 luffy
# 2 安装django
pip install django==3.1.12
pip install djangorestframework
pip install pymysql
# 3 创建项目
方式一:命令
可将目录切换到指定目录下创建
E:\加油努力至少放个屁>django-admin startproject luffy_api
django-admin startproject luffy_api
方式二:pycharm
用pycharm打开项目luffy_api,并选择提前备好的虚拟环境luffy
见下图
# 4 创建app
后端配置
目录调整
"""
├── luffy_api
├── logs/ # 项目运行时/开发时日志目录 - 包
├── manage.py # 脚本文件
├── luffy_api/ # 项目主应用,开发时的代码保存 - 包
├── apps/ # 开发者的代码保存目录,以模块[子应用]为目录保存 - 包
├── libs/ # 第三方类库的保存目录[第三方组件、模块] - 包
├── settings/ # 配置目录 - 包
├── dev.py # 项目开发时的本地配置
└── prod.py # 项目上线时的运行配置
├── urls.py # 总路由
└── utils/ # 多个模块[子应用]的公共函数类库[自己开发的组件]
└── scripts/ # 保存项目运营时的脚本文件 - 文件夹
"""
# 将原本的settings.py改名为dev.py并移到settings包中,上线时在settings包再创建prod.py
配置开发环境
1、 修改manage.py
# 报错
django项目运行,要先加载settings.py(dev.py),执行的是 python manage.py runserver, 一旦把dev.py 移动到settings文件夹下后,配置文件中BASE_DIR路径变了,apps拼接的路径也变了,要相应的修改
# 解决
修改manage.py 中 os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'luffy_api.settings.dev')
-pycharm运行,可能会报错
-修改启动配置,删除之前的django-server,再创建一个,它会自动关联虚拟环境
-或配置文件中,找到django,指定配置文件(见下图)
2、 创建app
python manage.py startapp home # 在哪执行,app就创建在哪里,所以要切到apps目录下创建app
命令cd luffy_api
命令cd apps
命令python ../../manage.py startapp home
3、 在dev.py注册app
-在INSTALLED_APPS 直接写app的名字,会报错,报模块找不到的错误---》
"""
No module named 'home'报错原因:
1 模块就是没有
2 不在环境变量中
3 自己写了一个,跟它同名
"""
-解决方式:
方式一:注册luffy_api.apps.home #应用在apps目录下
INSTALLED_APPS = [
'luffy_api.apps.home',
]
方式二:只需要把apps路径加入到环境变量即可
# 把apps文件夹加入环境变量,以后注册app,直接写名字即可
sys.path.insert(0, str(BASE_DIR))# 要str一下,以后导入模块,路径短一些
sys.path.insert(0, os.path.join(BASE_DIR, 'apps'))
5、 上线后配置
wsgi.py,asgi.py ,配置文件也要改---》后面上线才用到
# wsgi.py
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'luffy_api.settings.prod')
# asgi.py
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'luffy_api.settings.prod')
6、 验证现在配置文件用的是dev.py
# from django.conf import settings
# print(settings) # luffy_api.settings.dev
- dev.py
BASE_DIR = Path(__file__).resolve().parent.parent
# 把apps文件夹加入环境变量,以后注册app,直接写名字即可
import os
sys.path.insert(0, str(BASE_DIR))
sys.path.insert(0, os.path.join(BASE_DIR, 'apps'))
"""配置文件中输出结果:
BASE_DIR = Path(__file__).resolve().parent.parent
# print(BASE_DIR) # E:\加油努力至少放个屁\luffy_api\luffy_api,因为咱们把dev移动到settings文件夹下了,因为以后代码,都在小luffy_api下,我们就以这个文件夹作为根
print(sys.path)#'E:\\加油努力至少放个屁\\luffy_api'
sys.path.insert(0,BASE_DIR)
print(sys.path) #('E:/加油努力至少放个屁/luffy_api/luffy_api')
sys.path.insert(0, os.path.join(BASE_DIR, 'apps'))
print(sys.path) #'E:\\加油努力至少放个屁\\luffy_api\\luffy_api\\apps'
"""
在写项目直接导入utils文件夹也不''错误提示''的方法
国际化
- dev.py
# 修改dev.py文件内容
LANGUAGE_CODE = 'zh-hans'
TIME_ZONE = 'Asia/Shanghai'
USE_TZ = False
封装logger
# django 默认使用 python原生的日志模块,咱们选择它
-以后不要再用print输出了,都用日志输出
-print输出,上线也会有输出,如果用日志,日志有级别,上线后把级别调高,你开发阶段的输出就不再打印了
# 开发阶段debug模式》输出info
# 上线阶段调成error模式》错误信息才记录
# 可以使用第三方 logru 公司里可能会用
# django中集成日志
1. 复制日志配置到dev.py中
LOGGING = {
'version': 1,
'disable_existing_loggers': False,
'formatters': {
'verbose': {
'format': '%(levelname)s %(asctime)s %(module)s %(lineno)d %(message)s'
},
'simple': {
'format': '%(levelname)s %(module)s %(lineno)d %(message)s'
},
},
'filters': {
'require_debug_true': {
'()': 'django.utils.log.RequireDebugTrue',
},
},
'handlers': {
'console': {
# 实际开发建议使用WARNING
'level': 'DEBUG', # 控制台只显示DEBUG以上,就是Info开始
'filters': ['require_debug_true'],
'class': 'logging.StreamHandler',
'formatter': 'simple'
},
'file': {
# 实际开发建议使用ERROR
'level': 'INFO', #文件中只显示INFO以上,从WARNING
'class': 'logging.handlers.RotatingFileHandler',
# 日志位置,日志文件名,日志保存目录必须手动创建,注:这里的文件路径要注意BASE_DIR代表的是小luffyapi
'filename': os.path.join(os.path.dirname(BASE_DIR), "logs", "luffy.log"),
# 日志文件的最大值,这里我们设置300M
'maxBytes': 300 * 1024 * 1024,
# 日志文件的数量,设置最大日志数量为10
'backupCount': 10,
# 日志格式:详细格式
'formatter': 'verbose',
# 文件内容编码
'encoding': 'utf-8'
},
},
# 日志对象
'loggers': {
'django': {
'handlers': ['console', 'file'],
'propagate': True, # 是否让日志信息继续冒泡给其他的日志处理系统
},
}
}
2. 在utils下新建 common_logger.py
复制以下到common_logger.py中
import logging
logger = logging.getLogger('django')
3. 在想使用日志的位置,导入直接使用即可,日志有级别,控制台和文件中打印的日志级别是不一样的
from utils.common_logger import logger
class LoggerView(APIView):
def get(self, request):
# 以后不要再用print输出了,都用日志输出
logger.info('info级别')
logger.warn('warn级别')
logger.warning('warning级别')
logger.error('error级别')
logger.critical('critical级别')
logger.debug('debug级别')
return Response('看到我了')
- utils/common_logger.py
import logging
logger = logging.getLogger('django')
- views.py
from rest_framework.views import APIView
from utils.common_logger import logger
class LoggerView(APIView):
def get(self, request):
# 以后不要再用print输出了,都用日志输出
logger.info('info级别')
logger.warn('warn级别')
logger.warning('warning级别')
logger.error('error级别')
logger.critical('critical级别')
logger.debug('debug级别')
return Response('看到我了')
封装全局异常
- utils/common_exception.py
##### 1 写一个函数(只要走到这,程序出异常了--》记录日志--》越详细越好)
from rest_framework.views import exception_handler
from rest_framework.response import Response
from utils.common_logger import logger
def common_exception_handler(exc, context):
res = exception_handler(exc, context)
if res: # 有值:drf的异常,处理了,格式不是咱们想要的
err = res.data.get('detail') or res.data or '未知错误,请联系系统管理员'
response = Response({'code': 888, 'msg': '请求异常-drf:%s' % err})
else: # 其他异常,没有处理,自己处理格式
response = Response({'code': 999, 'msg': '请求异常-其他:%s' % str(exc)})
# 记录日志,越详细越好, 请求错误:请求地址是:%s,请求方式是:%s,请求用户ip地址是:%s,错误是:%s,执行的视图函数是:%s
request = context.get('request')
path = request.get_full_path()
method = request.method
ip = request.META.get('REMOTE_ADDR')
user_id = request.user.pk or '未登录用户'
err = str(exc)
view = str(context.get('view'))
logger.error(
'请求错误:请求地址是:%s,请求方式是:%s,请求用户ip地址是:%s,用户id是:%s,错误是:%s,执行的视图函数是:%s' % (
path, method, ip, user_id, err, view))
return response
- dev.py
##### 2 在配置文件中配置一下
REST_FRAMEWORK = {
'EXCEPTION_HANDLER': 'utils.common_exception.common_exception_handler',
}
- views.py
from rest_framework.views import APIView
from rest_framework.exceptions import APIException
class ExceptionView(APIView):
def get(self, request):
# raise APIException('不让你看')
# raise Exception('随便')
5 / 0
return Response('看到我了')
封装Response
# 之前使用drf的Response,我们需要自己构造返回字典
return Response(data={code:100,msg:成功,result:[{},{}]})
return Response(data={code:100,msg:成功,token:asdasd,username:lqz})
# 我们封装 APIResponse,以后使用,效果如下
return APIResponse()---》{code:100,msg:成功}
return APIResponse(result=[{},{}])
return APIResponse(token=afasfd,username=lqz)
- utils/response.py
from rest_framework.response import Response
# APIResponse()
# APIResponse(result=[{},{}])
# APIResponse(token=afasfd,username=lqz)
# APIResponse(token=afasfd,username=lqz,status=201,headers={xx:'xx'})
class APIResponse(Response):
def __init__(self, code=100, msg='成功', status=None,
template_name=None, headers=None,
exception=False, content_type=None, **kwargs):
data = {'code': code, 'msg': msg}
if kwargs:
data.update(kwargs)
super().__init__(data=data, status=status, headers=headers, template_name=template_name, exception=exception,
content_type=content_type)
# Response(data=data, status=status, headers=headers)
- views.py
### 测试封装的Response
from utils.common_response import APIResponse
from rest_framework.response import Response
class ResponseView(APIView):
def get(self, request):
# return APIResponse(token='adfasdf', username='lqz')
# return APIResponse(code=101, msg='用户名密码错误')
# return APIResponse(result=[{'name': '西游记', 'price': 99}, {'name': '西游记233', 'price': 999}])
return Response(data={'code': 100, 'msg': '成功',
'result': [{'name': '西游记', 'price': 99}, {'name': '西游记233', 'price': 999}]})
- urls.py
from django.contrib import admin
from django.urls import path
from home import views # pycharm报错,但实际上不报错 ,只需要把加入到环境变量的路径都做成source root即可
urlpatterns = [
path('admin/', admin.site.urls),
path('logger/', views.LoggerView.as_view()),
path('exceptions/', views.ExceptionView.as_view()),
path('response/', views.ResponseView.as_view()),
]
数据库创建
# 使用mysql作为数据库
-mysql在win上安装步骤:https://zhuanlan.zhihu.com/p/571585588
# 1 创建数据库
root用户创建的权限很高,后续使用代码操作数据库不使用root用户,新建一个用户 luffy
-如果使用root用户,一旦密码泄露,所有库都不安全了
-如果新建一个luffy用户,只授予luffy库的权限,即便泄露了密码,只是这个库不安全了
create database luffy default charset=utf8;
# 2 为指定数据库配置指定账户
创建路飞用户,授予了luffy库所有表的所有权限
-查看用户:select user,host,authentication_string from mysql.user;
设置权限账号密码
# 授权账号命令:grant 权限(create, update) on 库.表 to '账号'@'host' identified by '密码'
-创建用户:
#配置任意ip都可以连入数据库的账户
grant all privileges on luffy.* to 'luffy'@'%' identified by 'Luffy123?';
#由于数据库版本的问题,可能本地还连接不上,就给本地用户单独配置
grant all privileges on luffy.* to 'luffy'@'localhost' identified by 'Luffy123?';
#刷新一下权限
flush privileges;
# 3 以后,操作luffy库,都用luffy用户登录,就不用root用户了
# 4 配置文件配置
项目中配置使用mysql数据库,使用luffy用户
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.mysql',
'NAME': 'luffy',
'HOST': '127.0.0.1',
'PORT': 3306,
'USER': 'luffy',
'PASSWORD': 'Luffy123?'
}
}
# 5 安装myslqclient
运行会报错pymysql兼容问题
-解决方式一:直接安装mysqlclient ---》win平台看人品,mac基本装不上,linux需要单独处理
-解决方式二:使用pymysql
-安装,在配置文件中加入:
import pymysql
pymysql.install_as_MySQLdb()
# 6 隐藏数据库密码
数据库的用户名,密码,都是直接写死在代码中的,如果咱们代码被泄露了,数据库也就被人看到了
方案:
-使用从环境变量中获取
-PATH: 任意路径下敲可执行文件能找到
-其它key value 是该机器的全局配置,可以直接拿到
-使用python代码拿到
#步骤一:
配置环境变量:
此电脑 => 属性 => 高级系统设置 => 环境变量 => 系统变量 => 点击新建 => 填入变量名与值 =>确定
变量名:LUFFY_USER 变量值:luffy
变量名:LUFFY_PWD 变量值:Luffy123?
#步骤二:配置文件配置
user=os.environ.get('LUFFY_USER','luffy')
password=os.environ.get('LUFFY_PWD','Luffy123?')
print(user)
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.mysql',
'NAME': 'luffy',
'HOST': '127.0.0.1',
'PORT': 3306,
'USER': user,
'PASSWORD': password
}
}
# 配置完环境变量,重启一下pycharm
# 如果环境变量没配置,就用默认的,如果配置了,就用配置的(项目上线时候,运维配置环境变量--->运维配置的环境变量的值---->开发根本不知道)
后端数据库用户表迁移
# 用户表,使用auth的user表,自己写
如果用的是auth的user表,必须在迁移之前,就定好,扩写的要写完
1.创建user模块
前提:在 luffy 虚拟环境下
1.1终端从项目根目录进入apps目录
cd luffyapi & cd apps
1.2创建用户app
python ../../manage.py startapp user
2. 创建用户表,user/models.py中
扩展user表
3. dev.py中注册
INSTALLED_APPS = [
''luffy_api.apps.user'',
]
AUTH_USER_MODEL='user.User'
4. 迁移命令
大luffyapi所在目录的终端
python manage.py makemigrations
python manage.py migrate
- user/models.py
from django.db import models
from django.contrib.auth.models import AbstractUser
class User(AbstractUser):
mobile=models.CharField(max_length=32,unique=True)
icon=models.ImageField(upload_to='icon',default='icon/default.png')
"""upload_to:指定图片上传的路径
default='avatar/default.png' 默认图片"""
class Meta:
db_table='luffy_user' #数据库的表以luffy_user开头
verbose_name='用户表'
verbose_name_plural=verbose_name # 在django后台展示的就是中文表名且没有后缀s
def __str__(self):
return self.username
前端项目创建
#创建vue前端:
vue create luffy_front
1.App.vue
<template>
<div id="app">
<router-view/>
</div>
</template>
2.删除AboutView.vue
3.删除AboutView.vue的路由在router/index.js
4.HomeView.vue
<template>
<div class="home">
<h1>首页</h1>
</div>
</template>
<script>
export default {
name: 'HomeView',
components: {
}
}
</script>
5.删除components的HelloWord.vue文件
6.配置运行/调试配置
添加新配置>脚本>serve
前端配置
1. 跟后端交互:axios
# 安装
cnpm install -S axios
以后想发送ajax请求,必须导入,使用
可以把axios放到vue实例中,以后任意组件中 this.$axios.get()
# main.js中加入
import axios from 'axios'
Vue.prototype.$axios = axios;
2. 操作cookie: vue-cookies
# 安装
cnpm install -S vue-cookies
# # main.js中加入
import cookies from 'vue-cookies'
Vue.prototype.$cookies = cookies;
3. ui库:elementui
# 安装
cnpm install -S element-ui
# main.js中加入
import ElementUI from 'element-ui';
import 'element-ui/lib/theme-chalk/index.css'; // 全局都会有这个css的样式
Vue.use(ElementUI);
4. 去掉 标签的默认样式
步骤1 编写全局css
assets/css/global.css
步骤2 main.js中导入
import '@/assets/css/global.css'
5. 全局配置文件
后期上线只需改这一个url地址
步骤1 js/settings.js
export default {
BASE_URL:'http://127.0.0.1:8000/'
}
步骤2 main.js中
import settings from "@/assets/js/settings";
Vue.prototype.$setting = settings
- assets/css/global.css
html, body, div, span, applet, object, iframe,
h1, h2, h3, h4, h5, h6, p, blockquote, pre,
a, abbr, acronym, address, big, cite, code,
del, dfn, em, img, ins, kbd, q, s, samp,
small, strike, strong, sub, sup, tt, var,
b, u, i, center,
dl, dt, dd, ol, ul, li,
fieldset, form, label, legend,
table, caption, tbody, tfoot, thead, tr, th, td,
article, aside, canvas, details, embed,
figure, figcaption, footer, header, hgroup,
menu, nav, output, ruby, section, summary,
time, mark, audio, video {
margin: 0;
padding: 0;
border: 0;
font-size: 100%;
font: inherit;
vertical-align: baseline;
}
/* HTML5 display-role reset for older browsers */
article, aside, details, figcaption, figure,
footer, header, hgroup, menu, nav, section {
display: block;
}
body {
line-height: 1;
}
ol, ul {
list-style: none;
}
blockquote, q {
quotes: none;
}
blockquote:before, blockquote:after,
q:before, q:after {
content: '';
content: none;
}
table {
border-collapse: collapse;
border-spacing: 0;
}
- js/settings.js
export default {
BASE_URL:'http://127.0.0.1:8000/'
}
- main.js
import Vue from 'vue'
import App from './App.vue'
import router from './router'
import store from './store'
Vue.config.productionTip = false
// 1 axios 配置
import axios from 'axios'
Vue.prototype.$axios = axios;
// 2 vue-cookies 配置
import cookies from 'vue-cookies'
Vue.prototype.$cookies = cookies;
// 3 elementui 配置
import ElementUI from 'element-ui';
import 'element-ui/lib/theme-chalk/index.css'; // 全局都会有这个css的样式
Vue.use(ElementUI);
// 4 使用 global css
// 配置全局样式
import '@/assets/css/global.css'
// 5 全局配置
import settings from "@/assets/js/settings";
Vue.prototype.$settings = settings
new Vue({
router,
store,
render: h => h(App)
}).$mount('#app')
跨域问题
,浏览器就会报错
请求正常发送成功,服务端也响应了,但是回来到浏览器的时候,报错,被浏览器的同源策略拦截了
# 解决方式:
CORS(跨域资源共享)---》是一个后端技术--》后端只需要在响应头中加入固定的响应头,前端就不禁止了
# CORS请求分成两类(浏览器发送请求之前判断)
-简单请求:只发送一次请求,就是真正的请求
# 只要同时满足以下两大条件,就属于简单请求。
1 请求方法是以下三种方法之一:
HEAD
GET
POST
2 HTTP的头信息不超出以下几种字段:
Accept
Accept-Language
Content-Language
Last-Event-ID
Content-Type:只限于三个值application/x-www-form-urlencoded、multipart/form-data、text/plain
-非简单请求:先发送一个options 预检请求,服务端如果写了cors,再发送真正的请求,如果没有写cors,浏览就不再发送真正的请求了
自定义中间件解决跨域
- utils/common_middleware.py
from django.utils.deprecation import MiddlewareMixin
class CORSMiddleWare(MiddlewareMixin):
def process_response(self, request, response):
# 简单请求
response['Access-Control-Allow-Origin'] = '*' # 允许所有客户端
# 非简单请求
if request.method == 'OPTIONS':
# res['Access-Control-Allow-Methods'] = 'DELETE,PUT' #仅允许DELETE,PUT请求
response['Access-Control-Allow-Methods'] = '*' #允许所有请求方式
response['Access-Control-Allow-Headers'] = '*' #允许所有请求头
return response
- settings/dev.py
# 注册自定义中间件
MIDDLEWARE = [
...
'utils.common_middleware.CorsMiddleWare',
]
第三方解决跨域
# 1 下载
pip install django-cors-headers
# 安装之后django会自动被升级需要手动降级3.2版本后项目才能运行
# 2 注册app
INSTALLED_APPS = (
...
'corsheaders',
...
)
# 3 加中间件
MIDDLEWARE = [
...
'corsheaders.middleware.CorsMiddleware',
...
]
# 4 配置文件
CORS_ORIGIN_ALLOW_ALL = True # 相当于我们的['Access-Control-Allow-Origin'] = '*'
CORS_ALLOW_METHODS = (
'DELETE',
'GET',
'OPTIONS',
'PATCH',
'POST',
'PUT',
'VIEW',
)
CORS_ALLOW_HEADERS = (
'XMLHttpRequest',
'X_FILENAME',
'accept-encoding',
'authorization',
'content-type',
'dnt',
'origin',
'user-agent',
'x-csrftoken',
'x-requested-with',
'Pragma',
'token'
)
后台主页功能
软件开发模式
# 1 瀑布开发模式
-架构,数据库设计---》分任务开发(周期很长,可能半年)---》测试---》上线
# 2 敏捷开发(devops)
-架构设计--》很多板块
-开发某个版块,再设计相关板块的数据库 # 一周左右
-开发某个板块
-测试测试该板块
-运维上线该板块
-开发另一个版本
# 根据原型图,分析出首页需要配合俩接口
-轮播图接口(要写)
-查询所有轮播图
-推荐课程接口(暂时先不写)
# 设计表:
轮播图表:Banner
# 写轮播图接口
-查询所有轮播图
Banner数据表
1.写一个基表BaseModel
# 这个表,只用来继承,不会再数据库生成表
2.写轮播图表
3.数据迁移
在大luffyapi路径下的终端
python manage.py makemigrations
python manage.py migrate
- utils/common_model.py
# 这个表,只用来继承,不会再数据库生成表
from django.db import models
class BaseModel(models.Model):
# 是否显示,记录插入时间,最后修改时间,是否删除(软删除),排序
# 课程表,也需要这些字段,需要继承这个表
created_time = models.DateTimeField(auto_now_add=True, verbose_name='创建时间')
updated_time = models.DateTimeField(auto_now=True, verbose_name='最后更新时间')
is_delete = models.BooleanField(default=False, verbose_name='是否删除')
is_show = models.BooleanField(default=True, verbose_name='是否上架')
orders = models.IntegerField(verbose_name='优先级')
class Meta: #是一个元类,用于设置类的元信息
abstract = True #设置了Meta类的抽象属性为True,这意味着该类不能被实例化,只能作为其他类的基类。
- home/models.py
from django.db import models
from utils.common_model import BaseModel
class Banner(BaseModel):
title = models.CharField(max_length=16, unique=True, verbose_name='名称')
image = models.ImageField(upload_to='banner', verbose_name='图片') # 地址,存放轮播图的地址
link = models.CharField(max_length=64, verbose_name='跳转链接')
info = models.TextField(verbose_name='详情') # 也可以用详情表,宽高出处
class Meta:
db_table = 'luffy_banner'
verbose_name_plural = '轮播图表'
def __str__(self):
return self.title
轮播图接口
视图
- home/views.py
from rest_framework.generics import GenericAPIView
from rest_framework.mixins import ListModelMixin
from rest_framework.generics import ListAPIView
from rest_framework.viewsets import ViewSetMixin, GenericViewSet
from .models import Banner
from .serializer import BannerSerializer
from django.conf import settings
# class BannerView(ViewSetMixin,ListAPIView): # 自动生成路由
# class BannerView(ViewSetMixin,GenericAPIView,ListModelMixin): # 自动生成路由
class BannerView(GenericViewSet, ListModelMixin): # 自动生成路由
queryset = Banner.objects.filter(is_delete=False, is_show=True).order_by('orders')[:settings.BANNER_COUNT] # 展示被软删除的、显示上架的、根据orders排序通过settings/user_settings.py配置的数量显示张数
serializer_class = BannerSerializer
序列化类
- home/serializer.py
from rest_framework import serializers
from .models import Banner
class BannerSerializer(serializers.ModelSerializer):
class Meta:
model = Banner
fields = ['id', 'image', 'link'] # 只返回给前端需要的字段名
路由
- urls.py
# 总路由
from django.contrib import admin
from django.urls import path
# from .apps.home import views
from django.urls import include
urlpatterns = [
path('admin/', admin.site.urls),
# path('loggers/', views.LoggerView.as_view()),
# path('exceptions/', views.ExceptionView.as_view()),
# path('response/', views.ResponseView.as_view()),
# path('cors/',views.cors_function),
path('api/v1/home/',include('home.urls')),
]
- home/urls.py
# 分路由
from django.contrib import admin
from django.urls import path
from home import views
from rest_framework.routers import SimpleRouter
from .views import BannerView
router = SimpleRouter()
# 127.0.0.1:8080/api/v1/home/banner/--- get
router.register('banner', BannerView, 'banner')
urlpatterns = [
]
urlpatterns += router.urls
配置文件
- settings/user_settings.py
# 用户自己配置,单独放到一个py文件中
BANNER_COUNT=3
- settings/dev.py
# 导入用户配置
from .user_settings import *
补充
# app 后端---》app一打开---》广告页---》可以滑动---》点击广告页---》一种浏览器打开页面跳转,一种情况打开一个他们app内的页面
# 原理就是轮播图接口
simpleui后台管理
任何项目,都会有后台管理,使用django的admin做后台管理使用simpleui美化
1. 下载simpleui---》app中注册
# 安装
pip install django-simpleui
# 在dev.py的应用中注册
INSTALLED_APPS = [
'simpleui',#加到最顶行
...
]
2. 创建一个超级用户,后台登录admin
python manage.py createsuperuser
Username: admin
Password: 123
3. admin中注册这个表
4. 后台中应用名显示中文
5. 轮播图放到meida文件夹下
默认情况admin文件上传到项目根路径下,需要配置:
MEDIA_ROOT = os.path.join(BASE_DIR, 'media')
配置后上传数据路径为luffy_api/media/banner
6. 后台管理录入数据
- home/admin.py
from django.contrib import admin
# Register your models here.
from .models import Banner
admin.site.register(Banner)
- apps/home/apps.py
from django.apps import AppConfig
class HomeConfig(AppConfig):
name = 'home'
verbose_name = '主页'
- apps/user/apps.py
from django.apps import AppConfig
class UserConfig(AppConfig):
default_auto_field = 'django.db.models.BigAutoField'
name = 'user'
verbose_name = '用户'
开放MEDIA接口
1.dev.py配置
MEDIA_ROOT = os.path.join(BASE_DIR, 'media')
2. 接口中不带meida 路径的: 配置文件中
MEDIA_URL = 'media/' # 取出的文件地址,拼接上media这个目录
3. 前端能访问图片
path('media/<path:path>', serve, {'document_root': settings.MEDIA_ROOT}),
- urls.py
from django.contrib import admin
from django.urls import path, include
from home import views # pycharm报错,但实际上不报错 ,只需要把加入到环境变量的路径都做成source root即可
from django.views.static import serve
from django.conf import settings
urlpatterns = [
path('admin/', admin.site.urls),
# path('logger/', views.LoggerView.as_view()),
# path('exceptions/', views.ExceptionView.as_view()),
# path('response/', views.ResponseView.as_view()),
# path('cors/', views.cors_function),
path('api/v1/home/', include('home.urls')),
# path('user/', include('user.urls')),
# 开启meida访问 meida/banner/banner2.png
path('media/<path:path>', serve, {'document_root': settings.MEDIA_ROOT}),
]
- settings/dev.py
MEDIA_ROOT=os.path.join(BASE_DIR,'media')
MEDIA_URL = 'media/'
前端主页功能
前端首页
- components/Header.vue
<template>
<div class="header">
<div class="slogan">
<p>老男孩IT教育 | 帮助有志向的年轻人通过努力学习获得体面的工作和生活</p>
</div>
<div class="nav">
<ul class="left-part">
<li class="logo">
<router-link to="/">
<img src="../assets/img/head-logo.svg" alt="">
</router-link>
</li>
<li class="ele">
<span @click="goPage('/free-course')" :class="{active: url_path === '/free-course'}">免费课</span>
</li>
<li class="ele">
<span @click="goPage('/actual-course')" :class="{active: url_path === '/actual-course'}">实战课</span>
</li>
<li class="ele">
<span @click="goPage('/light-course')" :class="{active: url_path === '/light-course'}">轻课</span>
</li>
</ul>
<div class="right-part">
<div>
<span>登录</span>
<span class="line">|</span>
<span>注册</span>
</div>
</div>
</div>
</div>
</template>
<script>
export default {
name: "Header",
data() {
return {
url_path: sessionStorage.url_path || '/',
}
},
methods: {
goPage(url_path) {
// 已经是当前路由就没有必要重新跳转
if (this.url_path !== url_path) {
this.$router.push(url_path);
}
sessionStorage.url_path = url_path;
},
},
created() {
sessionStorage.url_path = this.$route.path;
this.url_path = this.$route.path;
}
}
</script>
<style scoped>
.header {
background-color: white;
box-shadow: 0 0 5px 0 #aaa;
}
.header:after {
content: "";
display: block;
clear: both;
}
.slogan {
background-color: #eee;
height: 40px;
}
.slogan p {
width: 1200px;
margin: 0 auto;
color: #aaa;
font-size: 13px;
line-height: 40px;
}
.nav {
background-color: white;
user-select: none;
width: 1200px;
margin: 0 auto;
}
.nav ul {
padding: 15px 0;
float: left;
}
.nav ul:after {
clear: both;
content: '';
display: block;
}
.nav ul li {
float: left;
}
.logo {
margin-right: 20px;
}
.ele {
margin: 0 20px;
}
.ele span {
display: block;
font: 15px/36px '微软雅黑';
border-bottom: 2px solid transparent;
cursor: pointer;
}
.ele span:hover {
border-bottom-color: orange;
}
.ele span.active {
color: orange;
border-bottom-color: orange;
}
.right-part {
float: right;
}
.right-part .line {
margin: 0 10px;
}
.right-part span {
line-height: 68px;
cursor: pointer;
}
</style>
- components/Footer.vue
<template>
<div class="footer">
<ul>
<li>关于我们</li>
<li>联系我们</li>
<li>商务合作</li>
<li>帮助中心</li>
<li>意见反馈</li>
<li>新手指南</li>
</ul>
<p>Copyright © luffycity.com版权所有 | 京ICP备17072161号-1</p>
</div>
</template>
<script>
export default {
name: "Footer"
}
</script>
<style scoped>
.footer {
width: 100%;
height: 128px;
background: #25292e;
color: #fff;
}
.footer ul {
margin: 0 auto 16px;
padding-top: 38px;
width: 810px;
}
.footer ul li {
float: left;
width: 112px;
margin: 0 10px;
text-align: center;
font-size: 14px;
}
.footer ul::after {
content: "";
display: block;
clear: both;
}
.footer p {
text-align: center;
font-size: 12px;
}
</style>
- components/Banner.vue
<template>
<div class="banner">
<el-carousel height="400px">
<el-carousel-item v-for="item in 4" :key="item">
<img src="../assets/img/banner1.png" alt="">
</el-carousel-item>
</el-carousel>
</div>
</template>
<script>
export default {
name: "Banner"
}
</script>
<style scoped>
.el-carousel__item {
height: 400px;
min-width: 1200px;
}
.el-carousel__item img {
height: 400px;
margin-left: calc(50% - 1920px / 2);
}
</style>
- views/HomeView.vue
<template>
<div class="home">
<Header></Header>
<Banner></Banner>
<div>
<el-row>
<el-col :span="6" v-for="(o, index) in 8" :key="o" class="course_detail">
<el-card :body-style="{ padding: '0px' }">
<img src="http://photo.liuqingzheng.top/2023%2002%2022%2021%2057%2011%20/image-20230222215707795.png"
class="image">
<div style="padding: 14px;">
<span>热门课程</span>
<div class="bottom clearfix">
<time class="time">价格:199</time>
<el-button type="text" class="button">查看详情</el-button>
</div>
</div>
</el-card>
</el-col>
</el-row>
</div>
<img src="http://photo.liuqingzheng.top/2023%2003%2001%2016%2010%2034%20/1.png" alt="" width="100%" height="500px">
<Footer></Footer>
</div>
</template>
<script>
import Banner from "@/components/Banner";
import Footer from '@/components/Footer'
import Header from "@/components/Header";
export default {
name: 'HomeView',
components: {
Header, Footer, Banner
}
}
</script>
<style scoped>
.time {
font-size: 13px;
color: #999;
}
.bottom {
margin-top: 13px;
line-height: 12px;
}
.button {
padding: 0;
float: right;
}
.image {
width: 100%;
display: block;
}
.clearfix:before,
.clearfix:after {
display: table;
content: "";
}
.clearfix:after {
clear: both
}
.course_detail {
padding: 50px;
}
</style>
轮播图接口打通
<router-link不能跳外链
<a>可以跳外链
- components/Banner.vue
<template>
<div class="banner">
<el-carousel height="400px">
<el-carousel-item v-for="item in banner_list" :key="item.id">
<div v-if="item.link.indexOf('http')==0">
<a :href="item.link"><img :src="item.image" alt=""></a>
</div>
<div v-else>
<router-link :to="item.link"><img :src="item.image" alt=""></router-link>
</div>
</el-carousel-item>
</el-carousel>
</div>
</template>
<script>
export default {
name: "Banner",
data() {
return {
banner_list: []
}
},
created() {
this.$axios.get(this.$settings.BASE_URL + 'home/banner/').then(res => {
console.log(res.data)
if (res.data.code == 100) {
this.banner_list = res.data.result
} else {
this.$message({
showClose: true,
message: res.data.msg,
type: 'error'
});
}
})
}
}
var a = 'ss'
var res = a.indexOf('ss')
console.log(res)
</script>
<style scoped>
.el-carousel__item {
height: 400px;
min-width: 1200px;
}
.el-carousel__item img {
height: 400px;
margin-left: calc(50% - 1920px / 2);
}
</style>
导出项目依赖
# 在虚拟环境中,进到项目根路径,直接在终端执行命令
pip freeze > requirement.txt
导出项目所有安装的模块,包括安装模块所依赖的模块也在内
git忽略文件
# 忽略文件,在一开始就要忽略,如果已经被版本管理了,再忽略就没用了,如果之前没管,已经提交了
删除---》提交到版本库---》再在忽略文件中加入
# 咱们项目的忽略文件
.idea
logs/*.log
scripts
__pycache__
*.pyc
# 补充:
__pycache__:是对文件的一些缓存,只要文件启动就会创建这个文件夹
# 记住:迁移记录文件是否提交---》建议不提交
**/migrations/*.py # 忽略迁移记录
!**/migrations/__init__.py #不不忽略 __init__.py
- .gitignore
.idea
logs/*.log
scripts
__pycache__
*.pyc
标签:py,django,虚拟环境,luffy,import,path,Luffy
From: https://www.cnblogs.com/Super-niu/p/17765752.html