美文网首页
使用Django开发需要用到的知识和技巧

使用Django开发需要用到的知识和技巧

作者: Dxes | 来源:发表于2020-01-12 22:36 被阅读0次

Django生产迁移和执行迁移的注意事项

第一次生成和迁移和执行迁移之后,数据库中会有一部分django自带的表,而我们每次迁移完成后,都有对应的迁移记录。如果你在想把迁移之后的表删除,在重新执行迁移,需要先在django_migratios这张表中删除对应的迁移记录,才可以再次迁移这张表。

record.png

在Django自带'django_user'这张表中保存着在控制台创建的超级管理员的账号信息。Django默认会将会话的数据写到表’django_session'表中。

tables.png

模糊查询和多条件查询

参数名 含义
__exact 表示精确查询
__contains 表示包含关系,相当于SQL中' %王%'
__startswith 表示以什么什么开头,相当于SQL中' 王%'
__endswith 表示以什么什么结尾,相当于SQL中' %王'
queryset = Record.objects.filter(car__carno__istarswith=carno)
# 查询在Recor模型的模型管理器(objects)里面查询car对象的carno属性(忽略大小写、以什么开头)的记录,返回一个查询集。

在Django中有个Q对象,可以用于多条件查询, 可以使用符号&或者|将多个Q()对象组合起来传递给filter(),exclude(),get()等函数 。

from django.db.models import Q

#  |    表示‘或者’的意思
#  &    表示’并且‘的意思
#  ~    表示‘非’的意思

#例如:
Q(car__carno__startswith='川A') | Q(car__owner__contains='王')
相当于SQL语句:
# select * from tb1 where carno like '川A%' or owner like  '%王%';这样的查询语句。

# 车牌或者车主姓名模糊查询查询
queryset = Record.objects.filter(
    Q(car__carno__istarswith=carno) |
    Q(car__owner__contains=carno)
)

分页器的使用

有的时候我们在页面中展示大量的数据,这样不仅给项目测试增加负担,也会为降低用户的体验感,而Django为我们提供了一个Paginator类来帮助我们管理分页数据。

分页器对象的属性:
属性 描述
object_list 查询到的数据(列表)
per_page 每一页要展示的内容
orphans=0 这是一个缺省参数,如果最后一页的数据小于这个值,会合并到上一页
allow_empty_first_page=True 允许首页为空,默认为True
分页器对象的方法
方法 描述
page 返回一个Page对象
count 返回对象列表(数据)的长度
num_pages 返回总页数
page_range 返回页码列表

Page对象

Page对象一般用来指定当前页
注意:Paginator对象是由我们进行示例化的,而Page对象在Paginator对象使用page方法时实现

Page对象的方法:

属性 描述
object_list 指定对象列表,包含当前页的对象
number 当前页面的页码
paginator 指对应的分页器对象
Page对象的属性
方法 描述
has_next 是否有下一页
has_previous 是否有上一页
has_other_pages 是否有上一页或下一页
next_page_number 返回下一页的页码
previous_page_number 返回上一页的页码
start_index 返回当前页起始的对象序号
end_index 返回当前页结束的对象序号
from django.core.paginator import Paginator
from django.db import DatabaseError
from django.db.models import Q
from django.http import JsonResponse
from django.shortcuts import render
from carsearch.models import Record


def search(request):
    """查询"""
    context = {
        'searched': False,
        'current_page': 1,
        'total_page': 0
    }
    if request.method == 'POST':
        carno = request.POST.get('carno', '')
        carno = carno.replace(' ', '').upper()
        context['carno'] = carno
        page = int(request.POST.get('page', '1'))
        size = int(request.POST.get('size', '4'))
        if carno:
            context['searched'] = True
            context['current_page'] = page
            # __exact: 精确查询
            # __contains: 字符串两头加%通配符的模糊查询
            # __startswith: 字符串后面加%通配符的模糊查询
            # __endswith: 字符串前面加%通配符查询
            # 注意参数前面加i表示查询的时候忽略大小写
            queryset = Record.objects.filter(car__car_no__startswith=carno)
            # 返回一个paginator对象,页面显示的记录的条数,和总条数
            paginator = Paginator(queryset, size)
            # 返回总页面数
            context['total_page'] = paginator.num_pages
            # 返回一个page对象
            context['page_obj'] = paginator.get_page(page)
    return render(request, 'index.html', context)

解决1+N查询

我们在调试项目的过程中,项目的性能往往是因为数据库的查询语句(关联查询)导致项目的性能上不去。

应用场景如下:

class Record(models.Model):
    """违章记录模型"""
    no = models.AutoField(primary_key=True, verbose_name='编号')
    # 与Car模型关联
    car = models.ForeignKey(to=Car, on_delete=models.PROTECT, db_constraint=False, db_column='con', verbose_name='车辆')
    offend_time = models.DateTimeField(verbose_name='违章时间')
    offend_place = models.CharField(max_length=256, verbose_name='违章地点')
    offend_reason = models.CharField(max_length=1000, verbose_name='违章原因')
    punish = models.CharField(max_length=256, verbose_name='处罚方式')
    dealed = models.BooleanField(default=False, verbose_name='是否受理')

    class Meta:
        db_table = 'tb_record'
        verbose_name = "违章记录"
        verbose_name_plural = '违章记录'

class Car(models.Model):
    """车辆模型表"""
    no = models.AutoField(primary_key=True, verbose_name='编号')
    car_no = models.CharField(max_length=10, verbose_name='车牌号', unique=True)
    owner = models.CharField(max_length=20, verbose_name='车主')
    type = models.IntegerField(
        choices=((1, '大型汽车'), (2, '小型汽车'), (3, '专用汽车'), (4, '小型汽车')),
        default=2, verbose_name='类型'
    )

    class Meta:
        db_table = 'tb_car'
        verbose_name = '车辆'
        verbose_name_plural = '车辆'
# view.py
def search(request):
    """查询"""
    context = {
        'searched': False,
    }
    if request.method == 'POST':
        # 从前端页面的请求中取到carno,取不到给空值
        carno = request.POST.get('carno', '')
        carno = carno.replace(' ', '').upper()
        context['carno'] = carno
        if carno:
            context['searched'] = True
            # 通过模型管理器,按照car对象的car_no(以什么开头)或者按照car对象的__owner属性(以什么开头)的查询Record模型中的记录
            queryset = Record.objects.filter(
                Q(car__car_no__startswith=carno) |
                Q(car__owner__startswith=carno))
    return render(request, 'index.html', context)

如果在查询过程中,我们想要显示车主,但是Record这个模型中并没有车主信息,这个时候就会产生一加N查询,他会将相同的记录查询多次。这样就大大降低了程序的性能。

sql.png

这种现象称为一加N查询要消除这种现象,只需要在查询的后面上

.select_related('关联字段') 用于一对多查询,

.prefetch_related('关联字段')用于多对多查询

 queryset = Record.objects.filter(
                Q(car__car_no__startswith=carno) |
                # 解决一加N查询,在查询后面加上.select_related()方法,一次性将Car关联的对象都放入返回的集合中
                Q(car__owner__startswith=carno)).select_related('car').order_by('-offend_time')
     

这样我们就解决了1+N查询

sql2.png

使用前端渲染(前后端分离)

在传统的Web应用开发中,大多数的程序员会将浏览器作为前后端的分界线。浏览器中为用户进行页面展示的部分叫前端,而将运行在服务器,为前端提供业务逻辑和数据准备的所有代码统称为后端。而前后端的分离开发,实际上时指前后端工程师约定好数据交互接口,并行的进行开发和测试,后端只提供数据,不做渲染。前端通过HTTP请求获取数据并且将数据渲染到页面中,这个工作是交给浏览器中的JavaScript代码来完成的

使用前后端分离开发的诸多好处:

​ 1.提升开发效率。 前后端分离以后,可以实现前后端代码的解耦,只要前后端沟通约定好应用所需接口以及接 口参数,便可以开始并行开发,无需等待对方的开发工作结束。在这种情况下,前后端工程师都可以只专注 于自己的开发工作,有助于打造出更好的团队。除此之外,在前后端分离的开发模式下,即使需求发生变 更,只要接口与数据格式不变,后端开发人员就不需要修改代码,只要前端进行变动即可。

​ 2.增强代码的可维护性。 前后端分离后,应用的代码不再是前后端混合,只有在运行期才会有调用依赖关系, 这样的话维护代码的工作将变得轻松愉快很多,再不会牵一发而动全身。当你的代码变得简明且整洁时,代 码的可读性和可维护性都会有质的提升。

​ 3.支持多终端和服务化架构。 前后端分离后,同一套数据接口可以为不同的终端提供服务,更有助于打造多终 端应用;此外,由于后端提供的接口之间可以通过HTTP(S)进行调用,有助于打造服务化架构(包括微服务)。

此处参考的昊叔的文档

返回JSON数据(前面的车辆违章查询实例)

def search(request):
    """查询"""
    # 有没有查询过,默认是False,当前页码1,总页数0,records空列表
    context = {
        'searched': False,
        'current_page': 1,
        'total_page': 0,
        'records':[],
    }
    # 拿车牌号
    carno = request.GET.get('carno', '')
    # 处理输入的车牌号,去掉空格,转换成大写
    carno = carno.replace(' ', '').upper()
    # 拿当前页的页码,如果没有,赋默认值1
    page = int(request.POST.get('page', '1'))
    # 如果拿到了车牌或者车主的信息
    if carno:
        # 将searched变为True
        context['searched'] = True
        # 通过Q对象用车牌号或者车主作为筛选条件查询,并且把Record关联的car对象也一起查询出来(主要是解决一加N查询问题)在利用违章时间(offend_time)进行降序排序。
        queryset = Record.objects.filter(
            Q(car__car_no__startswith=carno) |
            # 解决一加N查询,在查询后面加上.select_related()方法,一次性将Car关联的对象都放入返回的集合中
            Q(car__owner__startswith=carno)).select_related('car').order_by('-offend_time')
        # django自带的分页器,拿到分页器对象,每页最多显示5条数据
        paginator = Paginator(queryset, 5)
        # 通过分页器对象的num_pages属性可以拿到总页数
        context['total_page'] = paginator.num_pages
        # 通过get_page()这个方法,指定页码,就可拿到这一页的对象
        page_obj = paginator.get_page(page)
        # 通过这个页面对象的number属性 ,可以拿到当前页码
        context['current_page'] = page_obj.number
        records = []
        # 从当前页对象的object_list属性中遍历数据,将每一条记录组装成字典。
        for record in page_obj.object_list:
            records.append({
                'no': record.no,
                'carno': record.car.carno,
                'owner': record.car.owner,
                'time': record.offend_time,
                'place': record.offend_place,
                'reason': record.offend_reason,
                'punish': record.punish,
                'dealed': record.dealed 
            })
         # 将records列表添加到context字典里面
         context['records'] = records
            # 返回json数据
    return JsonResponse(context)

在view.py写好数据接口之后在urls.py添加上之后去浏览器查看接口数据,你会得到类似下面的结果.

# 添加url
urlpatterns = [
    ……
    path('search/', search),
]

得到的json数据:

{
    "searched": true,
    "current_page": 1,
    "total_page": 1,
    "records": [
            {
            "no": 6,
            "carno": "川A88888",
            "owner": "王大锤",
            "time": "2019-07-16T23:05:00+08:00",
            "place": "春熙路",
            "reason": "违章停车",
            "punish": "罚款200元人民币,扣除驾照分2分",
            "dealed": true
            }]
    …………        
}

这样后端的数据接口就写好了。

远端仓库的使用

如果在创建厂库的时候使用了readme初始化(不推荐使用),那么将本地代码上传到仓库的时候,需要先使用 git pull的命令将远端代码拉下来,并且需要加额外的参数:--allow-unrelated-histories。之后会弹出一个合并文件,不用管,直接wq保存退出就行了。最后在使用 git push -u origin master 将代码推到远端仓库中。

# 将远端仓库的代码拉到本地
git pull --allow-unrelated-histories origin master
# 将本地代码推到远端
git push -u origin master

有时在接手别人项目的时候,这个项目已经有很多个版本了,这时只需克隆最新的版本就行了。

# 从git@gitee.com:Dxes_ld_xh/djangocase.git克隆djangocase,取的别名为djangocase2

git clone --depth=1 git@gitee.com:Dxes_ld_xh/djangocase.git djangocase2   
git的常用命令
命令 作用
git init 初始化本地厂仓库
git add 文件/文件夹 / -A / . 添加文件或者所有本地文件到缓存区中
git status 查看当前git状态
git commit -m ‘提交信息' 将缓存区中的内容全部提交到git本地仓库
git log 查看提交日志
git reset --heard HEAD 让工作目录中的内容和仓库中的内容保持一致
git reset --heard HEAD^ 回到上一个版本
git reset --heard HEAD 版本号 回到指定的版本
git checkout 文件名 从暂存区中恢复工作目录中的内容(让工作区中的指定文件,回到上次提交的时候的状态)
git clone url 将远程仓库克隆到本地
git remote add origin 地址 关联远程仓库
git push [-u] origin master 将本地仓库的内容提交到远程仓库的master分之
git push origin 分支名 将本地仓库的内容提交到远程仓库对应的分支上, 如果分支不存在会自动创建
git pull 将远程仓库中的内容更新到本地仓库和工作区中
git branch [-a] 查看分之
git branch 分之名 创建分之
git checkout 分支名 切换分之
git checkout -b 分之名 切换并创建新的分之
git diff 分之1 分之2 查看两个分之之间的差异
git merge 分之名 让当前分之和指定分之进行合并

注意: 切换分之、push、pull,这些操作前要保证工作区是干净的clean

相关文章

  • 使用Django开发需要用到的知识和技巧

    Django生产迁移和执行迁移的注意事项 第一次生成和迁移和执行迁移之后,数据库中会有一部分django自带的表,...

  • iOS语音录制、转码及播放

    前言 由于业务需要,在开发过程中需要使用到语音方面的知识,并且在和Android同步开发时,需要用到转码。因此,语...

  • django-environ的使用及区分不同环境

    在使用Django框架进行项目开发时,我们会用到许多环境变量,为了方便环境变量的使用,我们选择使用Django-e...

  • Django入门

    1 Django安装和配置 为避免Python版本冲突,依然使用visual env来开发,安装Django仅需要...

  • Eclipse使用技巧

    在使用Eclipse开发代码过程用到的小技巧,各种功能配置的使用,可以有效提高使用舒适度和开发效率。 1.修改Ec...

  • Django-1入门

    简介 通过简单示例,使用django完成基本流程的开发,学习django的主要的知识点,在后续课程中会逐个知识点进...

  • 使用 django-mptt 实现树形结构

    在 Web 开发中,省/市/区(县)是经常需要用到的数据,而省/市/区(县)是一种层级关系。在使用 Django ...

  • djano笔记(八)认证

    1.用户认证 认证需要用到auth模块 使用django自带的User模型 在django shell里先创建用户...

  • Python Django Flatpages踩坑篇

    基础知识 要使用Flatpages,需要至少读完Django官方文档Tutorial 1-4,安装Django环境...

  • Chrome中克服CORS限制

    在使用React+Django REST开发中,前端需要通过jquery获取本地Django API数据,遇到了这...

网友评论

      本文标题:使用Django开发需要用到的知识和技巧

      本文链接:https://www.haomeiwen.com/subject/elwwactx.html