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,這就是注釋。