使用Django開發(fā)需要用到的知識和技巧

Django生產(chǎn)遷移和執(zhí)行遷移的注意事項

第一次生成和遷移和執(zhí)行遷移之后,數(shù)據(jù)庫中會有一部分django自帶的表,而我們每次遷移完成后,都有對應的遷移記錄。如果你在想把遷移之后的表刪除,在重新執(zhí)行遷移,需要先在django_migratios這張表中刪除對應的遷移記錄,才可以再次遷移這張表。

record.png

在Django自帶'django_user'這張表中保存著在控制臺創(chuàng)建的超級管理員的賬號信息。Django默認會將會話的數(shù)據(jù)寫到表’django_session'表中。

tables.png

模糊查詢和多條件查詢

參數(shù)名 含義
__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()等函數(shù) 。

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)
)

分頁器的使用

有的時候我們在頁面中展示大量的數(shù)據(jù),這樣不僅給項目測試增加負擔,也會為降低用戶的體驗感,而Django為我們提供了一個Paginator類來幫助我們管理分頁數(shù)據(jù)。

分頁器對象的屬性:
屬性 描述
object_list 查詢到的數(shù)據(jù)(列表)
per_page 每一頁要展示的內(nèi)容
orphans=0 這是一個缺省參數(shù),如果最后一頁的數(shù)據(jù)小于這個值,會合并到上一頁
allow_empty_first_page=True 允許首頁為空,默認為True
分頁器對象的方法
方法 描述
page 返回一個Page對象
count 返回對象列表(數(shù)據(jù))的長度
num_pages 返回總頁數(shù)
page_range 返回頁碼列表

Page對象

Page對象一般用來指定當前頁
注意:Paginator對象是由我們進行示例化的,而Page對象在Paginator對象使用page方法時實現(xiàn)

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: 字符串前面加%通配符查詢
            # 注意參數(shù)前面加i表示查詢的時候忽略大小寫
            queryset = Record.objects.filter(car__car_no__startswith=carno)
            # 返回一個paginator對象,頁面顯示的記錄的條數(shù),和總條數(shù)
            paginator = Paginator(queryset, size)
            # 返回總頁面數(shù)
            context['total_page'] = paginator.num_pages
            # 返回一個page對象
            context['page_obj'] = paginator.get_page(page)
    return render(request, 'index.html', context)

解決1+N查詢

我們在調(diào)試項目的過程中,項目的性能往往是因為數(shù)據(jù)庫的查詢語句(關聯(lián)查詢)導致項目的性能上不去。

應用場景如下:

class Record(models.Model):
    """違章記錄模型"""
    no = models.AutoField(primary_key=True, verbose_name='編號')
    # 與Car模型關聯(lián)
    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這個模型中并沒有車主信息,這個時候就會產(chǎn)生一加N查詢,他會將相同的記錄查詢多次。這樣就大大降低了程序的性能。

sql.png

這種現(xiàn)象稱為一加N查詢要消除這種現(xiàn)象,只需要在查詢的后面上

.select_related('關聯(lián)字段') 用于一對多查詢,

.prefetch_related('關聯(lián)字段')用于多對多查詢

 queryset = Record.objects.filter(
                Q(car__car_no__startswith=carno) |
                # 解決一加N查詢,在查詢后面加上.select_related()方法,一次性將Car關聯(lián)的對象都放入返回的集合中
                Q(car__owner__startswith=carno)).select_related('car').order_by('-offend_time')
     

這樣我們就解決了1+N查詢

sql2.png

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

在傳統(tǒng)的Web應用開發(fā)中,大多數(shù)的程序員會將瀏覽器作為前后端的分界線。瀏覽器中為用戶進行頁面展示的部分叫前端,而將運行在服務器,為前端提供業(yè)務邏輯和數(shù)據(jù)準備的所有代碼統(tǒng)稱為后端。而前后端的分離開發(fā),實際上時指前后端工程師約定好數(shù)據(jù)交互接口,并行的進行開發(fā)和測試,后端只提供數(shù)據(jù),不做渲染。前端通過HTTP請求獲取數(shù)據(jù)并且將數(shù)據(jù)渲染到頁面中,這個工作是交給瀏覽器中的JavaScript代碼來完成的

使用前后端分離開發(fā)的諸多好處:

? 1.提升開發(fā)效率。 前后端分離以后,可以實現(xiàn)前后端代碼的解耦,只要前后端溝通約定好應用所需接口以及接 口參數(shù),便可以開始并行開發(fā),無需等待對方的開發(fā)工作結束。在這種情況下,前后端工程師都可以只專注 于自己的開發(fā)工作,有助于打造出更好的團隊。除此之外,在前后端分離的開發(fā)模式下,即使需求發(fā)生變 更,只要接口與數(shù)據(jù)格式不變,后端開發(fā)人員就不需要修改代碼,只要前端進行變動即可。

? 2.增強代碼的可維護性。 前后端分離后,應用的代碼不再是前后端混合,只有在運行期才會有調(diào)用依賴關系, 這樣的話維護代碼的工作將變得輕松愉快很多,再不會牽一發(fā)而動全身。當你的代碼變得簡明且整潔時,代 碼的可讀性和可維護性都會有質(zhì)的提升。

? 3.支持多終端和服務化架構。 前后端分離后,同一套數(shù)據(jù)接口可以為不同的終端提供服務,更有助于打造多終 端應用;此外,由于后端提供的接口之間可以通過HTTP(S)進行調(diào)用,有助于打造服務化架構(包括微服務)。

此處參考的昊叔的文檔

返回JSON數(shù)據(jù)(前面的車輛違章查詢實例)

def search(request):
    """查詢"""
    # 有沒有查詢過,默認是False,當前頁碼1,總頁數(shù)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變?yōu)門rue
        context['searched'] = True
        # 通過Q對象用車牌號或者車主作為篩選條件查詢,并且把Record關聯(lián)的car對象也一起查詢出來(主要是解決一加N查詢問題)在利用違章時間(offend_time)進行降序排序。
        queryset = Record.objects.filter(
            Q(car__car_no__startswith=carno) |
            # 解決一加N查詢,在查詢后面加上.select_related()方法,一次性將Car關聯(lián)的對象都放入返回的集合中
            Q(car__owner__startswith=carno)).select_related('car').order_by('-offend_time')
        # django自帶的分頁器,拿到分頁器對象,每頁最多顯示5條數(shù)據(jù)
        paginator = Paginator(queryset, 5)
        # 通過分頁器對象的num_pages屬性可以拿到總頁數(shù)
        context['total_page'] = paginator.num_pages
        # 通過get_page()這個方法,指定頁碼,就可拿到這一頁的對象
        page_obj = paginator.get_page(page)
        # 通過這個頁面對象的number屬性 ,可以拿到當前頁碼
        context['current_page'] = page_obj.number
        records = []
        # 從當前頁對象的object_list屬性中遍歷數(shù)據(jù),將每一條記錄組裝成字典。
        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數(shù)據(jù)
    return JsonResponse(context)

在view.py寫好數(shù)據(jù)接口之后在urls.py添加上之后去瀏覽器查看接口數(shù)據(jù),你會得到類似下面的結果.

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

得到的json數(shù)據(jù):

{
    "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
            }]
    …………        
}

這樣后端的數(shù)據(jù)接口就寫好了。

遠端倉庫的使用

如果在創(chuàng)建廠庫的時候使用了readme初始化(不推薦使用),那么將本地代碼上傳到倉庫的時候,需要先使用 git pull的命令將遠端代碼拉下來,并且需要加額外的參數(shù):--allow-unrelated-histories。之后會彈出一個合并文件,不用管,直接wq保存退出就行了。最后在使用 git push -u origin master 將代碼推到遠端倉庫中。

# 將遠端倉庫的代碼拉到本地
git pull --allow-unrelated-histories origin master
# 將本地代碼推到遠端
git push -u origin master

有時在接手別人項目的時候,這個項目已經(jīng)有很多個版本了,這時只需克隆最新的版本就行了。

# 從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 / . 添加文件或者所有本地文件到緩存區(qū)中
git status 查看當前git狀態(tài)
git commit -m ‘提交信息' 將緩存區(qū)中的內(nèi)容全部提交到git本地倉庫
git log 查看提交日志
git reset --heard HEAD 讓工作目錄中的內(nèi)容和倉庫中的內(nèi)容保持一致
git reset --heard HEAD^ 回到上一個版本
git reset --heard HEAD 版本號 回到指定的版本
git checkout 文件名 從暫存區(qū)中恢復工作目錄中的內(nèi)容(讓工作區(qū)中的指定文件,回到上次提交的時候的狀態(tài))
git clone url 將遠程倉庫克隆到本地
git remote add origin 地址 關聯(lián)遠程倉庫
git push [-u] origin master 將本地倉庫的內(nèi)容提交到遠程倉庫的master分之
git push origin 分支名 將本地倉庫的內(nèi)容提交到遠程倉庫對應的分支上, 如果分支不存在會自動創(chuàng)建
git pull 將遠程倉庫中的內(nèi)容更新到本地倉庫和工作區(qū)中
git branch [-a] 查看分之
git branch 分之名 創(chuàng)建分之
git checkout 分支名 切換分之
git checkout -b 分之名 切換并創(chuàng)建新的分之
git diff 分之1 分之2 查看兩個分之之間的差異
git merge 分之名 讓當前分之和指定分之進行合并

注意: 切換分之、push、pull,這些操作前要保證工作區(qū)是干凈的clean

最后編輯于
?著作權歸作者所有,轉載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容