<output id="qn6qe"></output>

    1. <output id="qn6qe"><tt id="qn6qe"></tt></output>
    2. <strike id="qn6qe"></strike>

      亚洲 日本 欧洲 欧美 视频,日韩中文字幕有码av,一本一道av中文字幕无码,国产线播放免费人成视频播放,人妻少妇偷人无码视频,日夜啪啪一区二区三区,国产尤物精品自在拍视频首页,久热这里只有精品12

      django 視圖

      * admin的使用 * ORM模型 * 事務 * cookie * session * 中間件 * form組件 * modelform組件 * Git * 分頁

      視圖

      CBV FBV

      1. CBV : class based view 基于類的視圖
        FBV: funcation based view 基于函數的視圖
        使用:在views里,好處是不需要加if判斷了

      舉個基于類的views的例子
      在views里

      from django.views import View
      class AddPublisher(View):
         def get(self,request):
            # get請求hr@qutke.com
            return response
         def post(self,request):
            # post請求
            return response
      

      在url里的路徑

      url(r'^add_publisher/', views.AddPublisher.as_view()),
      
      as_view()的流程:

      1). 程序啟動的時候,就執行as_view() 定義view函數并返回
      2). 請求到來的時候,執行父類里面的view函數:
      (1). 實例化當前的類 ——》 self
      (2). self.request = request
      (3). 執行self.dispatch的方法:
      3.1. 判斷請求方式是否別允許:
      3.1.1. 允許 通過反射拿到對用請求方式的方法 —— 》 handler
      3.1.2. 不允許 self.http_method_not_allowed ——》 handler
      3.2. 執行handler 得到 HttpResponse對象 返回

      使用裝飾器

      定義一個timer裝飾器
      FBV : 直接加在函數上
      CBV : from django.utils.decorators import method_decorator
      1). 加在方法上

      @method_decorator(timer)
      def get(self, request):
      

      2) 加在dispatch方法上(所有的請求方式都能加上)

      @method_decorator(timer)
      def dispatch(self, request, *args, **kwargs):
          ret=super().dispatch(request,*args,**kwargs)  #調用父類方法
          return ret
      

      3)加在類上, 必須有name參數

      (1)指定給誰加上

        @method_decorator(timer,name='post')
        @method_decorator(timer,name='get')
        class AddPublisher(View):
      

      (2)要是這種的話,就不用寫dispatch方法了,他會加在父類的方法上

      @method_decorator(timer,name='dispatch')
      class AddPublisher(View):
      
      使用類裝飾器和直接使用@timer有什么區別?

      沒什么區別,主要區別在于裝飾器里的args,func上
      1) 不使用method_decorator
      Args (<app01.views.AddPublisher object at 0x03B465B0>, <WSGIRequest: GET '/add_publisher/'>)
      Func :func函數,取值,對應得request是第二個值(就是取值不太方便)

      2) 使用method_decorator:
      Args 是 (<WSGIRequest: GET '/add_publisher/'>,)
      Func :bondfunc 綁定函數,取值的話第一個值對應得是request對象

      request

      1)屬性

      request.method  #請求方式 POST  GET :類型是字符串
      request.GET  #是url地址上的參數,不是get帶的參數
      request.POST     #form表單用戶提交POST請求的數據
      #request.POST.get(‘name’)  #得到數據(返回值,get()是字典形式)*
      request.FILES  # 上傳的文件
      request.path_info   # 路徑  不包含IP和端口 參數 
      print(request.path_info,type(request.path_info))  結果:/index/ <class 'str'>
      request.body        # 請求體   請求數據  get沒有請求體 
       結果:get  b’ ‘ 是空的,post ’ b’ czc…name=’’’里面有內容
      Request.META     #請求頭的信息
      Request.COOKIES:  #一個標準的python字典
      Request.session:  #一個既會讀又課寫的類似于字典的形象,表示當前會話
      以上的必須記住
      Request.scheme 協議 http  https  結果是http 類型是字符串
      Request.encoding:表示提交數據的編碼方式,如果為None,則default_charset=’utf-8’
      

      2)方法

      Request.get_full_path()    #路徑   不包含ip和端口  包含參數
      Request.is_ajax()          #判斷是否是ajax請求
      Request.host()   #獲取主機的ip和端口
      

      上傳文件

      1. form 表單里寫上編碼方式

        enctype="multipart/form-data"

      2. 要是POST請求,在模板里要寫上

      3. request.FILES 打印結果是字典
        request.FILES.get(‘s19’) 獲取值, 文件在內存里
        4) chunks:意思是一片一片的傳

      這是一個上傳下載文件的代碼:
      在views里

      def upload(request):
          if request.method=='POST':
              print(request.POST)
              f1 = request.FILES.get('s19')
              print(f1,type(f1))
              with open(f1.name,'wb')as f:     #把文件寫進去,字節形式
                  for chunk in f1.chunks():
                      f.write(chunk)
          return render(request,'upload.html')
      

      在模板里

      <form action="" method="post" enctype="multipart/form-data">
          {% csrf_token %}
          文件 <input type="file"  name="s19">
          <button>上傳</button>
      </form>
      

      response

      HttpResponse('字符串')    ——》 返回的字符串
      render(request,'模板的文件名',{k1:v1})    ——》  返回一個完整的HTML頁面
      redirect(要跳轉的地址)    —— 》重定向       Location :地址
      jsonresponse
      
      httpresponse 和jsonresponse 的區別

      Jsonresponse 傳輸字典類型的,要想傳輸其他類型,加上safe=False

      from django.http.response  import JsonResponse
      JsonResponse(data)    # Content-Type: application/json
      JsonResponse(data,safe=False)  # 傳輸非字典類型
      

      舉個例子

      import json
      from django.http.response  import JsonResponse
      def json_data(request):
          date={'name':'alex','age':30}
          # return HttpResponse(date)  #得到的是字典的鍵
          ret = HttpResponse(json.dumps(date))
          ret['Content-Type']='application/json'
          return  ret                 #{'name':'alex','age':30}
                                  # Content-Type: text/html; charset=utf-8
      
          # return JsonResponse(date) #{'name':'alex','age':30}
                                  # Content-Type: application/json
      return JsonResponse(li,safe=False)
      

      分組

      1. Django settings.py配置文件中默認沒有 APPEND_SLASH 這個參數,但 Django 默認這個參數為 APPEND_SLASH = True。 其作用就是自動在網址結尾加'/'。

      2.分組 ( )

      url(r'^blog/([0-9]{4})/([0-9]{2})/$', views.blog),
      

      分組的結果會當做位置參數 ——》 傳遞給視圖函數

      def blog(request,name,aa):
          return HttpResponse('ok')
      

      3.命名分組 (?P

      url(r'^blog/(?P<year>[0-9]{4})/(?P<month>[0-9]{2})/$', views.blog),
      

      ?分組的結果會當做關鍵字參數 ——》 傳遞給視圖函數

      def blog(request,year,month):
          print(year,month)
          return HttpResponse('ok')
      

      4.include 路由分發
      先匹配一級目錄,在匹配二級目錄 (多個app的時候)

      from django.conf.urls import url,include
      from app01 import views
      urlpatterns = [
         url(r'^app01/', include('app01.urls')),
         url(r'^app02/', include('app02.urls')),
      ]
      

      **傳遞額外的參數給視圖函數 **
      注:要是命名函數的名字和參數的鍵同名,那命名函數名字的值就是參數的值

      url(r'^blug/(?P<year>[0-9]{4})/(?P<month>[0-9]{2})/',views.blug,{'foo':'v1'})
      def blug(request,year,month,**kwargs):
          print(year,month)
          print(kwargs)
          return HttpResponse('ok')
      

      5. URL命名和反向解析

      靜態地址
      1)命名

      url(r'^blog/$', views.blogs, name='xxxx'),
      url(r'^home/',views.home)
      

      使用:
      ?
      在模板
      ? {% url 'xxxx' %} ——》 '/blog/' 一個完整的URL
      或是在py文件
      ? from django.urls import reverse
      ? reverse('xxxx') ——》 '/blog/

      2)命名分組

      url(r'^blog/(?P<year>[0-9]{4})/(?P<month>[0-9]{2})/$', views.blog,name='blog' ),
      

      使用:
      ?
      在模板
      ? {% url 'blog' ‘2019’ ‘12’ %} ——》 '/blog/2019/12/' 一個完整的URL 位置傳參
      ? {% url 'blog' month='09' year='2016' %} '/blog/2016/09/' 關鍵字傳參
      ? 在py文件
      ? from django.urls import reverse
      ? reverse('blog',args=('2018','02')) ——》 '/blog/2018/02'
      reverse('blog', kwargs={'year': '2020', 'month': '03'}) ——》 /blog/2020/03

      namespace 在多個app下有相同的方法,用'namespace:name'便于區分

      urlpatterns = [
         url(r'^admin/', admin.site.urls),
         url(r'^app01/', include('app01.urls',namespace='app01')),
         url(r'^app02/', include('app02.urls',namespace='app02')),
      ]
      

      使用:

      在模板
      {%  url   'namespace:name'  參數 %}
      在py文件
      reverse( 'namespace:name' ,arrgs=(),kwargs={} )
      

      admin的使用

      LANGUAGE_CODE = 'zh-Hans' 改成中文
      1. 創建超級用戶

      python manage.py createsuperuser
      用戶名和密碼    密碼 數字+字母+至少8位
      

      2. 注冊model

      在app下的admin.py中寫
      

      from app01 import models
      admin.site.register(models.Person)
      3. 訪問 http://127.0.0.1:8000/admin/

      ORM模型

      對象關系映射(Object Relational Mapping,簡稱ORM)模式是一種為了解決面向對象與關系數據庫存在的互不匹配的現象的技術。

      ORM的操作:

      類     —— 》   表
      對象   —— 》   數據(記錄)
      屬性   —— 》   字段
      
      models.User.objects.all()  # 所有數據   對象列表
      models.User.objects.get(username='alex')  # 獲取一個滿足條件的對象  沒有數據 或者 多條數據就報錯
      models.User.objects.filter(username='alex1')  # 獲取滿足條件的所有對象  對象列表1) 對應關系
      
      class Student(models.Model)
      models.CharField (max_length=32)  # varchar(32)
      models.AutoField (primary_key=True)  #自增字段 pk主鍵 
          models.ForeignKey (‘Publisher’,on_delete=models.CASCADE)  #publisher是所管連的表的類名(可以是字符串的形式)
      

      models.CASCADE 是級聯刪除
      default=’男’
      on_delete=models.SET_DEFAULT 是設置默認值
      SET_NULL是設置為空
      SET(value)
      on_delete:所關聯的表刪除后,對這個表所做的操作
      django1.11版本之前的不用填寫 默認是on_delete=models.CASCADE
      django2.0版本之后就是必填項

      1.ORM字段 對象關系映射

      orm跟MySQL的區別
      orm是關聯數據庫的,讓開發者用代碼操作對象,簡化開發,屏蔽不同數據庫的SQL差異,減少手寫SQL的工作,降低出錯率。
      直接操作MySQL比用orm執行效率更高。

      orm因額外的映射轉換過程,會存在輕微的性能損耗,"代碼->SQL"的轉換過程會消耗少量CPU和時間,而直接手寫SQL可跳過此步驟直接與MySQL交互。

      1. 對于簡單業務(如單表查詢,新增),orm的性能損耗通常可忽略,此時開發效率比微小的性能差距更重要,
      2. 對于高并發,復雜查詢,(如多表聯查,大數據量統計),orm自動生成的SQL可能不夠優化(如冗余字段,低效關聯),此時手寫SQL可針對性優化,效率優勢會更明顯。

      常用的字段
      ?        AutoField :自增字段 自增的整形字段,必填參數primary_key=True,則成為數據庫的主鍵。無該字段時,django自動創建。
      一個model不能有兩個AutoField字段。
      ?        AutoField****IntegerField: 一個整數類型。數值的范圍是 -2147483648 ~ 2147483647。
      ?        AutoField****CharField: 字符類型
      ?        AutoField****DateField ; 日期類型
      參數:
      auto_now:每次修改時修改為當前日期時間。
      auto_now_add:新創建對象時自動添加當前日期時間。每次修改時,時間不變
      auto_now和auto_now_add和default參數是互斥的,不能同時設置。
      ?        AutoField****DatetimeField : 日期時間字
              AutoField****BooleanField : - 布爾值類型
              AutoField****NullBooleanField 可以為空
              AutoField****TextField- 文本類型
              AutoField****FloatField:浮點型
              AutoField****DecimalField 10進制小數

      2.參數

      1). null = Ture 數據庫中可以為空
      2). blank = Ture 表單中可以為空
      3). db_column 修改數據庫中字段的列名

      4). default 默認值
      5) unique=True 唯一
      6) verbose_name=’名字’  Admin中顯示的字段名稱中文提示
      7) choices Admin中顯示選擇框的內容可供選擇的值 gender=models.BooleanField('性別',default=False,choices=((0,'男'),(1,'女')))
      8) help_text='請輸入正確年齡'  Admin中該字段的提示信息

      3.自定義一個char類型字段:

       class MyCharField(models.Field):
          """
          自定義的char類型的字段類
          """
      
          def __init__(self, max_length, *args, **kwargs):
              self.max_length = max_length
              super(MyCharField, self).__init__(max_length=max_length, *args, **kwargs)
      
          def db_type(self, connection):
              """
              限定生成數據庫表的字段類型為char,長度為max_length指定的值
              """
              return 'char(%s)' % self.max_length
      

      使用:用自定義的類名 phone = MyCharField(max_length=11,)

      4. 表的參數

      Class Mate類是固定寫法,是給上邊的類做的標配

      class Person(models.Model):
          pid = models.AutoField(primary_key=True)
          name = models.CharField(max_length=32, db_column='username', unique=True, verbose_name='姓名')  # varchar(32)
      
      
      class Meta:
          # 數據庫中生成的表名稱 默認 app名稱 + 下劃線 + 類名
          db_table = "person"
          # 排序
          ordering = ('pk',)
      
      
      # 聯合索引 
      index_together = [
          ("name", "age"),
      ]
      # 聯合唯一索引
      unique_together = (("name", "age"),)
      

      下圖是該名字,改變后,名字變了,內容不變

      orm 批量操作 bulk_create

      models.StudyRecord.objects.bulk_create(study_record_list)
      
      或者
      models.StudyRecord.objects.get_or_create(student=student,course_record_id=course_record_id)  # 獲取或插入
      models.StudyRecord.objects.update_or_create(student=student,course_record_id=course_record_id)   # 更新或插入
      

      5. ORM的查詢(13條) 必知必會13條

      import os
      os.environ.setdefault("DJANGO_SETTINGS_MODULE", "orm_practice.settings")
      import django
      django.setup()
      from app01 import models
      

      返回的是對象列表 (8)

      all   獲取表中所有的數據    ——》 對象列表  QuerySet
      filter  #  獲取表中滿足條件的所有數據   ——》 對象列表  QuerySet
      exclude  獲取表中不滿足條件的所有數據    ——》 對象列表  QuerySet
      order_by  對已經排好序的結果進行倒序      ——》 對象列表  QuerySet
      排序    默認升序   字段加- 降序     多個字段   ——》 對象列表  QuerySet
      models.Person.objects.all().order_by('-age', 'pk'),先按第一個字段排,要是有兩個一樣的,按第二個排
      reverse  翻轉
      ret = models.Person.objects.all().order_by('pk').reverse()
      values   獲取數據的字段名和對應的值    ——》 對象列表  QuerySet   [{} ,{}]字典
      #  不填寫參數    獲取所有字段名字和值  obj=models.Person.objects.values()
      #  填寫參數      獲取指定字段名字和值   obj=models.Person.objects.values('name',’age’)
      values_list 
      獲取數據的字段對應的值    ——》 對象列表  QuerySet   [() ,()] 元祖
      #  不填寫參數    獲取所有字段值
      #  填寫參數      獲取指定字段值   有順序
      distinct  去重  所有字段都一樣才去重
      

      返回的是對象 (3)

      get  # 獲取一條數據    ——》 對象     獲取不到或者多條就報錯
      first  取第一個元素   沒有元素  None
      last	取最后一個元素   沒有元素  None
      

      返回布爾值 (1)

      exists  判斷是否存在 models.Person.objects.filter(name='alex').exists()
      

      返回數字 (1)

      count  計數
      

      單表的雙下劃線

      ret = models.Person.objects.filter(pk=1)
      ret = models.Person.objects.filter(pk__gt=1)  # greater than   大于
      ret = models.Person.objects.filter(pk__lt=3)  # less than    小于
      ret = models.Person.objects.filter(pk__gte=1)  # greater than equal   大于等于
      ret = models.Person.objects.filter(pk__lte=3)  # less than  equal     小于等于
      
      ret = models.Person.objects.filter(pk__range=[1, 3])  # 范圍   左右都包含
      ret = models.Person.objects.filter(pk__in=[1, 5])  # in  只要1和5
      
      ret = models.Person.objects.filter(name__contains='alex')  #  like  完全包含
      ret = models.Person.objects.filter(name__icontains='ale')  #  like   忽略大小寫  ignore
      
      ret = models.Person.objects.filter(name__startswith='a')  #  以a開頭
      ret = models.Person.objects.filter(name__istartswith='a')  #  以a開頭忽略大小寫
      
      
      ret = models.Person.objects.filter(name__endswith='a')  #  以a開頭
      ret = models.Person.objects.filter(name__iendswith='g')  #  以a開頭忽略大小寫
      
      ret = models.Person.objects.filter(phone__isnull=True)  #  phone字段為空
      ret = models.Person.objects.filter(phone__isnull=False)  #  phone字段不為空
      
      
      ret = models.Person.objects.filter(birth__year=2019)  
      ret = models.Person.objects.filter(birth__contains='2019-04-09')  包含,相當于like
      # ret = models.Person.objects.filter(birth__month=4) 
      

      外鍵的操作

      1)基于對象的查詢
      正向查詢
      正向查詢: 外鍵所在表去查另一張表,Book >> Publisher
      反向查詢:普通表去查外鍵所在的表,Publisher >> Book

        book_obj = models.Book.objects.get(pk=1)
      # print(book_obj.publisher) 		 # 書籍所關聯的對象
      # print(book_obj.publisher.name)   # 書籍所關聯的對象的名字
      # print(book_obj.publisher_id)     # 書籍所關聯的對象的ID
      

      反向查詢

      pub_obj = models.Publisher.objects.get(pk=1)
      
      # 外鍵中 不指定related_name     pub_obj.表名小寫_set   關系管理對象
      # print(pub_obj.book_set,type(pub_obj.book_set))    #  表名小寫_set   關系管理對象  
      # print(pub_obj.book_set.all())
      
      # 外鍵中 指定related_name='books'    pub_obj.books  關系管理對象
      # print(pub_obj.books,type(pub_obj.books))    #  表名小寫_set   關系管理對象
      

      2)基于字段的查詢 外鍵名__name=’ ’ 跨表查詢

      查詢人民出版社出版的所有書籍

      ret = models.Book.objects.filter(publisher__name='人民出版社')
      

      查詢豐乳肥臀的出版社

      不指定 related_name      跨表時使用  表名小寫__字段
      # ret = models.Publisher.objects.filter(book__title='豐乳肥臀')
      # 指定 related_name='books'   跨表時使用books__字段
      # ret = models.Publisher.objects.filter(books__title='豐乳肥臀')
      # 指定 related_name='books'  related_query_name='book'  跨表時使用book__字段
      ret = models.Publisher.objects.filter(book__title='豐乳肥臀')
      # print(ret)
      print(pub_obj.books.all())
      

      多對多

      基于對象的查詢

      author_obj.books ——》 關系管理對象
      author_obj.books.all() ——》 關系管理對象
      
      不指定related_name 
      book_obj.author_set ——》 關系管理對象
      book_obj.author_set.all() ——》 作者寫過所有的書籍對象 
      
      指定related_name=’authors‘
      book_obj.authors——》 關系管理對象
      book_obj.authors.all() ——》 作者寫過所有的書籍對象 
      

      管理對象的方法

      all 獲取所有的對象
      set 設置關系 多對多 [ id,id ] [對象,對象] 一對多 [對象] 
      add 添加關系 多對多 id,id 對象,對象 一對多 對象 
      remove 刪除關系 一對多:必須設置外鍵可為空,才有remove clear方法
      clear 清空所有的關系
      create 創建一個對象并且添加關系
              `book_obj.authors.create(name='xxxx') `
      
      pub_obj.books.set(models.Book.objects.filter(pk__in=[3]))  # 設置關系  【對象 】
      pub_obj.books.add(*models.Book.objects.filter(pk__in=[4]))    # 添加關系   對象
      pub_obj.books.remove(*models.Book.objects.filter(pk__in=[3]))   # 刪除關系   對象    外鍵 null=True
      pub_obj.books.clear()   # 刪除關系   對象    外鍵 null=True
      

      聚合 aggregate

      所獲取的是對象列表[{ },{ }]
      例:

      import os
      os.environ.setdefault("DJANGO_SETTINGS_MODULE", "orm_practice.settings")
      import django
      django.setup()
      from app01 import models
      from django.db.models import Max, Min, Count, Avg, Sum
         
      # 1 所有書的平均價格
      # res = models.Book.objects.aggregate(Avg('price'))
      # print(res)
      # 2.上述方法一次性使用
      res = models.Book.objects.aggregate(Max('price'), Min('price'), Sum('price'), Count('pk'), Avg('price'))
      print(res)
      

      分組 annotate

      # 分組查詢  annotate
      """
      MySQL分組查詢都有哪些特點
          分組之后默認只能獲取到分組的依據  組內其他字段都無法直接獲取了
              嚴格模式
                  ONLY_FULL_GROUP_BY        
      """
      from django.db.models import Max, Min, Sum, Count, Avg
      # 1.統計每一個書的作者個數
      # res = models.Book.objects.annotate()  # models后面點什么  就是按什么分組
      """
      author_num是自定義的字段 用來存儲統計出來的每本書對應的作者個數
      """
      # res = models.Book.objects.annotate(author_num=Count('authors')).values('title', 'author_num')
      # print(res)
      
      # 2.統計每個出版社賣的最便宜書的價格
      # res = models.Publish.objects.annotate(min_price=Min('book__price')).values('name','min_price')
      # print(res)
      
      # 3.統計不止一個作者的圖書
          # 1.先按照圖書分組  求每一本書對應的作者個數
          # 2.過濾出不只一個作者的圖書
      # res = models.Book.objects.annotate(author_num=Count('authors')).filter(author_num__gt=1).values('title', 'author_num')
      """
      只要你的orm語句得出的結果還是一個queryset對象
      那么就可以繼續無限制的點queryset對象封裝的方法
      """
      # print(res)
      
      # 4.查詢每個作者出的書的總價格
      # res = models.Author.objects.annotate(sum_price=Sum('book__price')).values('name','sum_price')
      # print(res)
      
      
      """
      如果按照指定的字段分組該如何處理呢
          model.Book.objects.values('price').annotate()
          
      如果出現分組查詢報錯的情況
          需要修改數據庫嚴格模式
      """
      
      
          方式一:
          ret = models.Publisher.objects.annotate(min=Min('book__price')).values()
          方式二
          ret = models.Book.objects.values('publisher__name').annotate(min=Min('price'))  #對象列表{}
          for i in ret:
          	print(i)
      

      F和Q查詢

      from django.db.models import F, Q
      F查詢  比較兩個字段
      
          ret=models.Book.objects.filter(sale__gt=F('kucun'))   update(sale=F(‘sale’)*2)
      Q 查詢  |或   ;&  與   ;~  非
      
          Filter(Q(pk_gt=5))  ==	Q((‘ss’,kk))
      

      F查詢

      # 1.查詢賣出數大于庫存數的書籍
      """
      能夠幫助你直接獲取表中某個字段對應的數據
      """
      from django.db.models import F
      # res = models.Book.objects.filter(maichu__gt=F('kuncun'))
      # print(res)
      
      # 2.將所有書籍的價格提升50元
      # models.Book.objects.update(price=F('price') +500)
      
      # 3.將所有書的名稱后面加上爆款兩個字
      """
      在操作字符類型數據的時候 F不能夠直接做到字符串的拼接
      """
      from django.db.models.functions import Concat
      from django.db.models import Value
      models.Book.objects.update(title=Concat(F('title'),Value('爆款')))
      # models.Book.objects.update(title=Concat(F('title')+'爆款')  # 所有名稱都會全部變成空白
      

      Q查詢

      # 1.查詢賣出數大于100或者價格小于600的書籍
      # res = models.Book.objects.filter(maichu__gt=100,price__lt=600)
      """filter括號內多個參數是and關系"""
      from django.db.models import Q
      # res = models.Book.objects.filter(Q(maichu__gt=100),Q(price__lt=600))  # Q包裹逗號分割 還是and關系
      # res = models.Book.objects.filter(Q(maichu__gt=100)|Q(price__lt=600))  # | or關系
      # res = models.Book.objects.filter(~Q(maichu__gt=100)|Q(price__lt=600))  # ~ not關系
      # print(res)
      
      # Q的高階用法  能夠將查詢條件的左邊也變成字符串的形式
      # q = Q()
      # q.connector = 'or'
      # q.children.append(('maichu__gt', 100))
      # q.children.append(('price__lt', 600))
      # res = models.Book.objects.filter(q)  # 默認還是end關系
      # print(res)
      

      事務

      """
      事務
      	ACID
      		原子性
      			不可分割的最小單位
      		一致性
      			跟原子性是相輔相成
      		隔離性
      			事物之間互相不干擾
      		持久性
      			事務一旦確認永久生效
          事務的回滾
          	rollback
          事務的確認
          	commit
      """
      # 目前只需要掌握Django如何簡單的開啟事務
       # 事務
          from django.db import transaction
          try:
              with transaction.atomic():
                  # sql1
                  # sql2
                  # 在with代碼塊內書寫的所有orm操作都是屬于同一個事務
          except Exception as e:
              print(e)
          print('執行其他操作')
      

      only與defer , select_related與prefetch_related

      """
      orm語句的特點:
      	惰性查詢
      		如果僅僅只是書寫了orm語句 在后面根本沒有用到該語句查詢出來的參數
      		那么orm會惰性識別
      """
      
      # only與defer
       # res = models.Book.objects.all()
          # print(res)  # 要用數據了才會走數據庫
      
          # 獲取書籍表中所有書的名字
          # res = models.Book.objects.values('title')
          # for d in res:
          #     print(d.get('title'))
          # 實現獲取到的是一個數據對象 然后點title就能夠拿到書名  并且沒有其他字段
          # res = models.Book.objects.only('title')
          # res = models.Book.objects.all()
          #QuerySet [<Book: 三國演義爆款>, <Book: 紅樓夢爆款>, <Book: 論語爆款>, <Book: 聊齋爆款>, <Book: 老子爆款>]>
          # print(res)
          # for i in res:
          #     print(i.title)  # 點擊only括號內的字段  不會走數據庫
              # print(i.price)  # 點擊only括號內沒有的字段  會重新走數據庫查詢而all不需要走
      
          res = models.Book.objects.defer('title')
          for i in res:
              print(i.price)
          # print(res)
          """
          defer與only剛好相反
              defer括號內放的字段不在查詢出來的對象里面  查詢該字段需要重新走數據
              而如果查詢的是非括號內的字段 則不需要走數據庫
          """
          
          
       
      # select_related與prefetch_related
       # select_related與prefetch_related  跟跨表操作有關
          # res = models.Book.objects.all()
          # for i in res:
          #     print(i.publish.name)  # 每循環一次就要走一次數據庫查詢
      
          # res = models.Book.objects.select_related('publish') # INNER JOIN
          """
          select_related內部直接先將book與publish連起來  然后一次性將大表里面的所有數據
          全部封裝給查詢出來的對象
              這個時候無論是點擊book表的數據還是publish的數據都無需再走數據查詢了
              
          select_related括號內只能放外鍵字段  一對多 一對一
              多對多不行
          """
          # print(res)
          # for i in res:
          #     print(i.publish.name)
      
          res = models.Book.objects.prefetch_related('publish') # 子查詢
          """
          prefetch_related該方法內部其實就是子查詢
              將子查詢出來的所有結果也給你封裝到對象中
              給你的感覺就是一次性完成的
          """
          for i in res:
              print(i.publish.name)
      

      定義:cookie就是保存在瀏覽器本地的一組組鍵值對
      特性

      • 服務器讓瀏覽器進行設置的
      • 保存在瀏覽器本地的,瀏覽器也可以不保存
      • 下次訪問時自動攜帶相應的cookie
      **cookie能做什么:** 1. 登錄 (保存狀態) 2. 保存用戶的瀏覽習慣 3. 投票

      為什么要有cookie?

      HTTP協議是無狀態的,每次請求都是沒關系的,沒辦法保存,狀態,使用cookie保存狀態

      django的操作:

      1. 設置 本質: 響應頭 set-cookie

           ret = redirect('/home/')  #響應對象
           ret.set_cookie('is_login', '1')   # 普通的cookie  max_age=5設置時間  path  domain
           #ret.set_signed_cookie(key='is_login',value= '1', salt='day62')  # 加密的cookie
        
           #參數:
           max_age=5設置時間,  
           path='/', Cookie生效的路徑,/ 表示根路徑,特殊的:根路徑的cookie可以被任何url的頁面訪問domain=None, Cookie生效的域名
        
      2. 獲取 本質:請求頭cookie

           request.COOKIES[key]    {}    #  普通的cookie
           或者
           request.COOKIES.get(key)
           #request.get_signed_cookie('is_login',salt='day62',default='')   # 加密的cookie
        
      3. 刪除

         ret = redirect('/login/')
         ret.delete_cookie('is_login')
        

      session

      session 當做字典使用

      定義: 保存在服務器上一組組鍵值對,必須依賴于cookie。

      為什么要使用session?(特性)

      1. cookie保存在瀏覽器本地,不安全
      2. cookie的大小受到限制

      django中操作session

      1. 設置

         request.session[key] = value
         或者
         request.session.setdefault(key,value)
        
      2. 獲取

         request.session[key] 
         或者  
         request.session.get(key)
        
      3. 刪除

         del request.session['k1']
         request.session.delete()     # 刪除所有的session數據   不刪除cookie
         request.session.flush()      # 刪除所有的session數據  刪除cookie
         request.session.exists("session_key")  #檢查會話session的key在數據庫中是否存在
        

      其他:

          request.session.set_expiry(10)  #設置超時時間,但是數據庫的session不會刪   
          通過request.session.clear_expired() # 清除已過期的數據
      

      配置: 了解

      from django.conf import global_settings
      
      #數據庫Session
      SESSION_ENGINE = 'django.contrib.sessions.backends.db'   # 引擎(默認)
      
      #緩存Session
      SESSION_ENGINE = 'django.contrib.sessions.backends.cache'  # 引擎	
       
      #文件Session
      SESSION_ENGINE = 'django.contrib.sessions.backends.file'
      SESSION_COOKIE_AGE = 1209600 設置失效時間的
      SESSION_COOKIE_PATH = "/"      # Session的cookie保存的路徑(默認)
      SESSION_COOKIE_DOMAIN = None            # Session的cookie保存的域名(默認)
      SESSION_COOKIE_SECURE = False           # 是否Https傳輸cookie(默認)
      SESSION_COOKIE_HTTPONLY = True            # 是否Session的cookie只支持http傳輸(默認)
      

      中間件

      本質上就是python中的類

      使用:
      在app01下新建一個middlewares文件夾,在里面新建一個py文件

      from django.utils.deprecation import MiddlewareMixin
      

      在setting里添加配置

      1)官方的說法:中間件是在全局范圍內一個用來處理Django的請求和響應的框架級別的鉤子
      2) 五種方法:(執行時間、執行順序、參數、返回值)

      • process_request(self,request)
      • process_view(self, request, view_func, view_args, view_kwargs)
      • process_exception(self, request, exception)
      • process_template_response(self,request,response)
      • process_response(self, request, response)

      process_request(self,request)

      執行時間:
      ?視圖函數執行之前(請求到來后,路由匹配前)
      執行順序:
      ?按照注冊的順序 順序執行
      參數:
      ?request - 和視圖中的request對象是同一個
      返回值:
      ?None: 正常流程
      ?HttpResponse對象: 后面的中間件的process_request方法、視圖都不執行,直接執行當前中間件的process_response方法,再返回給瀏覽器

      process_response(self, request, response)

      執行時間:
      ?視圖函數執行之后
      執行順序:
      ?按照注冊的順序 倒序執行
      參數:
      ?request - 和視圖中的request對象是同一個
      ?response - 視圖函數返回的響應對象
      返回值:
      HttpResponse對象: 必須返回

      process_view(self, request, view_func, view_args, view_kwargs)

      執行時間:
      ?在process_request方法后,路由匹配之后,視圖函數執行之前
      執行順序:
      ?按照注冊的順序 順序執行
      參數:
      ?request - 和視圖中的request對象是同一個
      ?view_func - 視圖函數
      ?view_args - 給視圖使用的位置參數
      ?view_kwargs - 給視圖使用的關鍵字參數
      返回值:
      ?None: 正常流程
      ?HttpResponse對象: 后面的中間件的process_view方法、視圖都不執行,直接執行最后一個中間件的process_response方法,再返回給瀏覽器

      process_exception(self, request, exception)

      執行時間(觸發的條件):
      ? 視圖函數執行之后,視圖有異常時才執行
      執行順序:
      ? 按照注冊的順序 倒序執行
      參數:
      ? request - 和視圖中的request對象是同一個
      ? exception - 錯誤的對象
      返回值:
      ? None: 正常流程 ,交給下一個中間件處理異常,都返回的是None,交給django處理異常(大黃頁)
      ? HttpResponse對象: 后面的中間件的process_exception方法不執行,直接執行最后一個中間件的process_response方法,再返回給瀏覽器

      process_template_response(self,request,response)

      執行時間(觸發條件):
      ? 視圖函數執行之后,要求視圖函數返回的對象是TemplateResponse對象
      執行順序:
      ? 按照注冊的順序 倒序執行
      參數:
      ? request - 和視圖中的request對象是同一個
      ? response - 視圖函數返回的響應對象
      返回值:
      ? HttpResponse對象: 必須返回

      csrf相關的裝飾器

      csrf_exempt # 當前的視圖不需要CSRF校驗
      csrf_protect # 當前的視圖需要CSRF校驗

      from django.views.decorators.csrf import csrf_exempt, csrf_protect
      from django.views.decorators.csrf import ensure_csrf_cookie
      @ csrf_exempt   
      def  login(request) 普通函數直接加
      

      CBV中 csrf_exempt只能加在dispatch上或是類上

      @method_decorator(csrf_exempt,name='dispatch')
      

      csrf中間件步驟

      1. 請求到來時執行process_request方法:
        從cookie中獲取csrftoken的值 —— 》 賦值給 request.META['CSRF_COOKIE']
      2. 執行process_view方法:
        1. 查看視圖是否加了csrf_exempt裝飾器:
          1. 有 不需要csrf 校驗 返回none
          2. 沒有 需要csrf 校驗
        2. 請求方式的判斷:
          1. 如果是 'GET', 'HEAD', 'OPTIONS', 'TRACE' 不需要csrf 校驗 返回none
          2. 其他方式需要csrf 校驗
        3. 進行CSRF校驗:
          1. 從request.META獲取到csrftoken的值
          2. 嘗試從表單中獲取csrfmiddlewaretoken的值:
            1. 能獲取到
              csrfmiddlewaretoken的值和cookie中的csrftoken值做對比
              1. 對比成功 通過csrf校驗
              2. 對比不成功 不通過csrf校驗 拒絕請求
            2. 獲取不到 嘗試從請求頭中獲取x-csrftoken的值
              x-csrftoken的值和cookie中的csrftoken值做對比
              1. 對比成功 通過csrf校驗
              2. 對比不成功 不通過csrf校驗 拒絕請求
      json 和XML對比

      JSON 簡單的語法格式和清晰的層次結構明顯要比 XML 容易閱讀,并且在數據交換方面,由于 JSON 所使用的字符要比 XML 少得多,可以大大得節約傳輸數據所占用得帶寬。

      ajax

      (Asynchronous Javascript And XML)翻譯成中文就是“異步的Javascript和XML”,
      AJAX 不是新的編程語言,而是一種使用現有標準的新方法

      定義: 是一個js的技術,發送請求的一種途徑。
      特點:

      1. 異步 2. 局部刷新 3. 傳輸的數據量小(xml json)

      發請求的途徑:

      • 地址欄上輸入地址 GET
      • a標簽 GET
      • form表單 GET/POST

      簡單實例 固定格式

      $.ajax({
          url:'/calc/',
          type:'post',
          data:{
              i1:$('[name="i1"]').val(),
              i2:$('[name="i2"]').val(),
          },
          success:function (res) {
              $('[name="i3"]').val(res)
          }
      })
      

      參數

       $.ajax({
          url: '/ajax_test/',   # 請求的地址
          type: 'post',		# 請求的方式
          data: {				# 請求的數據
              name: 'alex',
              age: 73,
              hobby: JSON.stringify(['裝逼', '作死', '賣燒餅'])  #將對象轉成字符串
          },
      success: function (res) { # 成功后執行的函數
      location.href=地址  重定向   #返回時不要redirect了
          },
          error: function (res) {			# 失敗后執行的函數
              console.log(res)
          },
      })
      


      ret=json.loads(ret)
      print(ret,type(ret)) #<class 'list'>

      ajax上傳文件

      ajax通過django的csrf校驗
      1. 確保csrftoken的cookie

        1. 一個加
        2. 給視圖函數加裝飾器
      2. 提供參數

        1. 給data添加數據
          data: {
          csrfmiddlewaretoken:隱藏標簽或是cookie
          csrfmiddlewaretoken: $('[name="csrfmiddlewaretoken"]').val(),
          i1: $('[name="i1"]').val(),
          i2: $('[name="i2"]').val(),
          },
          ? 2. 加x-csrftoken的請求頭
          headers: {
          'x-csrftoken': 隱藏標簽或是cookie
          'x-csrftoken': $('[name="csrfmiddlewaretoken"]').val(),
          },
          3.文件導入
        <script src="/static/ajax_setup.js"></script> 
        

      總結:json

                           數據交換的格式
                      Python
                      ?	數據類型: 數字 字符串 列表 字典  布爾值  None
                      ?	轉化:
                      ?		序列化   Python的類型  ——》 json的字符串
                      ?		json.dumps(Python的類型)
                      ?		json.dump(Python的類型, f )
                      ?		反序列化     json的字符串   ——》   Python的類型
                      ?		json.loads( json的字符串)
                      ?		json.load(f )
                      js
                      ?	數據類型: 數字 字符串 列表 字典 布爾值  null
                      ?	轉化:
                      ?		序列化  js的類型  ——》 json的字符串
                      ?		JSON.stringify( js的類型  )
                      ?		反序列化     json的字符串   ——》   JS的類型
                      ?		JSON.parse( json的字符串 )
                      JsonResponse({})      #  contentType  :application/json
                      JsonResponse([],safe=False)
      

      form組件 是一個類

      from django import forms
      class RegForm(forms.Form):
         user = forms.CharField()
         pwd = forms.CharField()
      # gender=forms.CharField(widget=forms.Select(choices=((1,'男'),(2,'女')))) #單選下拉框
      # gender=forms.CharField(widget=forms.SelectMultiple(choices=((1,'男'),(2,'女')))) #多選
      # gender=forms.ChoiceField(choices=((1,'男'),(2,'女')),
      widget=forms.widgets.RadioSelect()   #單選radio
      )  #單選下拉框
          gender=forms.MultipleChoiceField(choices=((1,'男'),(2,'女'))) #多選
      

      使用: 在views

      form_obj=ReForm()   #實例化對象
      form_obj = RegForm(request.POST)  #把post提交過來的數據直接傳進去
      return render(request,'reg2.html',{'form_obj':form_obj })   
      

      模板 :

      {{ form_obj.as_p }}    ——》 生成p標簽   label 和 input標簽
      {{ form_obj}  input框
      {{ form_obj.user }}    ——》 字段對應的input標簽
      {{ form_obj.user.id_for_label }}     ——》 input標簽的ID
      {{ form_obj.user.label }}    ——》 字段對應的input標簽的中文
      {{ form_obj.user.errors }}   ——》 當前字段的所有錯誤信息
      {{ form_obj.user.errors.0 }} ——》 當前字段的第一個錯誤信息
      {{ form_obj.non_field_errors.0 }} __all__的錯誤的顯示
      

      form組件的主要功能如下:

      • 生成頁面可用的HTML標簽
      • 對用戶提交的數據進行校驗
      • 保留上次輸入內容

      form字段

      CharField        文本
      ChoiceField      選擇框
      MultipleChoiceField   多選框
      

      字段參數
      在form標簽里寫上novalidate ,就不提示錯了(取消瀏覽器的提示錯誤)

      widget=forms.PasswordInput   #密碼是密文      label=’中文’
      required=True,               是否允許為空
      widget=None,                 HTML插件
      label=None,                  用于生成Label標簽或顯示內容
      initial=None,                初始值 (設置默認值)
      error_messages=None,         錯誤信息 {'required': '不能為空', 'invalid': '格式錯誤'}
      validators=[],               自定義驗證規則
      disabled=False,              是否可以編輯
      is_valide()是否驗證成功
      

      關于choice的注意事項:

      在使用選擇標簽時,需要注意choices的選項可以從數據庫中獲取,但是由于是靜態字段 獲取的值無法實時更新,那么需要自定義構造方法從而達到此目的。

      方法一:在類里面定義一個__init取繼承父類

      方法二:

      from django.forms import models as form_model
      hobby=form_model.ModelMultipleChoiceField(queryset=models.Hobby.objects.all())
      

      校驗

      1). 內置校驗

          min_length=8,
          max_length
          required=True
      

      2). 自定義校驗

          Validators=[check]
          字段的參數  
      
          validators=[check,RegexValidator()],
           1. 寫函數
              
              from django.core.exceptions import ValidationError 
              def check(value):
                 # 自定義校驗規則
                 # 通過校驗  不用返回
                 # 沒有通過校驗  拋出異常   raise ValidationError('有非法字符')
          2. 內置的校驗器
      
              from django.core.validators import RegexValidator
                  phone = forms.CharField(
              	    	validators=[RegexValidator(r'^1[3-9]\d{9}$', '手機號格式不正確')]
      
      is_valid()的流程:
      1. 執行self.errors的方法 ——》 self.full_clean()
      2. full_clean方法():
        1. 定義一個存放錯誤信息的字典 self._errors = ErrorDict()
        2. 定義一個存放正確(經過校驗)值 的字典 self.cleaned_data = {}
        3. 執行self._clean_fields():
        4. 依次循環所有的字段
        5. 執行內部的校驗 和 自定義校驗器的校驗 value = field.clean(value)
        6. 將正確的值放在self.cleaned_data self.cleaned_data[name] = value
        7. 有局部鉤子就執行
          1. 通過校驗 self.cleaned_data[name] 重新賦值
          2. 不通過校驗 self.cleaned_data[name] 當前字段的鍵值對被清除 self._errors中存放當前字段的錯誤信息
        8. 執行self._clean_form() ——》 self.clean()
          1. 如果有重新定義就執行
            1. 通過校驗 返回所有的值 self.cleaned_data 重新賦值
            2. 不通過校驗 把錯誤信息添加到 all 中

      局部鉤子和全局鉤子

           from django.core.exceptions import ValidationError
      
      
          def clean_user(self):
              # 局部鉤子
              value = self.cleaned_data.get('user')  # alex
              # 通過校驗規則 返回正確的值  (你可以修改)
              return "{}dsb".format(value)
              # 不通過校驗規則 拋出異常
              raise ValidationError('錯誤提示')
      
      
          def clean(self):
              # 全局鉤子
              # 通過校驗規則 返回正確的值(所有的值 self.cleaned_data  )  (你可以修改)
              # 不通過校驗規則 拋出異常
              pwd = self.cleaned_data.get('pwd')
              re_pwd = self.cleaned_data.get('re_pwd')
              if pwd == re_pwd:
                  return self.cleaned_data
              raise ValidationError('兩次密碼不一致')
      

      modelform組件

      'oncontextmenu':"return false"是不讓你右鍵點擊

      from django import forms
      from django.core.exceptions import ValidationError
      
      
      class RegForm(forms.ModelForm):
          password = forms.CharField(min_length=6, widget=forms.PasswordInput(attrs={'placeholder': '您的密碼'}))
          re_password = forms.CharField(min_length=6, widget=forms.PasswordInput(attrs={'placeholder': '確認您的密碼'}))
      
          class Meta:
              model = models.UserProfile
              fields = '__all__'  # ['字段名']
              exclude = ['is_active']
      
              widgets = {
                  'username': forms.TextInput(attrs={'placeholder': '您的用戶名'}),
                  'password': forms.PasswordInput(attrs={'placeholder': 'xxxxx'}),
                  'name': forms.TextInput(attrs={'placeholder': '您的真實姓名'}),
                  'mobile': forms.TextInput(attrs={'placeholder': '您的手機號'}),
              }
      
              error_messages = {
                  'username': {'invalid': '請輸入正確的郵箱地址'}
      
              }
      
          def clean(self):
              # 獲取到兩次密碼
              password = self.cleaned_data.get('password')
              re_password = self.cleaned_data.get('re_password')
              if password == re_password:
                  # 加密后返回
                  md5 = hashlib.md5()
                  md5.update(password.encode('utf-8'))
                  password = md5.hexdigest()
                  self.cleaned_data['password'] = password
                  # 返回所有數據
                  return self.cleaned_data
              # 拋出異常
              self.add_error('re_password', '兩次密碼不一致!!')
              raise ValidationError('兩次密碼不一致')
      

      字段的展示:

      1. 普通字段
      	{{ 對象.字段名 }}
      2. choice參數
      	對象.字段名   ——》 數據庫的值
          對象.get_字段名_display()      ——》顯示 中文
          {{ 對象.get_字段名_display }}   放在前端不加括號
      	外鍵字段  對象(__str__)
      3. 自定義方法  models里
      	def show_classes(self):
      		return ' | '.join([str(i) for i in self.class_list.all()])
          {{ 對象.show_classes }}
      

      safe

      不需要轉義 和safe一樣
      在后端用mark_safe 在前端用safe

      from django.utils.safestring import mark_safe
      mark_safe(<span style="background-color: {};color: white;padding: 4px">{}</span>)
      

      編輯時, instance=obj : 把原始數據放到這里,給頁面展示
      Request.POST:獲取提交的值

      Git

      https://gitee.com/
      1.配置:
      先去當前項目找,沒有就去全局配置找
      全局配置命令:vim ~/.gitconfig文件查看

      Git config –-global  user.email  ‘qi@live.com’  
      Git config –-global  user.name  ‘qi’
      

      項目配置命令:當前項目下 vim .git/config 文件查看

      Git config –-local user.email  ‘qi@live.com’  
      Git config –-local user.name  ‘qi’
      

      系統配置命令:vim /etc/gitconfig文件查看

      Git config –-system user.email  ‘qi@live.com’  
      Git config –-system user.name  ‘qi’
      注意: 需要有root權限
      

      基本命令如下

      Git init  :先創建個空庫     
      git status: 查看狀態    
      git add .  :添加    
      git add 文件    
      get --version : 查看版本
      git commit –m’添加注冊和登錄功能’  :提交到本地 
      Git log :查看版本信息    
      git reset :是回滾到commit之前,(還可以重新修改,在提交)    
      git reset –hard ‘版本號’ :回到最原始的位置(會刪除本地的代碼)
      Git reflog :查看版本號    在會滾回來還是git reset –hard ‘版本號’
      Git clone 遠程倉庫地址
      
      給遠程倉庫起別名:Git remote add origin 遠程倉庫地址
      Git stash :保存 
      Git stash list : 查看“某個地方”存儲的所有記錄
      Git stash clear : 清空某個地方
      Git stash drop  :編號 ,刪除指定編號的記錄
      
      git push origin master:最后提交到服務器碼云   
      git pull origin  master :拉代碼,從遠程拉到本地 
      ==>
      Git fetch origin master : 去倉庫 獲取 
      +
      git merge origin/master-和網上下的master分支合并
      
      git show <commit-hashId> 便可以顯示某次提交的修改內容
      同樣 git show <commit-hashId> filename 可以顯示某次提交的某個內容的修改信息。
      如何把分支A 上某個commit應用到分支b上:git cherry-pick <commit id>
      
      
      git config --list  #查看git配置信息
      

      diff 即比較文件在暫存區和工作區的差異

    3. 尚未緩存的改動:git diff
    4. 查看已緩存的改動: git diff --cached
    5. 查看已緩存的與未緩存的所有改動:git diff HEAD
    6. 顯示摘要而非整個 diff:git diff --stat
    7. 顯示暫存區和工作區的差異:

      $ git diff [file]
      

      顯示暫存區和上一次提交(commit)的差異:

      $ git diff --cached [file]
      或
      $ git diff --staged [file]
      

      顯示兩次提交之間的差異:

      $ git diff [first-branch]...[second-branch]
      

      2.rebase變基
      使git記錄簡潔(除了第1條后邊的全整合在一起),多個記錄 ——》1個記錄

      用法:git rebase 分支
      1)Rebase第一種:
      第一步:Git rebase -i HEAD~3

      第二步:把第二,三行pick 變成s, s代表把當前版本合并到上一個版本,最終v3,v4都合并到v2中了

      第三步:

      HEAD~3:合并前3條
      注:合并記錄時不要把已提交(push)到倉庫的代碼合并,容易起沖突

      2)rebase第二種:

      • 第一步:git branch dev touch dev1.py git add git commit
      • 第二步:git checkout master touch master1.py git add git commit
      • 第三步:git checkout dev git rebase master(在dev上合并master)
      • 第四步:git checkout master git merge dev(切換到master,再合并dev)
        Git log --graph --pretty=format:”%h %s” 結果就是一條簡單的直線

      3)Rebase第三種:

      git pull origin  master (有分叉)
      ==》
      Git  fetch origin   dev
      +
      Git  rebase  origin  master/dev
      

      3.記錄圖形展示

      Git log --graph
      git log --graph --pretty=format:"%h %s"
      

      4.merge 和 rebase命令的區別

      Merge一次性展示所有沖突,rebase每次展示一次commit提交的沖突
      Merge保留完整的歷史記錄,rebase會重寫歷史記錄

      5. git rebase 產生沖突

      方法一:git add 文件名

      Git  rebase  --continue
      

      方法二:

      分支

      git branch   查看
      git branch   dev   新建dev分支
      git branch  -d  dev   刪除dev分支
      git checkout  dev   切換到dev分支
      git merge   dev     從dev合并到當前分支(有沖突 手動解決),在commit一下
      Git clone -b v2 http:xxx  :克隆    #-b 指定版本
      git checkout -b dev :創建并切換到分支
      

      注:先切換分支在合并,切換到merge,再把dev合并到merge

      在家開發一半,再到公司開發...

      origin只是名稱,可以換成任意如:xx等
      git clone 是指在一臺新電腦上沒有代碼的情況下使用,他會把所有的代碼以及所有分支,提交記錄都可以有。
      剛開始提交到云端時把master 和dev一起提交上去。
      如果在家本地已經有代碼,想跟公司的同步,使用pull命令就可以更新。


      在公司開發了一半,著急去吃飯,只把代碼提交到了本地版本庫,忘記提到云端,等回到家拉下的代碼不是最新的,但也不能在重新寫吧,就繼續寫新功能,在家寫完的代碼push到了云端,第二天去公司pull新代碼時出現了沖突,手動解決沖突,然后繼續開發下邊的功能,最后提交到云端。

      在公司把代碼提到本地,忘記提到云端。
      沖突指的是:在公司改了a1.py, 回家也改了a1.py, 修改了同一行數據,造成的沖突。

      1.修改代碼
      2. git add .
      3. git commit -m '女神約飯'
      

      回到家:

      1. git pull origin dev  
      此時功能不是最新的,也不可能把寫過的在寫一遍,就開發些新功能吧
      2. git add .
      3. git commit -m '在家開發了其他新功能'
      4. git push origin dev   #推到云端
      

      到公司:

      1. git pull origin dev 
      這時出現了沖突,vim文件,手動刪除
      2. vim a1.py 
      3. 繼續開發新功能
      4. git add .
      5.git commit -m '合并之后并開發完畢'
      6. git  push origin dev
      

      **單人開發 **

      新建一個dev分支   開發新功能
      開發完成 合并到master分支
      有bug  新建debug分組    
      到debug分支上修改bug 
      修改完成 合并到master分支  并且刪除debug分支
      

      多人協作開發

      遠程倉庫中每人有自己的分支
      在本地開發  開發完成后提交到自己的分支
      
      提交pull requests 合并到dev分支上
      
      Github (倉庫,小公司,網站):花錢放到別人的倉庫
      Gitlab  (工具,大公司,開源軟件)是一個用于倉庫管理系統的開源項目,使用Git作為代碼管理工    具:自己公司搭建一個屬于自己的倉庫,自己買服務器,自己有管理員,頁避免代碼泄露
      

      第一步:創建項目

      1. 寫代碼
      2. git add .
      3.git commit -m '東北熱基本功能'
      4. Git remote add origin 地址
      5. git push -u origin master 
      6. 在master分支 git log 下
      7. git tag -a v1 -m '第一版'    #  tag:打標簽,-a: 版本叫v1,-m: 版本描述   這是在本地打了個標簽    圖1
      8. git push origin --tags  #推送到倉庫   圖2
      

      圖1:
      圖2 :

      第二步: 創建分支邀請成員

      1. git checkout -b dev 
      2. git branch
      3. git push origin dev
      4. 在github邀請成員
      

      第三步:小弟拉代碼繼續開發

      1. git clone 地址
      2. git checkout dev  #切換到Dev分支
      3. git checkout -b ddz #在Dev分支上在創建一個ddz分支繼續開發
      4. touch doudizhu.py
          git add .
          git commit -m '斗地主功能開發中'
          git push origin ddz
      5. vim doudizhu.py  #回家繼續開發
         git add .
          git commit -m '加班開發完成'
          git push origin ddz
      

      第四部: 給leader審核代碼并合并到dev, 在github上合并的代碼,看視頻吧
      第五步: leader開發的release分支合并到master,有兩種方式,一個是在github上合并,一個就是命令,如下

      1. git checkout dev  #切換到Dev
      2. git checkout -b release # 在Dev分支上創建了一個分支,此時release和Dev的代碼一樣
      3. git push origin release # 吧release 推上去,提測人員就可以吧這個代碼拉走去提測,有問題直接修改就行(到這一步已經在線上github上合并了,下面是在本地合并一下)
      4. git merge  release #吧release合并到 Dev
      5. git checkout master  #切換到master
      6. 你本地還沒有ddz功能,需要先拉一下代碼
          git checkout master 
          git pull origin master 
      7. git tag -a v2 -m '第二版 增加斗地主功能'
      8. git push origin --tags  # 吧tag標簽推送上去
      

      免密碼登錄
      在url中體現

      gitignore的作用:

      配置 git 需要忽略的文件或文件夾,在 .gitignore 文件配置的文件或文件夾不會隨著 git 提交到你的倉庫

      修改 git 歷史提交 commit 信息(重寫歷史)

      https://www.jianshu.com/p/0f1fbd50b4be
      git 已經提交了,如何去修改以前的提交信息

      解決方法

      修改最新的 log
      如果只修改最新一條提交信息的 log 內容,直接使用命令 git commit --amend 就可以

      修改歷史的 log
      假設提交記錄如下:

      $ git log
      commit 9ac1179332670365a3e5ea00a6486998eb66db7a (HEAD -> fix_aop_no_class_defined, origin/fix_aop_no_class_defined)
      Author: candyleer <295198088@qq.com>
      Date:   Mon Apr 16 19:58:23 2018 +0800
      
          update test case
      
          Signed-off-by: candyleer <295198088@qq.com>
      
      commit 223fc80d17273b19238dcb648e6d6eefc579de0f
      Author: candyleer <295198088@qq.com>
      Date:   Mon Apr 16 18:47:50 2018 +0800
      
          unit test case
      
          Signed-off-by: candyleer <295198088@qq.com>
      
      commit 2275781a0d75add037721832bd68c1a8edb3813e
      Author: candyleer <295198088@qq.com>
      Date:   Mon Apr 16 18:29:29 2018 +0800
      
          should find method from parent
      
      1. 執行 git 命令, 修改近三次的信息

        $ git rebase -i HEAD~3

      將會得到提交日志是和git log倒敘排列的,我們要修改的日志信息位于第一位.

        1 pick 2275781 should find method from parent
        2 pick 223fc80 unit test case
        3 pick 9ac1179 update test case
        4
        5 # Rebase 79db0bd..9ac1179 onto 79db0bd (3 commands)
        6 #
        7 # Commands:
        8 # p, pick = use commit
        9 # r, reword = use commit, but edit the commit message
      

      2.我們現在要修改修改要should find method from parent這條日志,那么修改的日志為,將第一個pick 修改為edit, 然后 :wq 退出.

        1 edit 2275781 should find method from parent
        2 pick 223fc80 unit test case
        3 pick 9ac1179 update test case
      

      將會看到如下信息,意思就是如果要改日志,執行git commit --amend,如果修改完成后,執行git rebase --continue

      client_java git:(fix_aop_no_class_defined) git rebase -i HEAD~3
      Stopped at 2275781...  should find method from parent
      You can amend the commit now, with
      
        git commit --amend
      
      Once you are satisfied with your changes, run
      
        git rebase --continue
      ?  client_java git:(2275781)
      

      3.正式修改,執行命令,-s 就是自動加上Signed-off-by:

      $ git commit --amend -s 
      
      client_java git:(63b2cfd) git commit --amend -s
      [detached HEAD c46b30e] 1should find method from parent
       Date: Mon Apr 16 18:29:29 2018 +0800
       1 file changed, 4 insertions(+), 1 deletion(-
      

      修改完成后,:wq 退出,然后完成此次 log 的rebase

      $ git rebase --continue
      
      client_java git:(c46b30e) git rebase --continue
      Successfully rebased and updated refs/heads/fix_aop_no_class_defined.
      

      4.這樣本地修改就完成啦,用git log 再看下:

      commit 449efc747ffb85567667745b978ed7e3418cfe27 (HEAD -> fix_aop_no_class_defined)
      Author: candyleer <295198088@qq.com>
      Date:   Mon Apr 16 19:58:23 2018 +0800
      
          update test case
      
          Signed-off-by: candyleer <295198088@qq.com>
      
      commit 69237c0bd48439ea0d8b87bf2c7c7ac4786c66d4
      Author: candyleer <295198088@qq.com>
      Date:   Mon Apr 16 18:47:50 2018 +0800
      
          unit test case
      
          Signed-off-by: candyleer <295198088@qq.com>
      
      commit c46b30e456af6ecdf4a629a485e5efe5485e52b1
      Author: candyleer <295198088@qq.com>
      Date:   Mon Apr 16 18:29:29 2018 +0800
      
          1should find method from parent
      
          Signed-off-by: candyleer <295198088@qq.com>
      

      所有信息都有Signed-off-by:這個參數了

      5。最后push 到遠程倉庫,所有的 DCO 就都可以加上啦,-f強制推送

       git push origin <you_branch_name> -f
      

      分頁

      url

      from django.conf.urls import url
      from django.contrib import admin
      from app01 import views
      
      urlpatterns = [
          url(r'^admin/', admin.site.urls),
          url(r'^user_list/', views.user_list),
      ]
      

      views

      from django.shortcuts import render,redirect,HttpResponse
      
      users = [ {'name': 'alex-{}'.format(i),'password':123} for i in range(1,304)]
      
      def user_list(request):
          '''
          :param request:
          :return:
          page_num : 頁碼數
          '''
          try:
              page_num = int(request.GET.get('page','1'))
              if page_num <=0:  #page_num : 頁碼數  page=1
                  page_num = 1
          except Exception as e:
              page_num = 1
          #每頁顯示數據條數
          per_num = 10
          # 獲取總數量
          all_count = len(users)
          #獲取總頁碼數
          total_page_num, more  = divmod(all_count, per_num)
          if more:
              total_page_num +=1
          #最多顯示頁碼數
          max_show  = 11
          half_show = max_show // 2
          #總頁碼數不足以滿足最大頁碼數
          if total_page_num < max_show:
              page_start = 1
              page_end = total_page_num
          else:
              #頁碼數顯示負數時
              if page_num -half_show <= 0:
                  page_start = 1
                  page_end = max_show
              #頁碼數顯示超過總頁碼數時
              elif page_num + half_show > total_page_num:
                  page_start = total_page_num -max_show +1
                  page_end = total_page_num
              else:
                  #頁碼起始值
                  page_start = page_num -half_show
                  #頁碼終止值
                  page_end = page_num + half_show
      
          '''
          1  0  10
          2  10  20
          3  20  30
          '''
          start = (page_num-1) * per_num
          end = page_num * per_num
      
          return render(request,'user_list.html',{'users':users[start:end], 'total_page_num': range(page_start, page_end+1)})
      

      user_list.html

      <!DOCTYPE html>
      <html lang="en">
      <head>
          <meta charset="UTF-8">
          <title>Title</title>
      </head>
      <body>
      <table class="table table-bordered">
          <tbody>
      
          {% for user in users %}
              <tr>
                  <td>{{ user.name }}</td>
                  <td>{{ user.password }}</td>
              </tr>
          {% endfor %}
          </tbody>
      </table>
      
      {% for foo in total_page_num %}
              <tr>
      {#            <ul>#}
                      <a href="?page={{ foo }}"> {{ foo }}</a>
      {#            </ul>#}
              </tr>
      
          {% endfor %}
      </body>
      </html>
      

      第二種寫法:
      在py文件中循環
      改變的代碼如下:
      views:

      #return render(request,'user_list.html',{'users':users[start:end], 'total_page_num': range(page_start, page_end+1)})
      page_list = []
      for i in range(2,11):
          page_list.append('<li><a href="?page={}"> {}</a></li>'.format(i,i))
      page_html = ''.join(page_list)    
      return render(request,'user_list.html',{'users':users[start:end], "page_html":page_html})
      

      html:

        </tbody>
      </table>
      
      {{page_html | safe }}
      </body>
      </html>
      

      添加上頁下一頁的標簽
      接著以上代碼繼續寫
      py文件:

              else:
              #頁碼起始值
              page_start = page_num -half_show
              #頁碼終止值
              page_end = page_num + half_show
      
      page_list = []
      # 上一頁
      if page_num == 1:
          page_list.append( '<li class="disabled"><a><span>&laquo;</span></a></li>')
      else:
          page_list.append('<li><a href="?page={}"><span>&laquo;</span></a></li>'.format(page_num-1))
      for i in range(page_start,page_end+1):
          page_list.append('<li><a href="?page={}">{}</a></li>'.format(i,i))
      
      
      # 下一頁
      if page_num == total_page_num:
          page_list.append('<li class="disabled"><a><span>&raquo;</span></a></li>')
      else:
          page_list.append('<li><a href="?page={}"><span>&raquo;</span></a></li>'.format(page_num + 1))
      page_html = ''.join(page_list)
      

      html文件中還是如上。

      給頁碼加被選中的狀態

    8. py文件:
       for i in range(page_start,page_end+1):
          # 加選中的狀態
          if i == page_num:
              page_list.append('<li class="active"><a href="?page={}">{}</a></li>'.format(i, i))
          else:
              page_list.append('<li><a href="?page={}">{}</a></li>'.format(i,i))
      

      封裝成類的形式完整代碼

      pagnation.py

      class Pagination:
          def __init__(self,page_num,all_count,max_show=11,per_num=10 ):
              try:
                  page_num = int(page_num)
                  if page_num <= 0:  # page_num : 頁碼數  page=1
                      page_num = 1
              except Exception as e:
                  self.page_num = 1
              self.page_num = page_num
              # 每頁顯示數據條數
              self.per_num = per_num
      
              # 獲取總數量
              self.all_count = all_count
              # 獲取總頁碼數
              total_page_num, more = divmod(all_count, per_num)
              if more:
                  total_page_num += 1
              half_show = max_show // 2
              # 總頁碼數不足以滿足最大頁碼數
              if total_page_num < max_show:
                  page_start = 1
                  page_end = total_page_num
              else:
                  # 頁碼數顯示負數時
                  if page_num - half_show <= 0:
                      page_start = 1
                      page_end = max_show
                  # 頁碼數顯示超過總頁碼數時
                  elif page_num + half_show > total_page_num:
                      page_start = total_page_num - max_show + 1
                      page_end = total_page_num
                  else:
                      # 頁碼起始值
                      page_start = page_num - half_show
                      # 頁碼終止值
                      page_end = page_num + half_show
              self.page_start = page_start
              self.page_end = page_end
              self.total_page_num = total_page_num
          @property
          def page_html(self):
              page_list = []
              # 上一頁
              if self.page_num == 1:
      
                  page_list.append('<li class="disabled"><a><span>&laquo;</span></a></li>')
              else:
                  page_list.append('<li><a href="?page={}"><span>&laquo;</span></a></li>'.format(self.page_num - 1))
              for i in range(self.page_start, self.page_end + 1):
                  # 加選中的狀態
                  if i == self.page_num:
                      page_list.append('<li class="active"><a href="?page={}">{}</a></li>'.format(i, i))
                  else:
                      page_list.append('<li><a href="?page={}">{}</a></li>'.format(i, i))
      
              # 下一頁
              if self.page_num == self.total_page_num:
                  page_list.append('<li class="disabled"><a><span>&raquo;</span></a></li>')
              else:
                  page_list.append('<li><a href="?page={}"><span>&raquo;</span></a></li>'.format(self.page_num + 1))
              return ''.join(page_list)
      
              '''
              1  0  10
              2  10  20
              3  20  30
              '''
          @property
          def start(self):
      
              return (self.page_num - 1) * self.per_num
          @property
          def end(self):
              return self.page_num * self.per_num
      

      在py文件中直接引用
      views.py

      from django.shortcuts import HttpResponse, render, redirect,     reverse
      from app01.pagination import Pagination
      users = [ {'name': 'alex-{}'.format(i),'password':123} for i in range(1,304)]
      
      def user_list(request):
          '''
          :param request:
          :return:
          page_num : 頁碼數
          '''
          page = Pagination(request.GET.get('page','1'),len(users))
      
          return render(request,'user_list.html',{'users':users[page.start:page.end], 'page_html': page.page_html})
      

      html 代碼如上

      posted on 2020-03-05 17:19  xm微微一笑  閱讀(101)  評論(0)    收藏  舉報

      導航

      主站蜘蛛池模板: 大地资源中文第三页| 国产精品久久自在自线不卡| 亚洲AV高清一区二区三区尤物| 中文文字幕文字幕亚洲色| 国产精品99久久不卡| 老妇xxxxx性开放| 人人入人人爱| 一级做a爰片在线播放| 国产麻豆放荡av激情演绎| 亚洲中文字幕无码爆乳| 男女啪啪免费观看网站| 亚洲性线免费观看视频成熟| 美腿丝袜亚洲综合第一页| 国产乱人伦av在线无码| 亚洲和欧洲一码二码三码| 日韩有码中文字幕av| 国产午夜三级一区二区三| 人妻系列无码专区免费| 欧美亚洲日本国产综合在线美利坚| 亚洲高清有码中文字| 丰满少妇在线观看网站| 亚洲成人精品综合在线| 国产品精品久久久久中文| 奇米777四色影视在线看| 色综合色综合色综合频道| 亚洲精品成人片在线观看精品字幕| 国产精品无码不卡在线播放| 国产精品视频中文字幕| 老熟女重囗味hdxx69| 欧美高清一区三区在线专区| 久久91精品牛牛| 成人午夜国产内射主播| 无码福利写真片视频在线播放| 精品人妻少妇一区二区三区| 免费人成视频在线观看网站| 一级女性全黄久久片免费| h无码精品动漫在线观看| 国产色一区二区三区四区| 中文字幕日韩有码一区| 天堂mv在线mv免费mv香蕉| 亚洲gv天堂无码男同在线观看|