Django項目知識點(四)
- 2019 年 10 月 11 日
- 筆記
本來今天不想發文的,昨天沒發,怪不好意思的
django view
URL是Web服務的入口,用戶通過瀏覽器發送過來的任何請求,都是發送到一個指定的URL地址,然後被響應。
隨便新建一個Django項目,默認會自動為我們創建一個/project_name/urls.py文件,並且自動包含下面的內容,這就是項目的根URL:
配置media媒體文件
- settings.py
# 媒體文件配置 MEDIA_URL = '/media/' MEDIA_ROOT = os.path.join(BASE_DIR, 'media')
- url.py
確保在渲染的html渲染對應的媒體文件
from django.urls import path,include from django.conf import settings from django.conf.urls.static import static urlpatterns = [ # path('admin/', admin.site.urls), path('myadmin/',include('myadmin.urls')), path('',include('news.urls')), path('',include('verification.urls')), path('course/',include('course.urls')), path('doc/',include('doc.urls')), path('user/',include('user.urls')), path('ckeditor/',include('ckeditor_uploader.urls')), ] + static(settings.MEDIA_URL,document_root = settings.MEDIA_ROOT)
需要在urlpatterns 列表後面加上 static(settings.MEDIA_URL,document_root = settings.MEDIA_ROOT)
- include 指的就是包含該app下的url
對於大部分的view視圖一般寫成類的形式
from django.views import View class IndexView(View): ''' 在線課堂首頁面 ''' def get(self,request): # 1. 拿到所有的視頻數據 courses = Course.objects.only('title','cover_url','teacher__name','teacher__title').select_related('teacher').filter(is_delete = False) return render(request,'course/course.html',context= {'courses':courses}) class CourseDetailView(View): ''' 課程詳細頁 url :/course/<int:course_id>/ ''' def get(self,request,course_id): # 1. 拿到課程信息 course = Course.objects.only('title','cover_url','video_url','profile','outline','teacher__name','teacher__photo','teacher__title','teacher__profile').select_related('teacher').filter(is_delete = False,id = course_id) # 2. 渲染html if course: course = course[0] return render(request,'course/course_detail.html',context={'course':course}) else: return Http404('此課程不存在')
- 對應的url就使用as_view()函數方法
from django.urls import path from . import views app_name = 'course' urlpatterns = [ path('',views.IndexView.as_view(),name = 'index'), path('<int:course_id>/',views.CourseDetailView.as_view(),name = 'course_detail'), ]
視圖一般編寫步驟
- 拿到對應數據庫的模型對象
- 渲染到對於的html頁面
在類中有三個重要的訪問函數方法
- get
就是當我訪問當url是,就是執行get的方法
def get(self, request): return render(request, 'user/login.html')
- post
class LoginView(View): """ 登錄視圖 url: /user/login/ """ def get(self, request): return render(request, 'user/login.html') def post(self, request): # 1.先校驗 # loginform是登錄的表單,在form.py編寫導入 form = LoginForm(request.POST, request=request) if form.is_valid(): return json_response(errmsg='恭喜登錄成功!') else: # 將表單的報錯信息進行拼接 err_msg_list = [] for item in form.errors.values(): err_msg_list.append(item[0]) err_msg_str = '/'.join(err_msg_list) return json_response(errno=Code.PARAMERR, errmsg=err_msg_str)
如當我登錄的時候就會訪問登錄的界面發送get請求,提交數據在數據庫就是post請求
- put
put請求容易給人忽視,用於修改,當要修改用戶的數據
class UserUpdateView(View): """ 用戶更新視圖 url:/myadmin/user/<int:user_id>/ def get(self, request, user_id): user = User.objects.filter(id=user_id).first() if user: form = UserModelForm(instance=user) else: return json_response(errno=Code.NODATA, errmsg='沒有此用戶!') return render(request, 'myadmin/user/user_detail.html', context={'form': form}) """ def put(self, request, user_id): # 1. 拿到要修改的用戶對象 user = User.objects.filter(id=user_id).first() # 1.1 判斷用戶是否存在 if not user: return json_response(errno=Code.NODATA, errmsg='沒有此用戶!') # 2. 拿到前端傳遞的參數 put_data = QueryDict(request.body) # 3. 校驗參數 # 3.1 創建表單對象 # UserModelForm在form.py自定義的 form = UserModelForm(put_data, instance=user) if form.is_valid(): # 4. 如果成功,保存數據 form.save() return json_response(errmsg='用戶修改成功!') else: # 5. 如果不成功就返回渲染了錯誤提示信息的頁面 return render(request, 'myadmin/user/user_detail.html', context={'form': form})
QueryDict
>>> QueryDict('a=1&a=2&c=3') <QueryDict: {'a': ['1', '2'], 'c': ['3']}>
一般我們看到的數據就是json的鍵值對,而不是列表
request.body就是form表單的數據
Queryset
Django ORM用到三個類:Manager、QuerySet、Model。
Manager定義表級方法(表級方法就是影響一條或多條記錄的方法),我們可以以models.Manager為父類,定義自己的manager,增加表級方法;
QuerySet:Manager類的一些方法會返回QuerySet實例
就是從數據庫根據自己要求拿數據的
連數據都那不出來,寫啥視圖
所以在編寫queryset必須用django shell 調試
在model中,Django通過給Model增加一個objects屬性來提供數據操作大的接口。比如:想要查詢所有評論的數據,可以這麼寫:
Comments.objects.all() # 可切片 Comments.objects.all()[0:1] # 可迭代 for coment in comments: print(comment.author )
- exists() 判斷是否存在
難度提升

doc model
# is_delete是繼承baseModel docs = Doc.objects.values('file_url','file_name','title','desc','image_url').filter(is_delete= False)
現在拿到沒有刪除的部分數據,不拿author字段
app.object的用法
- filter() 過濾查詢對象。
- exclude() 排除滿足條件的對象
- annotate() 使用聚合函數
- order_by() 對查詢集進行排序
- reverse() 反向排序
- distinct() 對查詢集去重
- values() 返回包含對象具體值的字典的QuerySet
- values_list() 與values()類似,只是返回的是元組而不是字典。
- dates() 根據日期獲取查詢集
- datetimes() 根據時間獲取查詢集
- none() 創建空的查詢集
- all() 獲取所有的對象
- union() 並集
- intersection() 交集
- difference() 差集
- select_related() 附帶查詢關聯對象
- prefetch_related() 預先查詢
- extra() 附加SQL查詢
- defer() 不加載指定字段
- only() 只加載指定的字段
- using() 選擇數據庫
- select_for_update()
- raw()
raw() 使用sql
不熟悉SQL的可以跳過該部分,如下代碼: sql = 'select * from new' #需要查詢數據庫具體new對應表名 qs = new.objects.raw(sql) #將sql語句轉成RawQuerySet對象 該SQL是獲取全部記錄,相當於QuerySet如下查詢: qs = new.objects.all()
filter()
filter是篩選的意思,通過filter篩選得到符合條件的數據集。
tags = Tag.objects.only('name').filter(is_delete=False)
values() only()
返回的是queryset字典,不是對象,only才是返回的是對象
docs = Doc.objects.values('file_url','file_name','title','desc','image_url').filter(is_delete= False) docs = Doc.objects.only('file_url','file_name','title','desc','image_url').filter(is_delete= False)
select_related()
如果我要拿這個模型通過外鍵綁定的另外一個模型,使用select_related
course 模型定義了teacher字段綁定teacher模型
course = Course.objects.only('title','cover_url','video_url','profile','outline','teacher__name','teacher__photo','teacher__title','teacher__profile').select_related('teacher').filter(is_delete = False,id = course_id)
重點
官方文檔:https://docs.djangoproject.com/en/2.1/topics/db/aggregation/
Django的aggregate和annotate方法屬於高級查詢方法,主要用於組合查詢,是Django高手們必需要熟練掌握的。當我們需要對查詢集(queryset)的某些字段進行計算或進行先分組再計算或排序, 我們就需要使用aggregate和annotate方法了。
- aggregate
下面代碼來源官網
from django.db import models class Author(models.Model): name = models.CharField(max_length=100) age = models.IntegerField() class Publisher(models.Model): name = models.CharField(max_length=300) class Book(models.Model): name = models.CharField(max_length=300) pages = models.IntegerField() price = models.DecimalField(max_digits=10, decimal_places=2) rating = models.FloatField() authors = models.ManyToManyField(Author) publisher = models.ForeignKey(Publisher, on_delete=models.CASCADE) pubdate = models.DateField() class Store(models.Model): name = models.CharField(max_length=300) books = models.ManyToManyField(Book) >>> Book.objects.count() 2452 # publisher__name 是 book通過publisher綁定的app下的name字段,寫成publisher__name >>> Book.objects.filter(publisher__name='BaloneyPress').count() 73 # Average price across all books. >>> from django.db.models import Avg >>> Book.objects.all().aggregate(Avg('price')) {'price__avg': 34.35} # Max price across all books. >>> from django.db.models import Max >>> Book.objects.all().aggregate(Max('price')) {'price__max': Decimal('81.20')}
annotate
先介紹F,annotate 必用F
F介紹
-個F()對象表示一個模型字段或注釋的列的值。這樣就可以引用模型字段值並使用它們執行數據庫操作,而無需實際將它們從數據庫中拉出到Python內存中
說白了就是我從數據庫拿東西,但是有些需要的字段沒有,要通過綁定的外鍵的app的model拿。但是名稱又是app__字段來命名,這樣我要改名稱,而且拿第一次的model,放在python內存中,再拿通過外鍵綁定的另一個model,又要執行第一次步驟,那個效率就不行了,幹嘛我不一起拿,所以會用annotate可以提高效率
from django.db.models import F banners = Banner.objects.values('image_url', 'news_id').annotate(news_title=F('news__title')).filter(is_delete=False)
我要拿出image_url,news_id,和news_title,news_title來源banner模型外鍵綁定news中的title字段,拿出來它叫news__title,我要給它換個名字叫news_title,這就是注釋。
