django rest framework restful 規範

 

內容回顧:
    1. django請求生命週期
        
        -> 執行遵循wsgi協議的模塊(socket服務端)
        -> 中間件(路由匹配)
        -> 視圖函數(業務處理:ORM、模板渲染)
        -> 中間件
        -> wsgi返回
        
    2. 什麼wsgi
        web服務網關接口
        實現該協議的模塊:
            - wsgiref
            - werkzurg
            - uwsig

    3. 視圖
        - FBV
            url - 函數 
        - CBV 
            url - view
    
    4. djang rest framework
        
    
    5. restful 規範(10)
        什麼是接口?
            - URL
            - 約束
                # 約束繼承(實現)了他的類中必須含有IFoo中的方法
                interface IFoo:
                    def func(self): pass 
                    
                    
                class Foo(IFoo):
                    def func(self): 
                        print(11111)
        

        1. 根據method不一樣,進行不一樣操做
            GET/POST/PUT/DELETE/PATCH
        2. 面向資源編程
            http://www.luffycity.com/salary
        
        3. 體現版本
            http://www.luffycity.com/v1/salary
            http://www.luffycity.com/v2/salary
            
            https://v4.bootcss.com/
            https://v3.bootcss.com/
        4. 體現是API
            http://www.luffycity.com/api/v1/salary
            http://www.luffycity.com/api/v2/salary    
            
            http://api.luffycity.com/v1/salary    
            http://api.luffycity.com/v2/salary    
        5. https
            https://www.luffycity.com/api/v1/salary
            https://www.luffycity.com/api/v2/salary    
            
        6. 響應式設置狀態碼
            200
            300
            400
            500
            return HttpResponse('adfasdf',status=300)
        
        7. 條件 
            https://www.luffycity.com/api/v2/salary?page=1&size=10
        
        8. 返回值
            https://www.luffycity.com/api/v2/salary
            GET: 全部列表
            {
                code: 10000,
                data: [    
                    {'id':1,'title':'高亮'},
                    {'id':1,'title':'龍泰'},
                    {'id':1,'title':'小東北'},
                ]
            }
                
            POST: 返回新增的數據
                {'id':1,'title':'高亮'}
                
            https://www.luffycity.com/api/v2/salary/1/
            GET: 獲取單條數據
                    {'id':1,'title':'高亮'}
            PUT:更新
                    {'id':1,'title':'高亮'}
            PATCH: 局部更新
                    {'id':1,'title':'高亮'}
            DELETE:刪除
                
        9. 返回錯誤信息
            {
                code: 100001,
                error: 'xxx錯誤'
            }
        
        10. Hypermedia API
            ret = {
                code: 1000,
                data:{
                    id:1,
                    name:'小強',
                    depart_id:http://www.luffycity.com/api/v1/depart/8/
                }
            }
    
        建議你們使用restful規範
        
        
    6. django rest framework框架(10- 權限
        - 認證
        - 訪問頻率限制
        - 序列化
        - 路由 
        - 視圖
            面試題:你的寫的類都繼承過哪些類?
            class View(object):
            
            class APIView(View):
            
            class GenericAPIView(views.APIView):
            
            class GenericViewSet(ViewSetMixin, generics.GenericAPIView)
            
            class ModelViewSet(mixins.CreateModelMixin,
                   mixins.RetrieveModelMixin,
                   mixins.UpdateModelMixin,
                   mixins.DestroyModelMixin,
                   mixins.ListModelMixin,
                   GenericViewSet):
        - 分頁 
        - 解析器
        - 渲染器
        - 版本 

    
今日內容:
    - vue
    - restful api 
    
內容詳細:
    1. 渲染器
       規定頁面顯示的效果(無用)
    2. 版本 
        原理:要了解
        使用:
            1. 添加配置
                REST_FRAMEWORK = {
                    
                    .... 
                    
                    'DEFAULT_VERSIONING_CLASS':'rest_framework.versioning.URLPathVersioning',
                    'ALLOWED_VERSIONS':['v1','v2'], # 容許的版本
                    'VERSION_PARAM':'version', # 參數
                    'DEFAULT_VERSION':'v1', # 默認版本
                    ....
                }

            2. 設置路由 
                
                s9luffycity/urls.py
                    urlpatterns = [
                        #url(r'^admin/', admin.site.urls),
                        url(r'^api/(?P<version>\w+)/', include('api.urls')),
                    ]
                
                api/urls.py 
                    urlpatterns = [
                        url(r'^course/$', course.CourseView.as_view()),
                    ]
            
            3. 獲取版本 
                request.version 獲取版本  
            
    
    3. vue+rest framework
        vue: 
            - 路由 + 組件 
            - axios發送ajax請求
            - that 
        api:
            - 跨域 
            
        補充:
            - 域名不一樣
            - 端口不一樣 
        cors:
            本質設置響應頭
                    
                    # 容許你的域名來獲取個人數據
                    response['Access-Control-Allow-Origin'] = "*"

                    # 容許你攜帶Content-Type請求頭
                    response['Access-Control-Allow-Headers'] = "Content-Type"

                    # 容許你發送DELETE,PUT
                    response['Access-Control-Allow-Methods'] = "DELETE,PUT"
        
    
做業:
    1.建立兩張表
        課程表:
             id    title    
             1    Python全棧
             2    Python週末
             3    Linux
        課程詳細表:
            id     name        course_id
            1    Python基礎      1
            2    Python進階      1
            3    Python網絡      1
            4    Python併發      1
            5    Python數據庫      1
            6    Python前端      1

    2. 兩個頁面
        - 課程列表
        - 課程詳細 

 

內容回顧:
    - restful 規範(10- django rest framework框架(10- 跨域
        - 爲何會有跨域?
        - 繞過瀏覽器同源策略就能夠跨域。
            - jsonp
                動態建立script標籤
                同源策略會阻止ajax請求;不阻止具備src屬性的標籤
                <script src='xxxx'></script>
            - cors
                設置響應頭
            
今日內容:
    - vue 
    - api
    
    
    
內容詳細:
    1. vue
        - 課程列表
        - 課程詳細
        
        - 任務:    
            - 課程表 
                id   title  course_img   level(choices) 
            - 課程詳細(one2one  課程 )
                id   why  推薦課程
            - 章節 
                id    name  
        - 功能:
            a. 課程列表顯示圖片
            
            b. 課程詳細顯示:
                - 爲何要學習這個課程
                - 全部推薦課程
                - 全部章節
                 
    2. api
        1. 查詢全部的課程
            http://127.0.0.1:8000/api/v1/course/
            練習:level變中文
            
        2. 查詢課程詳細 
            http://127.0.0.1:8000/api/v1/course/1/
            - 路由 as_view 是否添加參數,取決於視圖繼承的類
            - 序列化
                - depth
                - source
                - 自定義method
            
            練習:顯示該課程相關的全部章節
            
    this補充:
        題目1:
            var name = '景女神'

            function Foo(name,age){
                this.name = name;
                this.age = age;
                this.getName = function(){
                    console.log(this.name); # 文州
                    
                    (function(){
                        console.log(this.name); # 女神
                    })()
                    
                }
            }

            obj = new Foo('文州',19)
            obj.getName()

        題目2:
            var name = '景女神'

            function Foo(name,age){
                this.name = name;
                this.age = age;
                this.getName = function(){
                    console.log(this.name); # 文州
                    var that = this 
                    (function(){
                        console.log(that.name); # 文州
                    })()
                    
                }
            }

            obj = new Foo('文州',19)

            obj.getName()

        題目3:
            var name = '景女神'
            obj = {
                name:'文州',
                age: 19,
                getName:function(){
                    console.log(this.name); # 文州
                    var that = this 
                    (function(){
                        console.log(that.name); # 文州
                    })()
                }
            }
            obj.getName()

    
做業:
    1. 先後端流程
    2. 圖片 
    3. CC視頻帳號
    4. git相關
        - 安裝git軟件
        - 註冊github帳號

 

 

內容回顧:
    1. 你理解的Http協議?
        - 創建在tcp之上
        - 一次請求一次響應而後斷開鏈接(無狀態、短鏈接)
        - 請求和響應
            發送:請求頭\r\n\r\n請求體
                  host:www.luffy.com\r\ncontent-type:application/json\r\n\r\n請求體
            響應:響應頭\r\n\r\n響應體
                  ...
    2. django請求生命週期
        
    3. wsgi
        
    4. django中間件是什麼?
        
    5. 使用中間件作過什麼?
        - 內置
            - csrf
            - session
        - 自定義
            - 登陸認證
            - 權限
            - cors
    6. 中間件中有多少個方法?
        5個
    
    7. FBV和CBV是什麼?以及優缺點。
    
    8. rest api 
        
    9. django rest framework框架
        
    10. 視圖常見的繼承
        from rest_framework.views import APIView # *
        from rest_framework.generics import GenericAPIView
        from rest_framework.viewsets import GenericViewSet # as_view
        from rest_framework.viewsets import ModelViewSet # *
    
    11. 如何實現的訪問頻率控制?
        匿名用戶:沒法控制,由於用戶能夠換代理IP
            {
                192.168.1.1:[1521223123.232, 1521223122.232, 1521223121.232],
                192.168.1.2:[1521223123.232, 1521223122.232, 1521223121.232],
                192.168.1.3:[1521223123.232, 1521223122.232, 1521223121.232],
                192.168.1.4:[1521223123.232, 1521223122.232, 1521223121.232],
                192.168.1.5:[1521223123.232, 1521223122.232, 1521223121.232],
                192.168.1.6:[1521223123.232, 1521223122.232, 1521223121.232],
            }
        
        
        登陸用戶:若是有不少帳號,也沒法限制
            {
                alex:[1521223123.232, 1521223122.232, 1521223121.232],
                eric:[1521223123.232, 1521223122.232, 1521223121.232],
            }
        
        參考源碼:from rest_framework.throttling import SimpleRateThrottle
        
    12. 序列化
        - source
        - method 
    
    
    
今日內容:
    1. 示例
        - 推薦課程
        - 用戶登陸
        - 攔截器
        
        
        VUE:
            - 課程列表:this.$axios + this 
            - 課程詳細:this.$axios + this 
            - 用戶登陸:
                - this.$axios
                - this 
                - 跨域簡單和複雜請求
                - vuex作全局變量
                - vuex-cookies 
            - 微職位 
                - 攔截器
                - 攜帶token 
            
            PS: api能夠同一放在store中保存
            
        API:
            - 課程列表 
                - 序列化:source='get_level_display'
            - 課程詳細:
                - 序列化:source='get_level_display'
                - 序列化:method
            - 用戶登陸 
                - update_or_create
            - 微職位 
                - 認證組件 
            
            關聯組件:
                - 版本
                - 解析器
                - 渲染器
                - 序列化 
                - 認證組件 
                - 視圖 
                - 路由 
            
            
    2. django組件:contenttype
        組件的做用:能夠經過兩個字段讓表和N張表建立FK關係
        
        
        表結構:
            from django.db import models
            from django.contrib.contenttypes.models import ContentType

            from django.contrib.contenttypes.fields import GenericForeignKey, GenericRelation


            class DegreeCourse(models.Model):
                """學位課程"""
                name = models.CharField(max_length=128, unique=True)
                course_img = models.CharField(max_length=255, verbose_name="縮略圖")
                brief = models.TextField(verbose_name="學位課程簡介", )


            class Course(models.Model):
                """專題課程"""
                name = models.CharField(max_length=128, unique=True)
                course_img = models.CharField(max_length=255)

                # 不會在數據庫生成列,只用於幫助你進行查詢
                policy_list = GenericRelation("PricePolicy")


            class PricePolicy(models.Model):
                """價格與有課程效期表"""
                content_type = models.ForeignKey(ContentType)  # 關聯course or degree_course
                object_id = models.PositiveIntegerField()

                #不會在數據庫生成列,只用於幫助你進行添加和查詢
                content_object = GenericForeignKey('content_type', 'object_id')


                valid_period_choices = (
                    (1, '1天'),
                    (3, '3天'),
                    (7, '1周'), (14, '2周'),
                    (30, '1個月'),
                    (60, '2個月'),
                    (90, '3個月'),
                    (180, '6個月'), (210, '12個月'),
                    (540, '18個月'), (720, '24個月'),
                )
                valid_period = models.SmallIntegerField(choices=valid_period_choices)
                price = models.FloatField()

        使用:
            # 1.在價格策略表中添加一條數據
            # models.PricePolicy.objects.create(
            #     valid_period=7,
            #     price=6.6,
            #     content_type=ContentType.objects.get(model='course'),
            #     object_id=1
            # )

            # models.PricePolicy.objects.create(
            #     valid_period=14,
            #     price=9.9,
            #     content_object=models.Course.objects.get(id=1)
            # )

            # 2. 根據某個價格策略對象,找到他對應的表和數據,如:管理課程名稱
            # price = models.PricePolicy.objects.get(id=2)
            # print(price.content_object.name) # 自動幫你找到

            # 3.找到某個課程關聯的全部價格策略
            # obj = models.Course.objects.get(id=1)
            # for item in obj.policy_list.all():
            #     print(item.id,item.valid_period,item.price)
            #
        
    3. 表結構 
內容回顧:
    1. 爲何會有跨域?
        瀏覽器具備同源策略全部纔出現跨域。
        同源策略:
            - 開放:src
            - 禁止:ajax
        解決跨域:
            - jsonp,在客戶端動態建立一個script標籤
                1.客戶端:建立一個 
                    <script src='http://www.jxntv.cn/data/jmd-jxtv2.html'></script>
                    <script>
                        function func(arg){
                            alert(arg);
                        }
                    </script>
                2.服務端:接收到請求並處理並返回值 "func('success')"
                    至關於:
                        <script>
                            func('success')
                        </script>
                        
                PS: jsonp只能發送GET請求
                
            - cors,設置響應響應響應響應響應頭
                - 簡單請求
                - 複雜請求
                    - options請求作預檢
                    - PUT/POST....
                    
        在django中解決方案:
            - 中間件中設置響應頭
            - django中的一個第三方組件:cors
                
        補充:
            jQuery Ajax:
                $.ajax({
                    ...
                })
            原生Ajax:XMLHttpRequest對象:
                var xhr = new XMLHttpRequest()
                
                xhr.onreadystatechange = function(){
                    if(xhr.readyState == 4){
                        // 已經接收到所有響應數據,執行如下操做
                        var data = xhr.responseText;
                        console.log(data);
                    }
                };
                
                xhr.open('POST', "/test/", true);
                
                // 設置請求頭
                xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded; charset-UTF-8');
                
                // 發送請求
                xhr.send('n1=1;n2=2;');
                
    2. restful 規範
    
    3. 你理解的http協議?    
    
    4. 常見請求頭
        - Content-Type 
        - User-Agent
        - referer,能夠作圖片防盜鏈。
        - Host
        - cookies

    5. 常見的請求方法:
        - GET/POST/DELETE/PUT/PATCH/OPTIONS

    6. 常見的狀態碼:
        - 200
        - 301/302
        - 403/404
        - 500
        
    7. 序列化 
    
    8. ORM補充:
        a. 需求: 只取某n列
            queryset=[ {},{}]
            models.User.objects.all().values( 'id','name')
            
            queryset=[ (),()]
            models.User.objects.all().values_list( 'id','name')
            
            queryset=[ obj,obj]
            result = models.User.objects.all().only('id','name','age')    
            # result = models.User.objects.all().defer('id','name','age')    
            for item in reuslt:
                print(item.id,item.name,item.age)
        b. 需求: 打印全部用戶姓名以及部門名稱
            
            class depart:
                title = ....
            
            
            class User:
                name = ...
                dp = FK(depart)
                
            # select * from user 
            # result = models.User.objects.all()
            # for item in result:
            #     print(item.name)
            
            # select * from user left join depart on user.dp_id = depart.id 
            # result = models.User.objects.all().selected_related('dp')
            # for item in result:
                #print(item.name,item.dp.title )

今日內容:
    1. 路飛學城表結構
        - 課程
        - 深科技
        
    2. 支付寶支付
    
    
內容詳細:
    1. 路飛學城表結構
        - 課程
            - 學位課(導師、獎學金、分模塊、週期)
            - 專題課 (小柯,週期)
        - 深科技

    2. 支付寶支付 
        a. 去支付寶申請 
            - 正式:營業執照
            - 測試:沙箱測試環境
                    APPID:2016082500309412
                    買家:
                        nbjsag5718@sandbox.com
                        111111
                        111111
        b. 開發程序
            SDK
                - 官方
                - github
                    pay.py 
                    依賴:pip3 install pycryptodome
            
            公鑰私鑰:
                - 應用公鑰
                    - 支付寶公鑰
                - 應用私鑰
                
內容回顧:
    1. Http協議?
        Http協議就是一個傳輸數據格式。
        
        我原來學習django框架,從socket服務端開始學起。
        本身創造了一個socket服務器來充當:網站。
        瀏覽器當socket客戶端。
        更清楚的明白到底http協議是什麼?
            - 請求頭 請求頭
            - 響應頭 響應頭
        
        一次請求響應後,斷開鏈接。
    2. 常見請求頭 
        
    3. 常見的請求體?
        Form表單提交:
            POST /index http1.1\r\nhost:www.luffycity.com...\r\n\r\nusername=alex&password=123&...
        Ajax請求:
            POST /index http1.1\r\nhost:www.luffycity.com...\r\n\r\nusername=alex&password=123&...
            POST /index http1.1\r\nhost:www.luffycity.com...\r\n\r\n{「username」:"alex","password":123}
            
        補充:django中獲取請求體
            - request.POST 
            - request.body 
            
    4. django請求生命週期
        - wsgi, 他就是socket服務端,用於接收用戶請求並將請求進行初次封裝,而後將請求交給web框架(Flask、Django)
        - 中間件,幫助咱們對請求進行校驗或在請求對象中添加其餘相關數據,例如:csrf、request.session 
        - 路由匹配 
        - 視圖函數,在視圖函數中進行業務邏輯的處理,可能涉及到:orm、templates => 渲染
        - 中間件,對響應的數據進行處理。
        - wsgi,將響應的內容發送給瀏覽器。
        
    5. 中間件
        - 5個方法 
        - 應用場景:
            - 登陸認證,再也不須要在每一個函數中添加裝飾器
            - 權限,當用戶登陸時候獲取當前用戶全部權限並放入session,而後再次訪問其餘頁面,獲取當前url並在session中進行匹配。若是沒有匹配成功,則在中間件返回「無權訪問」
            - 跨域,
                    - jsonp,動態建立一個script標籤。
                    - cors,設置響應頭
                    應用:本地開始先後端分離的時使用。
        
    6. ORM操做
        - only
        - defer
        - seleted_related
        - prefetch_related
    
        示例:
            class Depart(models.Model): 5個部門
                title = models.CharField(...)

            class User(models.Model):   10個用戶
                name = models.CharField(...)
                email = models.CharField(...)
                dp = models.FK(Depart)

            1.之前的你:11次單表查詢

                result = User.objects.all()
                for item in result:
                    print(item.name,item.dp.title)

            2. seleted_related,主動作連表查詢(1次鏈表)

                result = User.objects.all().seleted_related('dp')
                for item in result:
                    print(item.name,item.dp.title)

                問題:若是鏈表多,性能愈來愈差。

            3. prefetch_related:2次單表查詢
                # select * from user ;
                # 經過python代碼獲取:dp_id = [1,2]
                # select * from depart where id in dp_id
                result = User.objects.all().prefetch_related('dp')
                for item in result:
                    print(item.name,item.dp.title)

        
        贈送:
            數據量比較大,不會使用FK,容許出現數據冗餘。
        
    7. django rest framework的做用?
        快速搭建基於restful規範的接口。
    
    8. 你理解的 restful 規範?
        restful是一個規範,規定API如何編寫,經過他可讓咱們api更加簡潔可維護。
        如,最直觀的:
            method:
                - get
                - post 
                - put 
                - delete 
            
            原來都是url中設置的。
        除此以外:
            - api
            - 版本
            - 名詞
            - 條件
            - 狀態碼
            - 返回值
            - 錯誤信息
            - hypermedia link 
    
    9. django rest framework組件:
        
        - 訪問頻率控制原理:
            匿名:
                1.1.1.1:[時間,時間,時間,時間,]
            登陸:
                user:[時間,時間,時間,時間,] 
            
            默認將訪問記錄放在緩存中:redis/memcached
        - 序列化
            from rest_framework.serializers import Serializer

            class XX(Serializer):
                pass
            ser =XX(queryset,many=True) # ListSerializer對象
            ser =XX(obj, many=False)    # XX對象
                
        - 列表生成式 
        
        - 根據字符串的形式,自動導入模塊並使用反射找到模塊中的類【參考:s9day108】。
    
    

今日內容:
    1. 深科技表結構
    2. git
    
    
內容詳細:
    1. 深科技表結構(6表)
        

        # ######################## 深科技相關 ########################
        class ArticleSource(models.Model):
            """文章來源"""
            name = models.CharField(max_length=64, unique=True)

            class Meta:
                verbose_name_plural = "16. 文章來源"

            def __str__(self):
                return self.name

        class Article(models.Model):
            """文章資訊"""
            title = models.CharField(max_length=255, unique=True, db_index=True, verbose_name="標題")
            source = models.ForeignKey("ArticleSource", verbose_name="來源")
            article_type_choices = ((0, '資訊'), (1, '視頻'))
            article_type = models.SmallIntegerField(choices=article_type_choices, default=0)
            brief = models.TextField(max_length=512, verbose_name="摘要")
            head_img = models.CharField(max_length=255)
            content = models.TextField(verbose_name="文章正文")
            pub_date = models.DateTimeField(verbose_name="上架日期")
            offline_date = models.DateTimeField(verbose_name="下架日期")
            status_choices = ((0, '在線'), (1, '下線'))
            status = models.SmallIntegerField(choices=status_choices, default=0, verbose_name="狀態")
            order = models.SmallIntegerField(default=0, verbose_name="權重", help_text="文章想置頂,能夠把數字調大,不要超過1000")
            vid = models.CharField(max_length=128, verbose_name="視頻VID", help_text="文章類型是視頻, 則須要添加視頻VID", blank=True, null=True)
            comment_num = models.SmallIntegerField(default=0, verbose_name="評論數")
            agree_num = models.SmallIntegerField(default=0, verbose_name="點贊數")
            view_num = models.SmallIntegerField(default=0, verbose_name="觀看數")
            collect_num = models.SmallIntegerField(default=0, verbose_name="收藏數")

            # tags = models.ManyToManyField("Tags", blank=True, verbose_name="標籤")
            date = models.DateTimeField(auto_now_add=True, verbose_name="建立日期")

            position_choices = ((0, '信息流'), (1, 'banner大圖'), (2, 'banner小圖'))
            position = models.SmallIntegerField(choices=position_choices, default=0, verbose_name="位置")


            #comment = GenericRelation("Comment")

            class Meta:
                verbose_name_plural = "17. 文章"

            def __str__(self):
                return "%s-%s" % (self.source, self.title)

        class Collection(models.Model):
            """收藏"""
            content_type = models.ForeignKey(ContentType)
            object_id = models.PositiveIntegerField()
            content_object = GenericForeignKey('content_type', 'object_id')

            account = models.ForeignKey("Account")
            date = models.DateTimeField(auto_now_add=True)

            class Meta:
                unique_together = ('content_type', 'object_id', 'account')
                verbose_name_plural = "18. 通用收藏表"

        class Comment(models.Model):
            """通用的評論表"""
            content_type = models.ForeignKey(ContentType, blank=True, null=True, verbose_name="類型")
            object_id = models.PositiveIntegerField(blank=True, null=True)
            content_object = GenericForeignKey('content_type', 'object_id')

            p_node = models.ForeignKey("self", blank=True, null=True, verbose_name="父級評論")
            content = models.TextField(max_length=1024)
            account = models.ForeignKey("Account", verbose_name="會員名")
            disagree_number = models.IntegerField(default=0, verbose_name="")
            agree_number = models.IntegerField(default=0, verbose_name="贊同數")
            date = models.DateTimeField(auto_now_add=True)

            def __str__(self):
                return self.content

            class Meta:
                verbose_name_plural = "19. 通用評論表"

        class Account(models.Model):
            username = models.CharField("用戶名", max_length=64, unique=True)
            password = models.CharField("密碼", max_length=64)

        class UserAuthToken(models.Model):
            """
            用戶Token表
            """
            user = models.OneToOneField(to="Account")
            token = models.CharField(max_length=64, unique=True)
    
    
    2. git 
        git是一個用於幫助用戶實現版本控制的軟件。
        
        命令:
            git init 
            
            git status             查看當前文件夾的狀態。
            git add 文件名        對指定文件進行版本控制
            git add .            對指定文件夾下的全部文件及子目錄進行版本控制
            git commit -m '詳細的描述信息' 建立提交記錄(版本)
            
            git log 
            git reflog 
            
            git reset --hard 提交記錄(版本號)

 

相關文章
相關標籤/搜索