Django
Django
Django2.2.12
- 创建项目:
django-admin startproject <projectname>
- 创建应用:
django-admin startapp <appname>
或python manage.py startapp <appname>
- app注册:在INSTALLED_APPS里添加
- templates路径注册:settings.py中,在TEMPLATES中的DIRS添加路径
os.path.join(BASE_DIR,'templates')
- static路径注册:
settings.py中,STATICFILES_DIRS = [os.path.join(BASE_DIR, 'static'), ]
- views.py:视图函数,接受浏览器请求,给用户响应
- 配置urls.py:path函数
- 前端渲染和后端渲染
- 前端渲染:在浏览器中完成渲染操作,前端通过Ajax请求获得后端提供的数据,通过JavaScript代码用数据渲染页面
- 后端渲染:在服务器端用Python程序完成, 把前端提供的静态页改造成模板页,把动态内容换成占位符,通过Python程序把动态内容填入模板页
- 连接数据库:
DATABASES = { 'default' : { 'ENGINE' : 'django.db.backends.mysql', 'USER' : '', 'NAME' : '', 'HOST' : '', 'PORT' : 3306, 'PASSWORD' : '', 'CHARSET' : 'utf8', 'TIME-ZONE' : 'Asia/Shanghai', } }
创建Django超级用户
- 创建超级用户:
python manage.py createsuperuser
- 在admin.py中注册数据库
class SubjectAdmin(admin.ModleAdmin):
<详细内容>admin.site.register(Subject,SubjectAdmin)
模型
模型创建表(正向工程)
- 生成迁移文件:
python manage.py makemigrations
- 生成表:
python manage.py migrate
- 在pycharm进入交互式环境中操作表:
python manage.py shell
表创建模型(逆向工程)
python manage.py inpectdb > <指定文件>
:将数据库中的表,生成模型
元属性
1.abstract = True
:抽象类不能创建对象,专门用于继承
2. verbose_name
:一个更可读的名字
3. verbose_name_plural
:一个更可读的名字的复数形式
4. db_table
:表的名字
base64编码
- 前端页面中:
- 编码:
btoa('')
- 解码:
atob('')
- 编码:
- 在后端中:
- 编码:
base64.encode(b'')
- 解码:
base64.decode()
- 编码:
Django自带的用户管理界面
- 注册:
- 创建超级用户:
python manage.py createsuperuser
- 注册模型(admin.py):
- 设置需要的样式:class
SubjectAdmin(admin.ModelAdmin)
: - 添加SubjectAdmin:
admin.site.register(Subject,SubjectAdmin)
- 设置需要的样式:class
- 创建超级用户:
数据库查询
- Django自带的查询功能遇到关联查询时较为繁琐所以在查询两个有外键关联的表时,可以设置:
- 多对一或一对一关联时可以使用select_related方法解决"1+N查询问题"
- 多对多关联可以使用prefetch_related方法解决"1+N查询问题"
- 可以使用QuerySet对象的order_by方法对查询结果按照哪个字段进行排序
- filter多条件查询:
- subject =
Subject.objects.filter(条件).filter(条件)..
subject = Subject.objects.filter(Q(条件) | (条件))..
- subject =
中间件(拦截过滤器)日志记录
- 作用:
- 拦截异常
- Django中间件与之前学过的装饰器在写法和用途上都非常接近,
通过Django项目配置文件的MIDDLEWARE可以配置使用中间件
- 使用:
- 中间件
from django.shortcuts import render # 通过Python标准库logging模块的getLogger获取日志记录器 logger = logging.getLogger('django.request') def exception_handler_middleware(view_func): def wrapper(request, *args, **kwargs): # 拦截用户请求做出相应的处理 resp = view_func(request, *args, **kwargs) # 拦截服务器给用户的响应做出相应的处理 # 检测响应状态码是不是5xx ---> 服务器程序出问题 # 2xx ---> 请求成功 # 3xx ---> 重定向(给浏览器发送一个新的URL,让浏览器重新请求新的URL) # 4xx ---> 请求有问题 # ~ 404 ---> Not Found # ~ 401 ---> Unauthorized # ~ 403 ---> Forbidden # ~ 405 ---> 请求方法不支持 # ~ 400 ---> 请求数据格式不对 # 5xx ---> 服务器程序有问题 if str(resp.status_code).startswith('5'): # 生成一条日志记录这个错误以便通过追踪日志定位错误解决问题 # 写日志的时候需要根据日志的级别调用不同的方法 # debug --- 调试信息 # info --- 普通(正常)信息 # warning --- 警告信息 # error --- 错误信息 # critical --- 致命错误信息 logger.error(f'{request.method} {request.path} ---> {resp.status_code}') # 渲染专门定制的优雅的错误页给用户 return render(request, 'error.html') return resp return wrapper
- 在setting.py中注册中间件
MIDDLEWARE = [ 'search.middlewares.exception_handler_middleware', ]
- 配置日志(官网复制())
LOGGING = { 'version': 1, 'disable_existing_loggers': False, # 日志格式化器 'formatters': { 'verbose': { 'format': '{levelname} {asctime} {module} {process:d} {thread:d} {message}', 'style': '{', }, 'simple': { 'format': '{levelname} {message}', 'style': '{', }, }, # 配置日志处理器 'handlers': { 'file': { 'level': 'WARNING', 'class': 'logging.FileHandler', 'filename': os.path.join(BASE_DIR, 'error.log'), 'formatter': 'verbose', }, 'console': { 'class': 'logging.StreamHandler', 'formatter': 'simple', }, }, # 配置日志记录器 'loggers': { 'django.db': { 'handlers': ['file', 'console'], 'level': 'DEBUG', 'propagate': True, }, }, }
读写EXcel
-
- Office 2010 —> Excel 2010 —> openpyxl
- Office 2003 —> Excel 2003 —> xlwt / xlrd
-
wb = Workbook() sheet = wb.active col_names = ('H1', 'H2', 'H3', 'H4', 'H5', 'H6') for index, col in enumerate('ABCDEF'): sheet[f'{col}1'] = col_names[index] row = 2 for record in queryset: sheet[f'A{row}'] = record.h1 sheet[f'B{row}'] = record.h2 sheet[f'C{row}'] = record.h3 sheet[f'D{row}'] = record.h4 sheet[f'E{row}'] = record.h5 sheet[f'F{row}'] = record.h6 row += 1 buffer = BytesIO() wb.save(buffer) resp = HttpResponse(buffer.getvalue()) # 设置响应头指定MIME类型(告诉浏览器服务器返回的内容类型) resp['content-type'] = 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' filename = quote('<NAME>.xlsx') # 设置响应头指定内容处置方式(inline-内联打开;attachment-下载) # 如果要设置中文文件名,需要将中文处理成百分号编码,否则不能写到响应头 resp['content-disposition'] = f'attachment; filename*=utf-8\'\'{filename}' return resp
制作统计图表
- 在官网(https://echarts.apache.org/zh/index.html)调用echarts
前端接入通过JavaScript实现图表效果渲染 - 后端提供JSON数据 —> JsonResponse
使用原SQL语句查询
- 得到数据库连接:
conn = get_connection()
- 获取游标:
cursor = conn.cursor()
- 输入SQL语句:
cursor.execute('')
- 得到查询结果:
cursor.fetchone() / fetchmany() / fetchall()
redis储存数据
-
安装Django-redis:
pip install djang-redis
-
配置redis:
# 配置缓存服务器 CACHES = { "default" : { "BACKEND" : "django_redis.cache.RedisCache", "LOCATION" : "redis://ip地址/数据库", "OPTIONS" : { "CLIENT_CLASS" : "django_redis.client.DefaultClient", 'PASSWORD' : '密码' } } } # 配置将session放到缓存中 SESSION_ENGINE = "django.contrib.sessions.backends.cache" SESSION_CACHE_ALIAS = "default" # 关闭浏览器清除缓存 SESSION_EXPIPRE_ATBROWSER_CLOSE = True # 保存时间 SESSION_COOKIE_AGE = 86400
-
什么时候使用redis储存数据
- 数据:体量不大,访问频率极高,不怎么变化 —> 热数据
- 如果关系型数据某张表更新特别频繁,那么可以把表直接放到Redis
-
使用
- 缓存页面,加装饰器(只能用于函数):
@cache_page(timeout='<保存时间>',cache='<缓存位置>')
- 缓存类:```@method_decorator(decorator=cache_page(timeout=’<保存时间>’,cache=’<缓存位置>’),name=’<装饰的名字>’)
- 缓存页面,加装饰器(只能用于函数):
django-rest-framework
-
辅助写出rest风格的数据接口
-
模型:
class Subject(models.Model): """学科""" no = models.AutoField(primary_key=True, verbose_name='编号') name = models.CharField(max_length=50, verbose_name='名称') intro = models.CharField(max_length=2000, verbose_name='介绍') is_hot = models.BooleanField(default=False, verbose_name='是否热门') create_date = models.DateField(null=True, verbose_name='成立日期') def __str__(self): return f'{self.no}: {self.name}' class Meta: db_table = 'tb_subject' verbose_name = '学科' verbose_name_plural = '学科' class Teacher(models.Model): """老师""" no = models.AutoField(primary_key=True, verbose_name='编号') name = models.CharField(max_length=20, verbose_name='姓名') sex = models.BooleanField(default=True, choices=((True, '男'), (False, '女')), verbose_name='性别') birth = models.DateField(verbose_name='出生日期', help_text='出生日期的格式:yyyy/MM/dd') intro = models.CharField(max_length=2000, verbose_name='介绍') photo = models.CharField(max_length=512, verbose_name='照片') good_count = models.IntegerField(default=0, db_column='gcount', verbose_name='好评数') bad_count = models.IntegerField(default=0, db_column='bcount', verbose_name='差评数') subject = models.ForeignKey(to=Subject, on_delete=models.PROTECT, db_column='sno', verbose_name='所属学科') class Meta: db_table = 'tb_teacher' verbose_name = '老师' verbose_name_plural = '老师'
-
方法一:FBV
- 创建一个serializers.py文件
- 在serializers.py中设置相关类
class SubjectSimpleSerializer(serializers.ModelSerializer) : class Meta : model = Subject fields = ('no', 'name')
- 在views.py中
def subject(request): queryset = subject.objects.all() serialize = SubjectSimpleSerializer(queryset,many=True) return Response(serializer.data)
-
方法二:CBV
- 创建一个serializers.py文件
- 在serializers.py中设置相关类
class SubjectSimpleSerializer(serializers.ModelSerializer) : class Meta : model = Subject fields = ('no', 'name')
- 在view.py中
class SubjectViewSet(ModelViewSet): queryset = subject.objects.all() serializer_class = SubjectSimplerializer
- 在setting注册
INSTALLED_APPS=[ 'rest_framework', ]
- 在urls中设置路径
router = DefaultRouter() router.register('subject', SubjectViewSet) urlpatterns += router.urls
-
获取外键的值
- 如Teacher要获得关联外键的subject的属性
重复上面方法一或方法二的操作
在serializers.py中设置:
class SubjectSimpleSerializer(serializers.ModelSerializer) : subject_id=serializers.CharField(source='subject.mane') class Meta : model = Subject fields = ('no', 'name','subject_id')
source=’<外联表名>.<相关属性>’
- 如Teacher要获得关联外键的subject的属性
(后面补充)