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

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

模糊查詢和多條件查詢
| 參數(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查詢,他會將相同的記錄查詢多次。這樣就大大降低了程序的性能。

這種現(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查詢

使用前端渲染(前后端分離)
在傳統(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