• Python的重要知识点汇总2


    使用socket 模拟服务器 给 浏览器 发 数据:

     1 import socket
     2 
     3 sk = socket.socket()
     4 sk.bind(('127.0.0.1',8080))
     5 sk.listen()
     6 
     7 while 1:
     8     conn, addr = sk.accept()
     9     d = conn.recv(1024)
    10     # print(d.decode())
    11     conn.send(b'HTTP/1.1 200 OK
    
    ') # 和 浏览器通信 要遵守 http 协议
    12     conn.send(b'<h1>Welcome come to my site! </h1>')
    13     print('haha')
    14 
    15     conn.close()
    16 sk.close()
    17 
    18 
    19 # http 协议
    20 '''
    21 GET / HTTP/1.1
    22 
    23 '''
    24 '''
    25 HTTP/1.1 200 OK
    26 
    27 hello world
    28 '''
    server.py

    此时 浏览器 输入 127.0.0.1:8080 就可以访问收到 我们回复的内容了, 

    Django 框架: 

    目录:https://www.cnblogs.com/clschao/articles/10526431.html

     

    简单 web框架: 

    Django基础一之web框架的本质: https://www.cnblogs.com/clschao/articles/10391859.html

     1 from wsgiref.simple_server import make_server
     2 from op_db import getUserData
     3 from jinja2 import Template
     4 
     5 def index():
     6     # {'id': 1, 'name': 'tom', 'age': 18}
     7     userinfo = getUserData()
     8     print(userinfo)
     9     with open("index.html","rb") as f:
    10         d = f.read()
    11 
    12     tpl_str = Template(d.decode())
    13     ret = tpl_str.render({'data':userinfo})
    14     return ret.encode()
    15 
    16 
    17 def ico():
    18     with open("favicon.ico","rb") as f:
    19         d = f.read()
    20     return d
    21 
    22 def application(environ, start_response):
    23     start_response('200 OK', [('k1','v1'),])
    24     path = environ['PATH_INFO']
    25 
    26     urlpatterns = [
    27         ('/',index),
    28         ('/favicon.ico', ico),
    29     ]
    30     for i in urlpatterns:
    31         if i[0] == path:
    32             data = i[1]()
    33     return [data]
    34 
    35 if __name__ == '__main__':
    36     httpd = make_server('127.0.0.1', 8080, application)
    37     print('Serving HTTP on port 8080...')
    38     httpd.serve_forever()
    简单web 框架
     1 <!DOCTYPE html>
     2 <html lang="zh-CN">
     3 <head>
     4     <meta charset="utf-8">
     5     <meta http-equiv="X-UA-Compatible" content="IE=edge">
     6     <meta name="viewport" content="width=device-width, initial-scale=1">
     7     <title>hello world</title>
     8     <style>
     9         h1{
    10             background-color: deeppink;
    11         }
    12     </style>
    13 </head>
    14 <body>
    15     <h1>你好,{{data['name']}}</h1>
    16     <h1>我今年:{{data['age']}}岁 </h1>
    17     <ul>
    18         <li>哈哈哈哈好</li>
    19         <li>哈哈哈哈好</li>
    20         <li>哈哈哈哈好</li>
    21         <li>哈哈哈哈好</li>
    22         <li>哈哈哈哈好</li>
    23         <li>哈哈哈哈好</li>
    24         <li>哈哈哈哈好</li>
    25     </ul>
    26     <h1>{{data}}</h1>
    27 
    28     <ul>
    29         {%  for k,v in data.items() %}
    30             <li>{{k}}:{{v}}</li>
    31         {%  endfor    %}
    32     </ul>
    33 
    34 
    35 </body>
    36 </html>
    index.html
     1 import pymysql
     2 
     3 def getUserData():
     4     conn = pymysql.connect(
     5         host='127.0.0.1',
     6         port=3306,
     7         user='root',
     8         password='123456',
     9         database='test',
    10         charset='utf8'
    11     )
    12     try:
    13         cursor = conn.cursor(pymysql.cursors.DictCursor)
    14         cursor.execute('select * from userinfo limit 2;')
    15         ret = cursor.fetchone()
    16         conn.commit()
    17     except:
    18         conn.rollback()
    19 
    20     cursor.close()
    21     conn.close()
    22 
    23     return ret
    op_db.py

    url 分发: 

    正则分组,

    url 分发 (include  )

    视图函数 : 

    总体上是: FBV (function base view)  和  CBV (class base view)  

    对FBV  使用 装饰器 判断阻拦请求,

    对CBV 可以直接在 dispatch() 函数中 判断阻拦请求 ,也可以在CBV下写 装饰器,不过要借助 django 的 

    from django.utils.decorators import method_decorator   

    用时: @method_decorator(dec

     1 from django.shortcuts import render,redirect
     2 from django.shortcuts import HttpResponse
     3 
     4 # Create your views here.
     5 from django.views import View
     6 
     7 def home(request):
     8     '''
     9     项目首页
    10     :return:
    11     '''
    12     if request.method == 'GET':
    13 
    14         pass
    15     elif request.method == 'POST':
    16         pass
    17 
    18 
    19     return render(request,'home.html')
    20 
    21 def app03_home(request):
    22     return HttpResponse('这是 app03的首页')
    23 
    24 def dec(f):
    25     def inner(*args,**kwargs):
    26         # 搞事情
    27         request = args[0]
    28         print(request.META)
    29         ua = request.META['HTTP_USER_AGENT']
    30         #此时就可以 根据ua 来判断了
    31         if 'Chrome' in ua:
    32             # 合法
    33             ret = f(request)
    34             return ret
    35         else:
    36             return HttpResponse("请求不合法")
    37 
    38     return inner
    39 
    40 # 加装饰器 来判断请求是否合法
    41 @dec
    42 def login(request):
    43     if request.method == 'GET':
    44          return render(request, 'login.html')
    45     elif request.method == 'POST':
    46         username = request.POST.get('username')
    47         password = request.POST.get('password')
    48         if username == 'zcb' and password == '123':
    49             # return HttpResponse('登陆成功') # 跳转到 登陆成功页面
    50             # print('suc')
    51             # return render(request,'login_success.html') # 这种方式  不太好
    52             return redirect('/app03/login_success/')
    53 
    54         else:
    55             return HttpResponse('登陆失败')
    56 def login_success(request):
    57 
    58     return render(request,'login_success.html')
    59 
    60 
    61 from django.utils.decorators import method_decorator
    62 # CBV 类的方式 login2
    63 class Login2(View):
    64     def dispatch(self, request, *args, **kwargs):
    65         print('请求来了')
    66         # 这里可以先 判断  request 的合法性,如果不合法,就不调用 下面的 方法,
    67 
    68         ret = super().dispatch(request,*args,**kwargs)
    69         print('请求结束了')
    70         return ret
    71 
    72     # @method_decorator(dec)  #CBV 下使用装饰器
    73     def get(self,request):
    74         return render(request,'login2.html')
    75 
    76     def post(self,request):
    77         username = request.POST.get('username')
    78         password = request.POST.get('password')
    79         if username == 'zcb' and password == '123':
    80             return redirect('/app03/login_success/')
    81         else:
    82             return HttpResponse('登陆失败')
    给 login(FBV)和 login2(CBV ) 都加上了 装饰器 dec

    request 相关: 

    request.META : ua 等信息都在这, 

    request.path_info 

    request.path 

    request.method

    request.GET        --->  .get()  .getlist()

    request.POST      --->  .get()  .getlist()

    response 相关: 

    HttpResponse 对象 是回复 字符串,

    render() 回复一个页面

    redirect()  重定向到一个新的页面,  

    模板系统 : 

    https://files.cnblogs.com/files/zach0812/django%E6%A8%A1%E6%9D%BF%E7%B3%BB%E7%BB%9F.zip

    关于模板渲染你只需要记两种特殊符号(语法):

      {{ }}和 {% %}

      变量相关的用{{}},逻辑相关的用{%%}。

    万能的 点 .  

    过滤器( 操作 数据  )| :   

    标签 (逻辑操作 数据 在 {%  %} 里操作  ):

    模板继承 

    当有重复代码的时候,使用模板继承 可以省很多 代码,例如 管理的后台页面,   

    在模板中 加上 {% block % }  槽,  

    其他 文件中 通过    {%   extends 'filename'      % } 来引入模板,  

    组件 化   

    自定义标签和过滤器

    如果 内置的 标签(逻辑相关)  和 过滤器(对数据再操作  )  不能满足我们的需求,可以自定义,  

    在app中创建templatetags模块(模块名只能是templatetags)

    创建任意 .py 文件,如:my_tags.py

     1 from django import template  # 导入 文件
     2 
     3 register = template.Library() #创建一个注册器
     4 # register 固定的名字
     5 
     6 
     7 @register.filter
     8 def zz(val,val2=''):  # 自定义 过滤器
     9     # 它的作用是 后面加上  ~    过滤器的参数最多有两个!!!
    10 
    11     return val + '~'+val2
    12 
    13 @register.simple_tag   # 自定义标签
    14 def tt(val,val2,val3):  # 可以传多个参数
    15     # 它的作用是 后面加上 ~
    16     return val + val2+ val3 +'~'
    17 
    18 
    19 # 自定义 组件 标签  (作用 是 先将 test.html 渲染好之后,直接作为组件使用)
    20 @register.inclusion_tag('test.html')
    21 def func(val):
    22 
    23     data = [11,22,33]
    24     data.append(val)
    25 
    26     return {'data':data}
    my_filter_tags.py
    1 <div style="background-color: purple;color: #fff;"> 我去 </div>
    2 <ul>
    3     {% for d in data %}
    4         <li>{{ d }}</li>
    5     {% endfor %}
    6 </ul>
    test.html
     1 <!DOCTYPE html>
     2 <html lang="zh-CN">
     3 <head>
     4     <meta charset="utf-8">
     5     <meta http-equiv="X-UA-Compatible" content="IE=edge">
     6     <meta name="viewport" content="width=device-width, initial-scale=1">
     7     <title>hello world</title>
     8 </head>
     9 <body>
    10     {% load my_filter_tags %}   <!-- 自定义 过滤器(操作数据的 方法 )  -->
    11 {#    <h1>欢迎{{ name | zz }} 来到登陆页面</h1>#}
    12     <h1>欢迎{{ name | zz:'~' }} 来到登陆页面</h1>
    13 
    14     {% tt name name name %}   <!-- 自定义 标签 空格 加参数  -->
    15     {% func 44 %} <!-- 自定义 组件 标签   -->
    16 
    17     <form action="/app03/login/" method="post">
    18         {% csrf_token %}
    19         用户名:<input type="text" name="username">
    20         密  码:<input type="text" name="password">
    21         <input type="submit">
    22     </form>
    23 
    24 </body>
    25 </html>
    login.html 这里是用到自定义标签 和 过滤器的地方

    静态文件:  

    把一些  css,js ,jpg .mp4 等文件  加进来, 当服务器请求 这些 .css 等文件的时候,django 就会自动的读取 发送给浏览器, 

    引入时:  

    ORM --- 单表查询 : 

     1 from django.db import models
     2 
     3 # Create your models here.
     4 
     5 class Student(models.Model):
     6     # id = models.AutoField(primary_key=True)  # 默认的
     7     name = models.CharField(max_length=16)
     8     age = models.IntegerField()
     9     date = models.DateField(null=True) # 该字段允许 为空
    10 
    11 
    12 
    13     def __str__(self):
    14         # 当print (self) 的时候 就会 调用 self.__str__()
    15         return self.name
    models.py
      1 from django.shortcuts import render,redirect,HttpResponse
      2 
      3 # Create your views here.
      4 from app01 import models # 利用orm 操作数据库
      5 
      6 def index(request):
      7     #
      8     '''
      9     # 创建 记录方式1
     10     stu = models.Student(name='tom',age=18)
     11     stu.save()
     12 
     13     # 创建 记录方式2
     14     # models.Student.objects # 可理解  可通过objects来增删 改查,
     15     new_obj = models.Student.objects.create(name='e',age=10)
     16     print(new_obj)  # Student object
     17     print(new_obj.name)
     18     print(new_obj.age)
     19     '''
     20 
     21     # 增 ---  批量 插入
     22     '''
     23     objs = []
     24     for i in range(30): # 30个记录
     25         obj = models.Student(
     26             name = 'tom%s'%i,
     27             age = 10 + i,
     28         )
     29         objs.append(obj)
     30     models.Student.objects.bulk_create(objs) # 速度快  
     31     '''
     32 
     33     # 增 --- update_or_create  有就 更新 无则创建
     34     '''
     35     models.Student.objects.update_or_create(
     36         name='jack', # 如果有 name 的话,就 改 为下面 的默认值  ,如果没 的话 ,就创建. 
     37         defaults={
     38             'age':40  
     39         }
     40     )
     41 
     42     '''
     43 
     44 
     45     # 简单 查询
     46     '''
     47     # 简单 查询之 ---查询 所有的 数据
     48     all_objs = models.Student.objects.all()
     49     print(all_objs)   # QuerySet 类型 类似列表
     50     for obj in all_objs:
     51         print(obj.name)
     52     # 简单 查询之 --- filter 返回的 QuerySet  QuerySet 对象也可以调用 filter() 
     53     # 条件 查询 数据 filter() # 查询失败 不报错,返回为  空。
     54     objs = models.Student.objects.filter(id=8); # id 为8 的记录
     55     print(objs)
     56 
     57     # 简单 查询之 --- get返回的 model 对象 (Student 对象 )
     58     # 条件 查询 数据 get() 而且 get() 方法有且只有 一个结果,多了少了  都报错 。
     59     objs = models.Student.objects.get(id=8);
     60     print(objs)
     61     
     62     '''
     63 
     64     # 删除 delete
     65     '''
     66     # 通过 stu 对象 来调用删除
     67     # models.Student.objects.get(id=7).delete() # 需要先把它查出来,然后再删除
     68 
     69     # 通过 QuerySet 对象  来调用删除
     70     # models.Student.objects.filter(id=8).delete()
     71 
     72     # models.Student.objects.all().delete()   # 删除 表中  所有的数据
     73     '''
     74 
     75     # 更新
     76     '''
     77     # stu 对象 不能 update
     78     # models.Student.objects.get(name='jane').update(age = 38)  # stu对象 不能 更新
     79     models.Student.objects.filter(name='jane').update(age = 38) # QuerySet 对象 可以
     80     '''
     81 
     82     # 更多查询  都是重点
     83     #01 多条件 查询,
     84     '''
     85     sets = models.Student.objects.filter(age=38,name='jane')    #条件之间是 and 的关系
     86 
     87     # 关键字参数 也可以传个 字典~   打散传参 要注意 ,key value 都要是 字符串,  
     88     # sets = models.Student.objects.filter(**{'age':38,'name':'jane'}) # 也可以如下格式
     89     print(sets)
     90     
     91     
     92     # 除了 filter()  get 也支持  多条件, 它返回的是  stu 对象 返回结果  有且只能有一个,  
     93     '''
     94 
     95     # 02 排除 exclude , 排除 仅仅是 筛选出来 ,并没有删除原有的数据   # objects  和 queryset对象都可以调用
     96     '''
     97     set = models.Student.objects.exclude(id=9)
     98     print(set) # 返回的是个 QuerySet 对象
     99 
    100     set = models.Student.objects.filter(age=38).exclude(id=9) # 先筛选 再 exclude  两次过滤。
    101     print(set)
    102     '''
    103 
    104     #03  排序 orderby  原有数据 没变
    105     '''
    106     set = models.Student.objects.all().order_by('age','-id') # 意思是 先按 age 升序 ,然后 按id 降序
    107     print(set)   # 默认是升序 ,降序 用 -
    108     '''
    109     #04 反转 reverse  # 反转 必须在 order_by 的基础上 来 做  。
    110     '''
    111     set = models.Student.objects.all().order_by('id').reverse()
    112     print(set)
    113     '''
    114 
    115     #05 计数 count
    116     '''
    117     num = models.Student.objects.all().count() # 查询 之后 结果的 set 的 数量
    118     print(num)
    119     '''
    120 
    121     #06 first
    122     '''
    123     obj = models.Student.objects.all().first() # 返回 结果是 stu 对象
    124     print(obj)
    125     '''
    126 
    127     #07 last
    128     '''
    129     obj = models.Student.objects.all().last()   # 返回 结果是 stu 对象
    130     print(obj)
    131     '''
    132 
    133 
    134     #08 exist
    135     '''
    136     # 它 比 直接 if res: 效率高, exist 只要有一个 符合就返回了,
    137     flag = models.Student.objects.filter(name='jane').exists() # 返回 bool
    138     print(flag)
    139     '''
    140 
    141     #09 values_list 和 values
    142     '''
    143     set = models.Student.objects.filter(age=38)
    144     print(set)
    145 
    146     set =  models.Student.objects.filter(age=38).values_list() # 把所有 values 变为元素返回
    147     print(set)  # 它照样是 set 对象, 但是里面的数据 变为了 元组,
    148 
    149     set =  models.Student.objects.filter(age=38).values_list('name','age')
    150     print(set)
    151 
    152     set =  models.Student.objects.filter(age=38).values()
    153     print(set) # 里面变为 了字典  values_list  和 values 相当于 pymysql 中的 游标中的 元组 和 字典 ~
    154     set =  models.Student.objects.filter(age=38).values('name','age')
    155     print(set)
    156     '''
    157 
    158     #10 去重 主要用在 values_list  和 values  后 ;  因为如果是all(),filter() 都包含 id ,而id 是肯定不会重复的
    159     '''
    160     set = models.Student.objects.values_list('age').distinct().count()
    161     print(set)
    162     '''
    163 
    164     #11 基于双下划线 的模糊查询  相当于 数据库 like
    165     # set = models.Student.objects.filter(id>20) # 这种写法是错误的, 不支持 大于
    166     # 大于
    167     set = models.Student.objects.filter( id__gt = 20 ) # 此时id > 20
    168     print(set)
    169 
    170     # 大于等于  gte
    171     # 小于 lt
    172     # 小于等于 lte
    173 
    174     # 在... 里面 in
    175     set = models.Student.objects.filter( id__in = [20,22,30] )  # 在 后面三个中的 都要
    176     print(set)
    177 
    178     #range    []  左右 都闭区间
    179     set = models.Student.objects.filter(age__range=[18,30])
    180     print(set)
    181 
    182     #包含 contains  该字段 必须要是 字符串
    183     set = models.Student.objects.filter(name__contains='tom') #默认区分大小写
    184     print(set)
    185 
    186     set = models.Student.objects.filter(name__icontains='tom') #i  不区分大小写
    187     print(set)
    188 
    189     #以 ... 开头 startswith
    190     set = models.Student.objects.filter(name__startswith='ja')
    191     print(set)
    192 
    193     #以 ... 结尾 endswith
    194     set = models.Student.objects.filter(name__endswith='e')
    195     print(set)
    196 
    197     # 查询  与日期相关 比较重要~
    198     set = models.Student.objects.filter(date='2000-11-11')
    199     print(set)
    200     set = models.Student.objects.filter(date__year='2000')
    201     print(set)
    202     set = models.Student.objects.filter(date__year='2000',date__month='12')
    203     print(set)
    204     set = models.Student.objects.filter(date__year='2000',date__month='12',date__day='8')
    205     print(set)
    206     # 查看  大于 2000-12-8
    207     set = models.Student.objects.filter(date__year='2000',date__month='12',date__day__gt='8')
    208     print(set)
    209 
    210 
    211 
    212     return render(request,'index.html')
    views.py
      1 """
      2 Django settings for orm_pro project.
      3 
      4 Generated by 'django-admin startproject' using Django 1.11.9.
      5 
      6 For more information on this file, see
      7 https://docs.djangoproject.com/en/1.11/topics/settings/
      8 
      9 For the full list of settings and their values, see
     10 https://docs.djangoproject.com/en/1.11/ref/settings/
     11 """
     12 
     13 import os
     14 
     15 # Build paths inside the project like this: os.path.join(BASE_DIR, ...)
     16 BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
     17 
     18 
     19 # Quick-start development settings - unsuitable for production
     20 # See https://docs.djangoproject.com/en/1.11/howto/deployment/checklist/
     21 
     22 # SECURITY WARNING: keep the secret key used in production secret!
     23 SECRET_KEY = '9l6_6036bj+*ov$q)yg#p1ny6b8rk(j4z##8+6c)02l2cy@%i3'
     24 
     25 # SECURITY WARNING: don't run with debug turned on in production!
     26 DEBUG = True
     27 
     28 ALLOWED_HOSTS = []
     29 
     30 
     31 # Application definition
     32 
     33 INSTALLED_APPS = [
     34     'django.contrib.admin',
     35     'django.contrib.auth',
     36     'django.contrib.contenttypes',
     37     'django.contrib.sessions',
     38     'django.contrib.messages',
     39     'django.contrib.staticfiles',
     40     'app01.apps.App01Config',
     41 ]
     42 
     43 MIDDLEWARE = [
     44     'django.middleware.security.SecurityMiddleware',
     45     'django.contrib.sessions.middleware.SessionMiddleware',
     46     'django.middleware.common.CommonMiddleware',
     47     'django.middleware.csrf.CsrfViewMiddleware',
     48     'django.contrib.auth.middleware.AuthenticationMiddleware',
     49     'django.contrib.messages.middleware.MessageMiddleware',
     50     'django.middleware.clickjacking.XFrameOptionsMiddleware',
     51 ]
     52 
     53 ROOT_URLCONF = 'orm_pro.urls'
     54 
     55 TEMPLATES = [
     56     {
     57         'BACKEND': 'django.template.backends.django.DjangoTemplates',
     58         'DIRS': [os.path.join(BASE_DIR, 'templates')]
     59         ,
     60         'APP_DIRS': True,
     61         'OPTIONS': {
     62             'context_processors': [
     63                 'django.template.context_processors.debug',
     64                 'django.template.context_processors.request',
     65                 'django.contrib.auth.context_processors.auth',
     66                 'django.contrib.messages.context_processors.messages',
     67             ],
     68         },
     69     },
     70 ]
     71 
     72 WSGI_APPLICATION = 'orm_pro.wsgi.application'
     73 
     74 
     75 # Database
     76 # https://docs.djangoproject.com/en/1.11/ref/settings/#databases
     77 
     78 DATABASES = {
     79     'default': {
     80         'ENGINE': 'django.db.backends.mysql',
     81         'HOST':'127.0.0.1',
     82         'PROT':3306,
     83         'NAME':'orm01',
     84         'USER':'root',
     85         'PASSWORD':'123456',
     86     }
     87 }
     88 
     89 
     90 # Password validation
     91 # https://docs.djangoproject.com/en/1.11/ref/settings/#auth-password-validators
     92 
     93 AUTH_PASSWORD_VALIDATORS = [
     94     {
     95         'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator',
     96     },
     97     {
     98         'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator',
     99     },
    100     {
    101         'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator',
    102     },
    103     {
    104         'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator',
    105     },
    106 ]
    107 
    108 
    109 # Internationalization
    110 # https://docs.djangoproject.com/en/1.11/topics/i18n/
    111 
    112 LANGUAGE_CODE = 'en-us'
    113 
    114 TIME_ZONE = 'UTC'
    115 
    116 USE_I18N = True
    117 
    118 USE_L10N = True
    119 
    120 USE_TZ = True
    121 
    122 
    123 # Static files (CSS, JavaScript, Images)
    124 # https://docs.djangoproject.com/en/1.11/howto/static-files/
    125 
    126 STATIC_URL = '/static/'
    127 
    128 
    129 
    130 
    131 
    132 
    133 
    134 
    135 
    136 
    137 
    138 # 如果想打印orm转换过程中的sql,需要在settings中进行如下配置
    139 # LOGGING = {
    140 #     'version': 1,
    141 #     'disable_existing_loggers': False,
    142 #     'handlers': {
    143 #         'console':{
    144 #             'level':'DEBUG',
    145 #             'class':'logging.StreamHandler',
    146 #         },
    147 #     },
    148 #     'loggers': {
    149 #         'django.db.backends': {
    150 #             'handlers': ['console'],
    151 #             'propagate': True,
    152 #             'level':'DEBUG',
    153 #         },
    154 #     }
    155 # }
    setttings.py

    修改后端数据 切换页面   时,可以通过绑定事件,然后 location.href ,

    但是,麻烦,可以通过 a标签,它可以帮我们自动 发请求, 

    django批量操作 models中的表到 admin 中: 

    1 from django.contrib import admin
    2 
    3 # Register your models here.
    4 from app01 import models
    5 
    6 for table in models.__all__: # table 就是个字符串 
    7     if hasattr(models,table):
    8         admin.site.register(getattr(models,table))
    View Code

    django 中 使用外面的脚本 批量导入到数据库 中数据:(外部文件  操作django 的models  )

     1 # 外部 文件使用 djjango 的models, 需要配置 django 环境  (模仿 manage.py )
     2 import os
     3 if __name__ == '__main__':
     4     #===============配置=================
     5     os.environ.setdefault("DJANGO_SETTINGS_MODULE", "orm_pro.settings")
     6     import django
     7     django.setup()
     8     #================================
     9 
    10     from app01 import models
    11     obj_lists = []
    12     for i in range(50):
    13         obj = models.Books(
    14             name='葵花宝典第%s式'%i,
    15             price = 20+i,
    16             date ='1980-12-11',
    17             press_name= '人民日报出版社'
    18         )
    19         obj_lists.append(obj)
    20 
    21     models.Books.objects.bulk_create(obj_lists)
    脚本批量导入数据库数据.py

    url 别名  和 反向解析: 

    views.py 中要导入  reverse  

    url 路由 的时候 要用name 关键字 起个别名,  以后可以一直用这个别名,

    起了别名之后,以后,修改 前面的请求路径 也 不用修改面的,因为用了别名, 

    html 中 也可以使用 url 的别名, 语法: { %   url ' 别名'     %}  ,常用在  a标签 中的 href 属性中,  

    使用别名 的好处是 以防后面升级  路径时,不用到处更改 路径,  

    其中 redirect()中,可以直接写 别名,不用 reverse() 也可以,但,只限于 redirect()  ,  

    善用别名,

    善用路径,将后端数据放在路径中,删除数据 ,编辑数据的时候 ,可以通过 a 标签 达到 自动访问数据库的目的,例如 /edit/17  意思是编辑 id 为17 的图书 ,

    后端 数据 不要随便从 前端中获取,有可能是错的, 

    ORM --- 多表 操作  : 

    创建 django 的admin 用户,  

    python manager.py createsuperuser 

    多表操作之 增 删 改:

     1 from django.db import models
     2 
     3 # Create your models here.
     4 # 作者表
     5 class Author(models.Model):
     6     name = models.CharField(max_length=16)
     7     age = models.IntegerField()
     8     # authorDetail = models.OneToOneField(to='AuthorDetail',to_field='id',on_delete=models.CASCADE) # 不级联 model.SET_NULL  这时,如果删了的话,外键 就变为NULL了
     9     authorDetail_id = models.OneToOneField(to='AuthorDetail') # 默认 to_field 是id ,  django1.x 版本默认是 级联
    10     def __str__(self):
    11         return self.name
    12 
    13 
    14 
    15 # 作者详情表  # 作者表 和 作者详情表 是一对一的 关系
    16 class AuthorDetail(models.Model):
    17     birthday = models.DateField()
    18     tele = models.CharField(max_length=32)
    19     addr = models.CharField(max_length=64)
    20 
    21     def __str__(self):
    22         return self.addr
    23 
    24 
    25 
    26 # 出版社 表
    27 class Press(models.Model):
    28     name = models.CharField(max_length=32)
    29     city = models.CharField(max_length=32)
    30     email = models.EmailField() #实际也是 CharField,不过它可以帮我们 校验  是否是邮箱
    31 
    32     def __str__(self):
    33         return self.name
    34 
    35 
    36 
    37 #书籍表  和 作者是多对多的关系
    38 #书籍表 和 出版社 这里认为是一对多关系 (一个出版社 出版多本书 )
    39 class Book(models.Model):
    40     title = models.CharField(max_length=32)
    41     publishDate = models.DateField()
    42     price = models.FloatField()
    43     # price = models.DecimalField(max_digits=5,decimal_places=2) # 5位整数,2位小数
    44 
    45     press_id = models.ForeignKey(to='Press',on_delete=models.CASCADE) # 关联到 出版社 表 ,
    46 
    47     author = models.ManyToManyField(to='Author') #不是真实的字段,可以通过它操作第三张表 ,它 只是自动帮我们创建第三张表(  下面的  )
    48 
    49     def __str__(self):
    50         return self.title
    51 
    52 # class BookToAuthor(models.Model):   # 多对多的关系 用第三张  表
    53 #     book_id = models.ForeignKey(to='Book')
    54 #     author_id = models.ForeignKey(to='Author')
    models.py
     1 """orm_pro URL Configuration
     2 
     3 The `urlpatterns` list routes URLs to views. For more information please see:
     4     https://docs.djangoproject.com/en/1.11/topics/http/urls/
     5 Examples:
     6 Function views
     7     1. Add an import:  from my_app import views
     8     2. Add a URL to urlpatterns:  url(r'^$', views.home, name='home')
     9 Class-based views
    10     1. Add an import:  from other_app.views import Home
    11     2. Add a URL to urlpatterns:  url(r'^$', Home.as_view(), name='home')
    12 Including another URLconf
    13     1. Import the include() function: from django.conf.urls import url, include
    14     2. Add a URL to urlpatterns:  url(r'^blog/', include('blog.urls'))
    15 """
    16 from django.conf.urls import url
    17 from django.contrib import admin
    18 
    19 from app01 import views
    20 urlpatterns = [
    21     url(r'^admin/', admin.site.urls),
    22 
    23 
    24     url(r'^query/',views.query)
    25 
    26 ]
    urls.py
      1 from django.shortcuts import render,redirect,HttpResponse
      2 
      3 # Create your views here.
      4 from app01 import models # 利用orm 操作数据库
      5 from django.urls import reverse  # 可以反向解析 url 的别名
      6 
      7 def query(request):
      8 #一对一 操作多表 操作 author 表 和 authordetail表
      9     # 增  (一种是 对象 一种是属性 )
     10     '''
     11     author_detail_obj =  models.AuthorDetail.objects.create(
     12         birthday='1998-10-10',
     13         tele='188888888889',
     14         addr='黑龙江哈尔滨'
     15     )
     16     # 添加方式1  用属性 =  类对象的方式
     17     models.Author.objects.create(
     18         name='m万涛',
     19         age = 40,
     20         authorDetail_id=author_detail_obj # 这是类的属性
     21     )
     22     '''
     23     '''
     24     # 常用 
     25     # 添加方式2  用 表字段 =  查询结果 方式
     26     obj = models.AuthorDetail.objects.filter(addr='山西临汾').first()
     27     # print(obj.id)
     28 
     29     models.Author.objects.create(
     30         name='m狗蛋',
     31         age=24,
     32         authorDetail_id_id = obj.id  # 这是 数据库表中的 字段
     33     )
     34     '''
     35     #
     36     '''
     37     models.AuthorDetail.objects.get(id=1).delete()  #删它 会删 author ,然后会删 author_book 表 -->  牵一发而动全身
     38     '''
     39     #
     40     # models.Author.objects.get() # 不能用get 它得到的对象是 author 没有update()
     41     '''
     42     models.Author.objects.filter(id=2).update(
     43         name='德刚2',
     44         age=38,
     45         authorDetail_id_id = 6,
     46         # authorDetail_id = models.AuthorDetail.objects.get(id=6)
     47     )
     48     '''
     49 
     50     #
     51 
     52 # 一对多 操作多表  press 和 book  是一对多的关系  一本书 只能 由一个出版社
     53     #
     54     '''
     55     models.Book.objects.create(
     56         title = '李刚的辛福生活',
     57         publishDate='2009-10-10',
     58         price= 121,
     59         # press_id= models.Press.objects.create(name='幸福出版社',city='北京',email='1001@xx.com'),
     60         # press_id= models.Press.objects.get(id=1),
     61         
     62         # 常用 
     63         # press_id_id= models.Press.objects.get(id=1).id,
     64         press_id_id = 1  # 外键的时候, 这四种方式都可以   
     65     )
     66     '''
     67 
     68 
     69     # 删  和一对一的删除一样,
     70     # models.Press.objects.get(id=1).delete()
     71 
     72     #
     73     '''
     74     models.Book.objects.filter(id=8).update(
     75         title='钢铁之翼2',
     76         # press_id_id =2,
     77         press_id = models.Press.objects.get(id=2)
     78     )
     79     '''
     80 
     81     #
     82 
     83 # 多对多 操作多表  author  和 book 表
     84     #
     85     '''
     86     # 常用
     87     book_obj = models.Book.objects.get(id=1)
     88     # book_obj.author  # 使用 Book 中的author 属性来添加多对于的记录
     89     book_obj.author.add(*[1,2]) # book_id 1  的author 有两个 1 和 2
     90     # book_obj.author.add(*[1, 2,3])  # book_id 1  的author 有三个 1,2,3
     91     '''
     92 
     93     '''
     94     # 先找到 两个作者
     95     author1 = models.Author.objects.get(id=1)
     96     author2 = models.Author.objects.get(id=2)
     97     # 找到 书
     98     book_obj = models.Book.objects.get(id=3)
     99     book_obj.author.add(*[author1,author2])
    100     '''
    101 
    102     # 删 就是删除第三张 表
    103     '''
    104     # 首先要找到 这个表 ,通过 Book 中的 author 属性
    105     book_obj = models.Book.objects.get(id=9)
    106     # book_obj.author.remove(3) # remove 写的是对应的 author id
    107     book_obj.author.remove(*[3,5]) #删的是 9 对应的 3,5
    108 
    109     # book_obj.author.clear()  # 删的是 book 9 对应的所有 author
    110     # book_obj.author.set('4') # 将id book 9 对应的author id修改为 4 设置为1个
    111     # book_obj.author.set(['2','3']) # 将id book 9 对应的author id修改为 4和 6  设置为多个
    112     '''
    113     #
    114     '''
    115     多对多的 更改 就是 上面 删除中的 set   
    116     '''
    117 
    118     #
    119 
    120     return  HttpResponse('ok ')
    121     pass
    views.py

    级联的时候,orm   没有   级联更新,有级联删除,  

    多表操作之 查:

    多表查询,无论是 基于 对象 还是基于双下划线,它们都有  正向查询 和 反向查询 ,  

    就看外键那个属性写在哪,从  有 外键的表 查 叫:正向 , 反之,反向查询,   

    1,基于对象 的跨表 查询 (类似于    子查询  )

    2,基于双下划线的 跨表查询 (类似于连表   join 连接  )

    related_name关键字: 

    related_name = ‘xx’ :当创建外键 的时候 。它的作用是 当反向查询的时候 不用表名了,用 xx就行了。  

    聚合 函数使用    : 

    from django.db.models import Avg,Max,Min,Sum,Count

    补充:‘12’.isdigit( ) 不好,它全识别,使用  '12'.isdecimal()

    分组 查询  : 

    group by  分组 就是为了 统计信息,

    以及 分组后的   having 

    F查询   和  Q查询 : 

    orm (mysql)的坑(orm 不能解决):

    分组导致的,  分组之后取 其他字段 会导致数据有问题,

    如果分组,select 只能 select groupby 后的字段  和  统计的结果,其他字段都是无意义的,  

    只有如下可以:

    如果是实在想要其他字段,orm 解决不了 了,  

    原生sql 可以解决:

    先不分组, 先连接,连接之后,首先按照 price 降序排列,使得价格最大的在第一行,(这样就避免了后面 分组时候的错误),

    连接之后:

    先按price 降序排序:如下:

    然后,如果 max() 取数据,其他数据也都是在第一行的,就不会有错了, 

    最终如下:

    1 select title,price from 
    2     (
    3     select app01_author.id,app01_book.title,app01_book.price from app01_author 
    4     INNER JOIN app01_book_author on app01_author.id=app01_book_author.author_id 
    5     INNER JOIN app01_book on app01_book.id=app01_book_author.book_id 
    6     ORDER BY app01_book.price desc
    7     ) as b  
    8     GROUP BY id
    View Code 

    注:sql_mode 非常重要,  

     1 """orm_pro URL Configuration
     2 
     3 The `urlpatterns` list routes URLs to views. For more information please see:
     4     https://docs.djangoproject.com/en/1.11/topics/http/urls/
     5 Examples:
     6 Function views
     7     1. Add an import:  from my_app import views
     8     2. Add a URL to urlpatterns:  url(r'^$', views.home, name='home')
     9 Class-based views
    10     1. Add an import:  from other_app.views import Home
    11     2. Add a URL to urlpatterns:  url(r'^$', Home.as_view(), name='home')
    12 Including another URLconf
    13     1. Import the include() function: from django.conf.urls import url, include
    14     2. Add a URL to urlpatterns:  url(r'^blog/', include('blog.urls'))
    15 """
    16 from django.conf.urls import url
    17 from django.contrib import admin
    18 
    19 from app01 import views
    20 urlpatterns = [
    21     url(r'^admin/', admin.site.urls),
    22 
    23     url(r'^query/',views.query)
    24 
    25 ]
    urls.py
     1 from django.db import models
     2 
     3 # Create your models here.
     4 # 作者表
     5 class Author(models.Model):
     6     name = models.CharField(max_length=16)
     7     age = models.IntegerField()
     8     # authorDetail = models.OneToOneField(to='AuthorDetail',to_field='id',on_delete=models.CASCADE) # 不级联 model.SET_NULL  这时,如果删了的话,外键 就变为NULL了
     9     authorDetail_id = models.OneToOneField(to='AuthorDetail') # 默认 to_field 是id ,  django1.x 版本默认是 级联
    10     def __str__(self):
    11         return self.name
    12 
    13 
    14 
    15 # 作者详情表  # 作者表 和 作者详情表 是一对一的 关系
    16 class AuthorDetail(models.Model):
    17     birthday = models.DateField()
    18     tele = models.CharField(max_length=32)
    19     addr = models.CharField(max_length=64)
    20 
    21     def __str__(self):
    22         return self.addr
    23 
    24 
    25 
    26 # 出版社 表
    27 class Press(models.Model):
    28     name = models.CharField(max_length=32)
    29     city = models.CharField(max_length=32)
    30     email = models.EmailField() #实际也是 CharField,不过它可以帮我们 校验  是否是邮箱
    31 
    32     def __str__(self):
    33         return self.name
    34 
    35 
    36 
    37 #书籍表  和 作者是多对多的关系
    38 #书籍表 和 出版社 这里认为是一对多关系 (一个出版社 出版多本书 )
    39 class Book(models.Model):
    40     title = models.CharField(max_length=32)
    41     publishDate = models.DateField()
    42     dianzan_num = models.IntegerField(default=0) # 点赞
    43     comment_num = models.IntegerField(default=0) # 评论  后面又加上的(要么 default= ,要么set_null = True),
    44 
    45     price = models.FloatField()
    46     # price = models.DecimalField(max_digits=5,decimal_places=2) # 5位整数,2位小数
    47 
    48                                                                 # related_name = 'xx' 的意思是 反向查询的时候,不用表名了,用xx即可,
    49     # press_id = models.ForeignKey(to='Press',on_delete=models.CASCADE,related_name='xx') # 关联到 出版社 表 ,
    50     press_id = models.ForeignKey(to='Press',on_delete=models.CASCADE) # 关联到 出版社 表 ,
    51 
    52     author = models.ManyToManyField(to='Author') #不是真实的字段,可以通过它操作第三张表 ,它 只是自动帮我们创建第三张表(  下面的  )
    53 
    54     def __str__(self):
    55         return self.title
    56 
    57 # class BookToAuthor(models.Model):   # 多对多的关系 用第三张  表
    58 #     book_id = models.ForeignKey(to='Book')
    59 #     author_id = models.ForeignKey(to='Author')
    models.py
      1 from django.shortcuts import render,redirect,HttpResponse
      2 
      3 # Create your views here.
      4 from app01 import models # 利用orm 操作数据库
      5 from django.urls import reverse  # 可以反向解析 url 的别名
      6 
      7 def query(request):
      8 #1 基于对象的 多表查询  (类似于 子查询)
      9 #一对一 操作多表 操作 author 表 和 authordetail表
     10     #
     11     # 正向 查询
     12     '''
     13     author_obj = models.Author.objects.filter(name='超哥').first()
     14     print(author_obj.authorDetail_id.birthday)
     15     print(author_obj.authorDetail_id.tele)
     16     print(author_obj.authorDetail_id.addr)
     17     '''
     18     # 反向 查询  通过authorDetail 中 数据 查询 author 的信息
     19     '''
     20     detail_obj = models.AuthorDetail.objects.get(addr='江西南昌')
     21     # 具体是 通过小写的 表名
     22     print(detail_obj.author.name)
     23     print(detail_obj.author.age)
     24     print(detail_obj.author.authorDetail_id)
     25     '''
     26 
     27 # 一对多 操作多表  press 和 book  是一对多的关系  一本书 只能 由一个出版社
     28     #
     29     # 正向查询
     30     '''
     31     book_obj = models.Book.objects.get(id=7)
     32     print(book_obj.press_id.name)
     33     print(book_obj.press_id.city)
     34     print(book_obj.press_id.email)
     35     '''
     36     # 反向查询
     37     '''
     38     press_obj = models.Press.objects.get(name='幸福出版社')
     39     # 具体是用  表名_set
     40     # print(press_obj.book_set.first().title)
     41     # print(press_obj.book_set.first().publishDate)
     42     # print(press_obj.book_set.first().price)
     43     # print(press_obj.book_set.first().press_id)
     44     for book in press_obj.book_set.all():
     45         print(book.title)
     46         print(book.publishDate)
     47         print(book.price)
     48         print(book.press_id )
     49     '''
     50 
     51 # 多对多 操作多表  author  和 book 表
     52     #
     53     # 正向查询 一本书 是 哪几个作者写的
     54     '''
     55     book_obj = models.Book.objects.get(id=9)
     56     # 通过 book 中的 author 属性
     57     print(book_obj.author.all()) #<QuerySet [<Author: 德刚2>, <Author: 超哥>]>
     58     '''
     59 
     60     # 反向查询 一个作者 写了  哪几本书
     61     '''
     62     author_obj = models.Author.objects.get(name='德刚2')
     63     print(author_obj.book_set.all())
     64     '''
     65 
     66 #2 基于 双下划綫 的 多表查询  (类似于 join 连接)
     67 #一对一 操作多表 操作 author 表 和 authordetail表
     68     # 查 m狗蛋的地址
     69     '''
     70     # 正向查询
     71     # authorDetail_id   __   addr 它是先将 author 和 authorDeatail 连接在一起,然后再查 addr
     72     set = models.Author.objects.filter(name='m狗蛋').values('authorDetail_id__addr','age')
     73     print(set)  # 查找 addr 时 连表
     74     # 通过使用小写的 表名
     75     # 反向查询
     76     set = models.AuthorDetail.objects.filter(author__name='m狗蛋').values('addr','author__age')
     77     print(set) # 查找 addr 前 连表
     78     '''
     79 
     80     # 查 地址为 江西南昌 作者的名字
     81     '''
     82     # 正向查询
     83     set = models.Author.objects.filter(authorDetail_id__addr='江西南昌').values('name','authorDetail_id__birthday')
     84     print(set)
     85     # 反向查询
     86     set = models.AuthorDetail.objects.filter(addr='江西南昌').values('author__name','tele')
     87     print(set)
     88     '''
     89     # 查 电话 为 222222222 的作者的 名字
     90     '''
     91     # 正向查询
     92     set = models.Author.objects.filter(authorDetail_id__tele='222222222').values('name')
     93     print(set)
     94     # 反向查询
     95     set = models.AuthorDetail.objects.filter(tele='222222222').values('author__name')
     96     print(set)
     97     '''
     98 
     99 # 一对多 操作多表  press 和 book  是一对多的关系  一本书 只能 由一个出版社
    100     # 查 李刚的辛福生活 书  的出版社 是哪个?
    101     '''
    102     # 正向查询 有外键的 用外键 连接, 无外键的 用 表名小写连接,
    103     set = models.Book.objects.filter(title='李刚的辛福生活').values('press_id__name')
    104     print(set)
    105     # 反向查询
    106     set = models.Press.objects.filter(book__title='李刚的辛福生活').values('name')
    107     print(set)
    108     '''
    109     # 查 b哥出版社 都出版了 哪些书
    110     '''
    111     # 正向查询
    112     set = models.Book.objects.filter(press_id__name='b哥出版社').values('title')
    113     print(set)
    114     # 反向查询
    115     set = models.Press.objects.filter(name='b哥出版社').values('book__title')
    116     print(set)
    117     '''
    118 
    119 
    120 # 多对多 操作多表  author  和 book 表
    121     # 查 李刚的辛福生活  是谁写的
    122     '''
    123     # 正向查询
    124     set = models.Book.objects.filter(title='李刚的辛福生活').values('author__name')
    125     print(set)
    126     # 反向查询
    127     set = models.Author.objects.filter(book__title='李刚的辛福生活').values('name')
    128     print(set)
    129     '''
    130 
    131     # 查 m狗蛋 写了 哪些书
    132     '''
    133     # 正向查询
    134     set = models.Book.objects.filter(author__name='m狗蛋').values('title')
    135     print(set)
    136     # 反向查询
    137     set = models.Author.objects.filter(name='m狗蛋').values('book__title')
    138     print(set)
    139     '''
    140 #3 基于 双下划綫 的 进阶查询
    141     # 查 b哥出版社 , 出版的书 的名称 以及作者的名称 # press author -->  press --book --author
    142     # 三张表
    143     # 推荐第一种
    144     '''
    145     set = models.Press.objects.filter(name='b哥出版社').values('book__title','book__author__name')
    146     print(set)
    147 
    148     set = models.Book.objects.filter(press_id__name='b哥出版社').values('title','author__name')
    149     print(set)
    150 
    151     set = models.Author.objects.filter(book__press_id__name='b哥出版社').values('book__title','name')
    152     print(set)
    153     '''
    154 
    155 
    156     # 聚合 函数
    157     '''
    158     from django.db.models import Avg,Max,Min,Sum,Count
    159     # 算所有书  的平均价格
    160     # price = models.Book.objects.all().aggregate(Avg('price'))  # aggregate() 返回的是个字典
    161     res = models.Book.objects.all().aggregate(a = Avg('price'))  # a 会覆盖默认的键
    162     print(res)
    163 
    164     res = models.Book.objects.all().aggregate(Max('price'),Sum('price'),Count('price'))
    165     print(res)
    166     '''
    167 
    168     # 分组查询
    169     from django.db.models import Avg,Min,Max,Count,Sum
    170     # 一种写法
    171     '''
    172     # 查 每个出版社 出版书籍 的平均价格  如果用 sql的话: select avg(price) from app01_book group by press_id_id;
    173     #models.Book.objects.values('press_id_id') #所有出版社的id, 它作为 后面 annotate 时候的  分组条件,
    174     # models.Book.objects.values('press_id_id').annotate() # 分组
    175     ret = models.Book.objects.values('press_id_id').annotate(a = Avg('price'),b = Min('price'),c=Max('price'),d=Avg('press_id_id') )
    176     print(ret)
    177 
    178     # 多个 条件分组 
    179     # 以 press_id_id 和 id 为分组条件
    180     # models.Book.objects.values('press_id_id','id')
    181 
    182     ret = models.Book.objects.values('press_id_id','id').annotate(a = Avg('price'))
    183     print(ret)
    184     print(ret.filter(a__gt=25)) # 在查出 的结果中再次筛选, 它相当于 having ,group by 之后的 having  
    185     '''
    186 
    187 
    188     #另一种写法 以press 表为 分组依据,
    189     '''
    190     # 上面是把  values() 放在了 annotate ()前面 不好理解,
    191     # models.Press.objects  # Press 就是分组条件
    192                                           # a 一定要写
    193     # ret = models.Press.objects.annotate(a = Avg('xx__price')) # xx  是book 的别名, 做了一次连接,
    194     # print(ret) #<QuerySet [<Press: b哥出版社>, <Press: yy出版社>]>
    195     ret = models.Press.objects.annotate(a = Avg('xx__price')).values('a') # 同时会将 a 塞到 press 这个表中做为一个字段,
    196     print(ret)
    197     '''
    198 
    199 
    200     # F 函数   和 Q函数
    201 
    202     # F 查询:主要用于 单表中的 字段 的 比较,
    203     from django.db.models import F , Q
    204     # 例如查询 book 表中 评论数 大于   点赞赞 书
    205     '''
    206     ret = models.Book.objects.filter(comment_num__gt=F('dianzan_num'))
    207     print(ret)
    208     '''
    209 
    210     # F函数 还支持 四则运算
    211     '''
    212     ret = models.Book.objects.filter(comment_num__gt=F('dianzan_num') + 10)
    213     print(ret)
    214     '''
    215     # F 函数的 其他用途
    216     '''
    217     # 让 book 所有书 的价格 都加 20
    218     models.Book.objects.all().update(price =F('price') + 20)
    219     '''
    220 
    221 
    222     # Q函数  一个表中 的 字段 之间的或者关系,
    223     '''
    224     # 查 评论数  大于20 并且 点赞数 大于 20
    225     ret = models.Book.objects.filter(comment_num__gt=20,dianzan_num__gt=20)
    226     print(ret)
    227 
    228     # 查 评论数  大于20  或者  点赞数 大于 20
    229     ret = models.Book.objects.filter(Q(comment_num__gt=20)|Q(dianzan_num__gt=20))
    230     print(ret)
    231     # Q 也支持  & ~
    232     ret = models.Book.objects.filter(~(Q(comment_num__gt=20)&Q(dianzan_num__gt=20)))
    233     print(ret)
    234 
    235     # Q 也支持嵌套   把 多个条件 括起来,
    236     ret = models.Book.objects.filter(Q(~(Q(comment_num__gt=20) & Q(dianzan_num__gt=20)))&Q(price__gt=141))
    237     print(ret)
    238     '''
    239 
    240 
    241     # 习题 (orm mysql 的坑):
    242     # 查询 每个作者出版 书的最高价格
    243     ret = models.Author.objects.annotate(m = Max('book__price')).values('m')
    244     print(ret)
    245     # 它对应的原生 sql 是:
    246     ''' 
    247     # 连接    
    248     # select * from app01_author 
    249     inner join app01_book_author on app01_author.id = app01_book_author.author_id 
    250     inner join app01_book on app01_book.id = app01_book_author.book_id;  
    251 
    252     # select  app01_author.id, max(app01_book.price) from app01_author 
    253     inner join app01_book_author on app01_author.id = app01_book_author.author_id 
    254     inner join app01_book on app01_book.id = app01_book_author.book_id
    255     group by app01_author.id;
    256 
    257 
    258     '''
    259     # 上面还没有 坑,
    260     # 下面就是 orm 的坑: 分组导致的坑~
    261 
    262     #查 每个作者出版的所有书的最高价格  以及  最高价格的那本书的名称
    263     ret =  models.Author.objects.annotate( m = Max('book__price')).values('m','book__title')
    264     print(ret)
    265     # 如果写 肯定是上面这样写, 它是有坑的,
    266 
    267     '''
    268     | id | name    | age | authorDetail_id_id | id | book_id | author_id | id | title                 | publishDate | price | press_id_id | comment_num | dianzan_num |
    269     +----+---------+-----+--------------------+----+---------+-----------+----+-----------------------+-------------+-------+-------------+-------------+-------------+
    270     |  2 | 德刚2   |  38 |                  6 |  8 |       3 |         2 |  3 | 钢铁之翼              | 2020-03-06  |    40 |           2 |          10 |         100 |
    271     |  2 | 德刚2   |  38 |                  6 | 27 |       9 |         2 |  9 | 得当的内心独白        | 2008-10-01  |   220 |           5 |          10 |          40 |
    272     如果数据如上面, max(price),  price字段得到 的是 220 ,但是,其他字段 就没办法取了,只能按照第一行的数据。这 orm 是无法解决的。  
    273     
    274     mysql  中 可以设置 sql_mode = only_full_group_by ,此时就不能 select * 了,只能 select group by 后的字段 以及统计数据,其他字段无法拿到, 
    275     
    276     
    277     总结:  分组之后 拿统计数据才是 有意义的,其他字段 没有任何意义 ~       
    278     '''
    279 
    280     '''
    281     # 上述问题,orm 不能解决, 原生sql 可以解决:  
    282     #select title,price from 
    283     (
    284     select app01_author.id,app01_book.title,app01_book.price from app01_author 
    285     INNER JOIN app01_book_author on app01_author.id=app01_book_author.author_id 
    286     INNER JOIN app01_book on app01_book.id=app01_book_author.book_id 
    287     ORDER BY app01_book.price desc
    288     ) as b  
    289     GROUP BY id
    290     '''
    291 
    292 
    293 
    294 
    295     return  HttpResponse('ok ')
    views.py

    django 中时间相关: 

    auto_now 是更新的时候,自动更新时间,  auto_now_add 是创建的时候 加时间,更新时不更新时间,  

    而且差8小时, 配置: USE_TZ = False  

    问题: 

    auto_now_add 没多大问题,auto_now 更新数据的时会有问题, 

    我们如果用update() 去更新数据,auto_now 是不会帮我们更新时间的,【我们可以自己传入时间 datetime.datetime.now() 手动增加 】(常用)


    如果用 obj.name = 'tom3' obj.save() 更新数据时,auto_now 会帮更新时间

    时间转化:

    https://www.cnblogs.com/clschao/articles/10757374.html

    ORM --- 锁 和 事务: 

    https://www.cnblogs.com/clschao/articles/10463267.html

    行级锁:

    select_for_update,   

    共享锁, 排他锁,

    表锁: 

    事务四大特性:

    原子性 , 一致性,持久性,隔离性=  。

    Django --- Ajax : 

    https://www.cnblogs.com/clschao/articles/10468335.html  

    ajax 是js的技术, 

    这里不再使用 form 和 a  标签来 发送请求了,它是使用 ajax 发送请求,请求结果也是会返回给 ajax 的请求,  

    前后端 分离的时候用的就是 ajax , js 中的 ajax 就是类似于 python 中的 request , 

    登陆认证 只是 ajax 的一个应用,  

    补:content-type  :

    它是前后端 交互的时候的消息格式, 

    django 默认解析的 content-type 是   urlencoded 

    如果你发送请求 使用 content-type :application /json 那么,django 就不会帮你解析参数了,需要你自己手动从 请求头中自己  解析, 

    在做接口的时候,可能会遇到此类问题, 

    django 还认:  multipart/form-data  上传文件(见下面)   用的,django 只认这两种 content-type , 

    上传文件:  

    两种: 1,form 表单 上传文件, 2,ajax 上传文件, 

    如何将Python 中的 时间日期类型 进行 序列化:

    python中的datetime等时间日期类型是不能进行json序列化的,因为json没有对应的格式,此时需要我们自己手动处理:

     1 import json
     2 from datetime import datetime
     3 from datetime import date
     4 
     5 #对含有日期格式数据的json数据进行转换
     6 class JsonCustomEncoder(json.JSONEncoder):
     7     def default(self, field):
     8         if isinstance(field,datetime):
     9             return field.strftime('%Y-%m-%d %H:%M:%S')
    10         elif isinstance(field,date):
    11             return field.strftime('%Y-%m-%d')
    12         else:
    13             return json.JSONEncoder.default(self,field)
    14 
    15 
    16 d1 = datetime.now()
    17 
    18 dd = json.dumps(d1,cls=JsonCustomEncoder) # 使用的时候,要用cls 关键字 来指定自定义的类,  
    19 print(dd)
     1 {% load static %}
     2 <!DOCTYPE html>
     3 <html lang="zh-CN">
     4 <head>
     5     <meta charset="utf-8">
     6     <meta http-equiv="X-UA-Compatible" content="IE=edge">
     7     <meta name="viewport" content="width=device-width, initial-scale=1">
     8     <title>hello world</title>
     9 
    10 </head>
    11 <body>
    12     <h1>上传文件 </h1>
    13 
    14     <form action="" method="post" enctype="multipart/form-data">
    15         {% csrf_token %}
    16         头像:<input type="file" name="head_pic">
    17         用户名:<input type="text" name="username">
    18         <input type="submit">
    19     </form>
    20 </body>
    21 </html>
    upload.html
     1 {% load static %}
     2 <!DOCTYPE html>
     3 <html lang="zh-CN">
     4 <head>
     5     <meta charset="utf-8">
     6     <meta http-equiv="X-UA-Compatible" content="IE=edge">
     7     <meta name="viewport" content="width=device-width, initial-scale=1">
     8     <title>hello world</title>
     9 </head>
    10 <body>
    11     <h1>上传文件2</h1>
    12     文件:<input type="file" id="file">  {#    ajax  上传 不需要 name 属性也可 ajax 需要我们自己写 key value  #}
    13 
    14     用户名:<input type="text" id="uname">
    15     <button id="btn">上传</button>
    16     <script src="{% static 'jquery.js' %}"></script>
    17     <script>
    18         $('#btn').click(function () {
    19             // console.log($('#file')[0].files[0]);
    20             var form_data = new FormData();
    21             form_data.append('uname',$('#uname').val());
    22             form_data.append('file_obj',$('#file')[0].files[0]);
    23             form_data.append('csrfmiddlewaretoken','{{ csrf_token }}');
    24 
    25             $.ajax({
    26                 url:'{% url 'upload2' %}',
    27                 type:'post',
    28                 {#data:{#}
    29                 {#    csrfmiddlewaretoken:'{{ csrf_token }}',#}
    30                 {#    uname:$('#uname').val(),#}
    31                 {#    //file_obj: $('#file')[0].files[0]  // 直接上传 不可以,ajax 上传数据 需借助formdata#}
    32 {##}
    33 {#                }#}
    34                 data:form_data,
    35                 processData:false, // 不处理数据
    36                 contentType:false, // 不设置内容类型   在ajax 上传文件时候 必须写
    37 
    38 
    39                 success:function (res) {
    40                     console.log(res);
    41                 }
    42 
    43             })
    44 
    45         });
    46 
    47 
    48 
    49     </script>
    50 </body>
    51 </html>
    upload2.html
      1 from django.shortcuts import render,redirect,HttpResponse
      2 
      3 
      4 # Create your views here.
      5 from app01 import models # 利用orm 操作数据库
      6 from django.urls import reverse  # 可以反向解析 url 的别名
      7 from django.http import JsonResponse  # 做的工作是 添加 content-type: application/json
      8 
      9 def query(request):
     10     return  HttpResponse('ok ')
     11 
     12 from django.views import View
     13 
     14 def index(request):
     15     return render(request,'index.html')
     16 
     17 def home(request):
     18     if request.method == 'GET':
     19         all_books = models.Book.objects.all()
     20         print(all_books)
     21 
     22         all_press = models.Press.objects.all()
     23 
     24         return render(request,'home.html',{'all_books':all_books,'all_press':all_press})
     25     else:
     26         print(request.POST)
     27 
     28         return HttpResponse('ok')
     29 
     30 
     31 def data(request):
     32     ll = [11,1,1,33,44]
     33         # 在回复 非字典的时候,要加上 safe = False
     34     return JsonResponse(ll,safe = False)
     35 
     36 # 通过form 表单上传文件
     37 def upload(request):
     38     if request.method == 'GET':
     39         return render(request,'upload.html')
     40     else:
     41         print(request.POST) #<QueryDict: {'csrfmiddlewaretoken': ['Tu0Eo0hBDKlvmAS8ynxo8iEY2IY0smCiR9QQbDeFe9HGsRPmQNtMyNE4ZS2EKb9u'], 'head_pic': ['10.jpg'], 'username': ['zcb']}>
     42         print(request.FILES) # POST 中放的只是 文件名字,真实的数据 在 request.FILES  中,但是 form 表单中要加: enctype = 'multipart/form-data'
     43             # 配置好  enctype 中 之后: <MultiValueDict: {'head_pic': [<InMemoryUploadedFile: 9.jpg (image/jpeg)>]}>
     44         # 保存到 服务器
     45         file_obj = request.FILES.get('head_pic') # file_obj 可以当做是 文件句柄
     46         f_name = file_obj.name
     47 
     48         from orm_pro import settings
     49         import os
     50         path = os.path.join(settings.BASE_DIR,'static_files','user_img',f_name)
     51         with open(path,"wb") as f:
     52             # 方式1: 数据是多行的,
     53             for i in file_obj:
     54                 f.write(i)
     55 
     56             # 方式2 :如果数据就只有一行
     57             # for i in file_obj.chunks(): # 还是读数据,默认一次 读 64KB ( 只是django 中 )
     58             #     f.write(i)
     59 
     60 
     61         return HttpResponse('ok')
     62 
     63 # 通过 ajax 上传文件
     64 def upload2(request):
     65     if request.method == 'GET':
     66         print('hhhhhh')
     67         return render(request,'upload2.html')
     68         # return render(request,'upload2.html')
     69     else:
     70         print('#================================')
     71         print(request.POST)
     72         print(request.FILES)
     73         file_obj = request.FILES.get('file_obj')
     74 
     75         with open(file_obj.name, "wb") as f:
     76             # 方式1: 数据是多行的,
     77             for i in file_obj:
     78                 f.write(i)
     79             # 方式2 chunks()
     80 
     81 
     82         print('#================================')
     83 
     84         return HttpResponse('ok')
     85 
     86 
     87 
     88 import json
     89 class LoginView(View):
     90     def get(self,request):
     91         return render(request,'login.html')
     92 
     93     def post(self,request):
     94         # 此时是 ajax 请求过来的 不再是 form 了
     95         uname = request.POST.get('uname')
     96         pwd = request.POST.get('pwd')
     97         if uname == 'zcb' and pwd == '123':
     98             print("成功")
     99             # return render(request,'index.html') # ajango  成功之后 返回个首页
    100             ret = {'code':0,'msg':'ok','url':'/index/'}
    101             return HttpResponse(json.dumps(ret))
    102             # return HttpResponse(json.dumps(ret),content_type='application/json') # content_type这样之后,ajax收到数据就不用反序列化了
    103             # 上面一行 还要手动自己写 content_type ,有没有不用自己写的,有,   JsonResponse() # from django.http import JsonResponse
    104                 #直接 return JsonResponse(ret)
    105         else:
    106             # return  redirect('/login/') 此时 ajax 不认识 django 的 redirect 的,要想重定向要通过js 的location.href 。
    107 
    108             # 应该返回的是 redirect 的url
    109             ret = {'code':3,'msg':'用户名或密码错误','url':'/login/'}
    110             # 要返回的应该是 str
    111             return HttpResponse(json.dumps(ret))
    views.py
     1 """orm_pro URL Configuration
     2 
     3 The `urlpatterns` list routes URLs to views. For more information please see:
     4     https://docs.djangoproject.com/en/1.11/topics/http/urls/
     5 Examples:
     6 Function views
     7     1. Add an import:  from my_app import views
     8     2. Add a URL to urlpatterns:  url(r'^$', views.home, name='home')
     9 Class-based views
    10     1. Add an import:  from other_app.views import Home
    11     2. Add a URL to urlpatterns:  url(r'^$', Home.as_view(), name='home')
    12 Including another URLconf
    13     1. Import the include() function: from django.conf.urls import url, include
    14     2. Add a URL to urlpatterns:  url(r'^blog/', include('blog.urls'))
    15 """
    16 from django.conf.urls import url
    17 from django.contrib import admin
    18 
    19 from app01 import views
    20 urlpatterns = [
    21     url(r'^admin/', admin.site.urls),
    22     url(r'^query/',views.query),
    23     url(r'^index/',views.index),
    24     url(r'^home/', views.home,name='home'),
    25     url(r'^data/', views.data,name='data'),
    26     url(r'^upload/$',views.upload,name='upload'),
    27     url(r'^upload2/$',views.upload2,name='upload2'),
    28     url(r'^login/', views.LoginView.as_view(),name='login'),
    29 
    30 
    31 ]
    urls.py
     1 {% load static %}
     2 <!DOCTYPE html>
     3 <html lang="zh-CN">
     4 <head>
     5     <meta charset="utf-8">
     6     <meta http-equiv="X-UA-Compatible" content="IE=edge">
     7     <meta name="viewport" content="width=device-width, initial-scale=1">
     8     <title>hello world</title>
     9     
    10 </head>
    11 <body>
    12     <h1>你好,世界!</h1>
    13     <ul>
    14     </ul>
    15     <script src="{% static 'jquery.js' %}"></script>
    16     <script>
    17         $.ajax({
    18             url:'{% url 'data' %}',
    19             type:'get',
    20             success:function (res) {
    21                 console.log(res);
    22                 $.each(res,function (k,v) {
    23                     console.log(k,v);
    24                     /*
    25                     //1
    26                     var li = document.createElement('li');
    27                     $(li).text(v);
    28                     $('ul').append(li);
    29                     */
    30                     //2
    31                     var s = '<li>'+v.toString()+'</li>';
    32                     $('ul').append(s);
    33                 })
    34 
    35             }
    36         })
    37 
    38 
    39     </script>
    40 
    41 </body>
    42 </html>
    home.html

    上传文件:  https://files.cnblogs.com/files/zach0812/django_%E4%B8%8A%E4%BC%A0%E6%96%87%E4%BB%B6.zip

    django--- cookie 和 session(会话): 

    http  是不支持持续会话的,

    http的两个特性:

    1,无连接 (发一次  收一次 , 完事儿~)   

    2,无状态  (本次连接 结束,下次连接时 不认识对方,), cookie (给http 请求头中加了 cookie )来解决 这个问题,

     

    cookie 是服务端 发来存储在浏览器上的 一组键值对, 

    为什么会有 session  :

    把之前 想发给客户端的 放在 服务端,只给 客户端 发个key ,

    现在就是不能直接看到 真实cookie 的真实键值对了,而且存储在服务端, 用户下次访问 要拿着 key 过来访问服务端,  

    django 中设置session 不再通过 响应对象 来设置了,直接通过request 来设置, 

    而且django 设置 session 时,会保存到 数据库  django 的内置表  django_session 。  

    取 加密的cookie 时, 

    注: 经过网络传输 ,只有 str 一种类型,所以,直接  使用  cookie 时,True  是 str 类型, 如果使用了 session 的话,True 还是 bool 类型,   

    这个服务端的加密数据,是根据 用户 和浏览器 来生成的 记录, 

    django 做的事情是:一个浏览器 和一个用户 只给保留一条记录(覆盖), (但是,如果没有session_id(用户主动清除cookie) ,还是会产生新的记录的,没法判断是否是 原来的 浏览器  和  用户了  )

    cookie 和 session 里的参数 :  

    set_cookie() 的参数: 

    request.session 的一些方法:  

    views.py 中的 视图函数:

    补: django 项目的 配置文件

    from django.conf import global_settings  ,可以在 global_settings  配置 key  ,不叫 session_id ,

    但是,直接在用户配置文件中 配置即可, 

    django--- 中间件  (midware): 

    之前给视图函数加装饰器来判断是用户是否登录,把没有登录的用户请求跳转到登录页面。

    我们通过给几个特定视图函数加装饰器实现了这个需求。但是以后添加的视图函数可能也需要加上装饰器,这样是不是稍微有点繁琐。

    我们就可以用更适宜的方式来实现类似给所有请求都做相同操作的功能了,就是中间件(就是一个类),

    我们在一个固定位置 写个py 文件即可,

     把这个配置到 settings.py 即可, 这样所有的请求都会经过我们的这个 process_request()  ,响应走的时候(必须 return response )都会经过 process_response() ,

    中间件的一个用途:限制IP 频率, (客户端的 ip 在 request.META 中 ),规则: 例如,10s 之内 只能访问三次,  

    Django 请求的生命周期:

    Django -- form 验证 组件  :

    https://www.cnblogs.com/clschao/articles/10486468.html

    前后端 的认证 都是需要的, 

    form组件 主要做  数据校验,  

    views.py :  

    name  只能 6 到  16 位,  

    在使用的时候,可以将loginForm 对象 渲染到 HTML 中,

    如果使用 form_obj.as_p  会自动 加 label ,label 可以指定 input 的名字, 但是扩展性不好,一般不用 .as_p    

    django form 表单上传文件:

    参考: https://www.cnblogs.com/clschao/articles/10468335.html#part_2 

    models.py   中  ImageField(upload)

    def test(request):
        if request.method == 'GET':
            test_form = TestForm(request)
            return render(request,'zcb.html',{'test_form':test_form})
        else:
            img_obj = request.FILES.get('img')
            file_name = img_obj.name
    
            with open('static/xxnaicha/img/'+file_name,'wb') as f:
                for chunks in img_obj.chunks():
                    f.write(chunks)
    
            return HttpResponse('ok')
    View Code

    Django Rest_Framework 组件 : 

    具体详细项目见 百度网盘,

    drf 序列化: 

    当前端 向服务器请求数据,我们手工 序列化数据很麻烦,尤其当涉及外键关系,需要我们自己自行构建数据结构,

    Django自带的序列化组件,不好(外键关系无法处理),from django.core.serializers import serialize

    建议使用:  drf( Django Rest_Framework )

    APIView csrf 豁免,发送post 请求 比View方便,  

    1 # 构建一个 序列化器
    2 class BookSerialize(serializers.Serializer):
    3     id = serializers.IntegerField()
    4     title = serializers.CharField(max_length=32)
    5     CHOICES = ((1,'python'),(2,'linux'))
    6     # course = serializers.ChoiceField(choices=CHOICES) # 直接这样写  拿到的数据是 前面的 1,2  
    7     course = serializers.CharField(source='get_course_display') # source 可以执行 一些orm 操作,这时拿到的是 后面的Python 和 linux
    source 属性执行 orm 操作
     1 from rest_framework.views import APIView
     2 from rest_framework import serializers
     3 from rest_framework.response import Response
     4 
     5 class AuthorSerialize(serializers.Serializer):
     6     id = serializers.IntegerField()
     7     name = serializers.CharField(max_length=32)  # 想要什么字段写什么,写什么就序列化什么  
     8 
     9 class PublishSerialize(serializers.Serializer):
    10     id = serializers.IntegerField()
    11     name = serializers.CharField(max_length=32)
    12 
    13 class BookSerialize(serializers.Serializer):
    14     id = serializers.IntegerField()
    15     title = serializers.CharField(max_length=32)
    16 
    17     publish = PublishSerialize()  # 因为一本书只有一个出版社,
    18     author = AuthorSerialize(many=True) #因为一本书可能有多个作者 所以 many = True
    19 
    20 class Index(APIView):
    21     def get(self,request):
    22         book_queryset = Book.objects.all()
    23         ser_obj = BookSerialize(book_queryset,many=True)
    24         return Response(ser_obj.data)
    drf 序列化解决 外键关系

    注: 还要把 rest_framework 注册进 settings 里, 如下: 

    drf  反序列化: 

    当前端 提交过来一个数据的时候,我们就需要 反序列化了, 

    假设前端传过来的数据如下:

     

     1 from rest_framework.views import APIView
     2 from rest_framework import serializers
     3 from rest_framework.response import Response
     4 
     5 class AuthorSerialize(serializers.Serializer):
     6     id = serializers.IntegerField()
     7     name = serializers.CharField(max_length=32)  # 想要什么字段写什么,写什么就序列化什么
     8 
     9 class PublishSerialize(serializers.Serializer):
    10     id = serializers.IntegerField()
    11     name = serializers.CharField(max_length=32)
    12 
    13 class BookSerialize(serializers.Serializer):
    14     id = serializers.IntegerField(required=False) #required=False 表示  id不用校验
    15     title = serializers.CharField(max_length=32)
    16     CHOICES = ((1,'PYTHON'),(2,'LINUX'))
    17     course = serializers.CharField(source='get_course_display',write_only=True) # 序列化时候 用 ,这是返回字符
    18     post_course = serializers.ChoiceField(choices=CHOICES,read_only=True) # 反序列化时候 用 ,前端提交过来 数字
    19 
    20     publish = PublishSerialize(write_only=True)
    21     author = AuthorSerialize(many=True,write_only=True)
    22 
    23     post_publish_id = serializers.IntegerField (read_only=True)
    24     post_author_id = serializers.ListField(read_only=True)
    25 
    26     def create(self, validated_data):
    27         #  post 提交数据时,orm 操作保存数据
    28         book_obj = models.Book.create(
    29             title=validated_data['title'],
    30             publish_id = validated_data['post_publish_id'],
    31             course = validated_data['post_course']
    32         )
    33         # 处理多对多的关系
    34         book_obj.authors.add(*validated_data['post_author_id'])
    35         return book_obj  # 一定要 return
    36 
    37 
    38 
    39 class Index(APIView):
    40     def get(self,request):
    41         book_queryset = models.Book.objects.all()
    42         ser_obj = BookSerialize(book_queryset,many=True)
    43         return Response(ser_obj.data)
    44 
    45     def post(self,request):
    46         book_obj = request.data # 相当于 原来 request.POST  data中放着除了 GET外的信息  (APIView 封装了下原先的request 并得到了新的request)
    47 
    48         # 对前端传来的数据 做校验
    49         ser_obj = BookSerialize(data=book_obj)
    50         if ser_obj.is_valid():
    51             ser_obj.save()
    52             return Response(ser_obj.data)
    53         else:
    54             return Response(ser_obj.errors)
    加上 反序列化(前端向后端提交数据)

    所有的视图类,  

    drf    版本控制组件 认证组件  权限控制  频率控制   分页器  解析器 渲染器     :  

    项目见 百度网盘

    解析器: 

    django 中默认content-type 只支持两种 类型,一个是form-data 一个是url-encode 

    渲染器: 

    RESTful 规范:  

    REST 风格: 表述性状态转移,【这个风格只是个建议,】

    URI:统一资源标识符,

    URL:统一资源定位符, (url 是通过定位实现的URI )

    统一资源接口: 

      根据HTTP请求方式的不同对资源进行不同的操作(get 获取,post新增),
    例如:在前后端交互时,不能再addbook,editbook,delbook ,应该直接一个book ,然后根据不同的请求方式 来做不同的逻辑(get获取,post新增,delete删除)
      遵循HTTP请求方式的语义(get 就是获取,post就是新增(不能不增),)

    遵循 REST风格的就叫 RESTful 规范

    django ContentType组件:  

    使用ContentType 的好处:  

    使用ContentType 的步骤: 

    1,优惠券表中 需要foreignkey 到 ContentType
    2,object_id 是所关联到的表的 id
    3,GenericForeignKey 两者, 使用对象.就可以直接 找到所要的记录

    https://www.cnblogs.com/GGGG-XXXX/articles/9697458.html

    接口测试 Postman:  

    开发流程:  

    功能结构图
    原型图
    根据功能需求设计表结构( 没有表结构 ER图 ,是 不可以写代码的 )

    前后端分离项目 文档十分重要, 

    数据库设计软件PowerDesigner :

    xxx

    权限:

    通过url 来控制 用户的访问,

    权限表结构设计 (rbac): 

    rbac 模式 :role based access control :基于角色 的 权限控制,    

    动态菜单 展示     : 

    不同的用户 展示 不同的菜单栏,  

    ES6 常用语法 :

    笔记参看:https://github.com/able8/hello-es6#12promise

    变量的定义:

    var 会有  变量的提升,

    let 不会有 变量的提升,而且不能重复定义

     1         // var 变量提升,可以重复定义  
     2         var a = 'tom';
     3         var a = 'jane';
     4         console.log(a);
     5 
     6         // let 不会变量提升,也不能重复定义,更严格
     7         let b = 'tom' ;
     8         let b = 'ajen'; // 报错 duplicate declaration # 重复定义
     9         console.log(b);
    10         
    11         // const 固定值,不能修改,是常量  

    模板字符串:

    用`(反引号)标识,用${}将变量括起来

    1 let n = 'tom';
    2 let age = 18;
    3 let motto = `hello world,my name is ${n},my age is ${age}`;
    4 console.log(motto);

    箭头函数 (匿名函数):

    python 中的匿名函数为 : lambda   

    1 // res => res + 1  
    2 let f = res => res + 1  ; 
    3 let ret = f(1);
    4 console.log(ret);  
    基本箭头函数

    this:

    普通函数   的this 指的是 当前函数 最近的调用者, 

    箭头函数的this 与它所处的上下文中的this一致(常用于回调),

     1 function f() {
     2     console.log(this);
     3 }
     4 f(); //this 为 Window对象
     5 let obj = {
     6     func:f
     7 };
     8 obj.func(); //this 为 obj 这个对象
     9 
    10 let obj2 = {
    11     test:obj
    12 };
    13 obj2.test.func();// this仍然是 obj 这个对象 
    普通函数中,this为它最近的调用者
     1 function f() {
     2     setTimeout(function () {
     3         console.log('普通函数');
     4         console.log(this);// 为它的最近调用者 即 window 
     5         console.log('普通函数');
     6     });
     7     setTimeout(res=>{
     8         console.log('匿名函数');
     9         console.log(this); // 和 它所处的上下文 环境中this一致 ,即 f函数中的 this 一致  
    10         console.log('匿名函数');
    11     });
    12 }
    13 let obj = {
    14     func:f
    15 };
    16 obj.func();
    普通函数 和 箭头函数中this 的区别

    箭头函数的好处:

    如果回调函数是普通函数,想使用 外层函数的this, 必须要在外层先 let that = this; ,然后使用that , 

    而如果是箭头函数,则可以直接使用this ,

    数据的打散  和 聚合  :

    Python 函数实参位置  中用*  打散列表,** 打散字典,

    Python 函数形位置  中用*  聚合列表 ,**  聚合字典,  

    es 6 中也有类似操作: ...   

    三个点在实参位置时,起到聚合成数组  的作用,  

    1 function f(a,b,...args) {
    2     console.log(a);
    3     console.log(b);
    4     console.log(args);
    5 }
    6 f(1,2,3,4,5); // 3,4,5,被聚合成一个数组 
    三个点在形参位置 --聚合作用

    三个点在实参位置时,起到打散数组  的作用,  

    1 function f(a,b,c) {
    2     console.log(a);
    3     console.log(b);
    4     console.log(c);
    5 }
    6 f(...[1,2,3]); // 把[1,2,3] 打散成 1,2,3
    三个点在实参位置 --打散作用

    解构 赋值:

    es 6 中也有类似操作: 

    它是用{} 解析对象, 用 [ ] 解析数组,  

    View Code

    ES6的 面向对象  :

    在es5中,定义一个类是 用原型链 来定义,es6 中,我们可以通过class 来定义类了~

     1 /*类的基本用法*/
     2 class Demo{
     3     constructor(userName,age){
     4         this.nick = userName;
     5         this.age = age;
     6     }
     7     run(){
     8         console.log('run with ',this.nick);
     9         return 1;
    10     }
    11 }
    12 let d = new Demo('tom',18);
    13 console.log(d.nick,d.age);
    14 let ret = d.run();
    15 console.log('我是 方法run 的返回值: ',ret);
    16 
    17 /*继承*/
    18 class MyDemo extends Demo{
    19     constructor(userName,age) {
    20         super(userName,age);  // 子类中没有this ,需要先super下,
    21         this.nick = userName;
    22         this.age = age;
    23     }
    24 }
    25 let demo2 = new MyDemo('a',18);
    26 demo2.run();
    View Code

    ES6 中的 import 和 export  :

    与python 不同的是,js中要想import 导入,必须要先 export 出 变量,

    要想导入,必须先抛出 变量,  

    但是,浏览器还不支持它们,还不能识别,  

    ES6的 Promise  :

    使用js进行异步操作,会陷入回调地狱(callback hell ) ,代码可读性降低,  

     1 /*
     2 * Promise 实例化: 要传它一个函数
     3 * 为了后续使用,这个函数要有两个参数(不需要我们手动传入,js引擎传),第一个代表是成功要执行的函数,第二个是失败要执行的函数
     4 *
     5 * */
     6 
     7 let p = new Promise(function (a,b) {
     8     //这里写 异步代码
     9     $.ajax({
    10         url:'test.py',
    11         success:function (res) {
    12             console.log(res);
    13             a();
    14             // b();
    15         },
    16         error:function(res){
    17             console.log('fail');
    18         }
    19     })
    20 });
    21 // 此时默认上面的异步代码一定执行成功
    22 p.then(function f1() {
    23     console.log('上面Promise 形参中的第一个函数 a执行了');
    24 },function f2() {
    25     console.log('上面Promise 形参中的第二个函数 b执行了');
    26 });
    27 
    28 p.then(function f1() {
    29     console.log('上面Promise 形参中的第一个函数 a执行了');
    30 }).catch(function f2() {
    31     console.log('上面Promise 形参中的第二个函数 b执行了');
    32 })
    Promise 简单使用--构建Promise对象,以及 Promise对象.then() 和 Promise对象.then().catch()

    上面代码如果不用Promise对象的话,代码如下:

     1 function test() {
     2     $.ajax({
     3         url:'test.py',
     4         success:function (res) {
     5             console.log(res);
     6             function f1() {
     7                 console.log('上面Promise 形参中的第一个函数 a执行了');
     8             }
     9             f1();
    10         },
    11         error:function(res){
    12             console.log('fail');
    13             function f2() {
    14                 console.log('上面Promise 形参中的第二个函数 b执行了');
    15             }
    16             f2();
    17         }
    18     })
    19 }
    20 test();
    不用Promise 的话,可读性低,

    再如:

    如果是有两次异步请求:  

     1 let p = new Promise(function (a,b) {
     2     //这里写 异步代码
     3     $.ajax({
     4         url:'test.py',
     5         success:function (res) {
     6             console.log(res);
     7             a();
     8         },
     9         error:function(res){
    10             console.log('fail');
    11             b();
    12         }
    13     })
    14 });
    15 
    16 let p2 = new Promise(function (a,b) {
    17     $.ajax({
    18         url:'test2.py',
    19         success:function (res) {
    20             a();
    21         },
    22         error:function (res) {
    23             b();
    24         }
    25     })
    26 });
    27 
    28 p.then(function f1() {
    29     p2.then(function f3() {
    30         console.log('2次都成功了');
    31     }).catch(function f4() {
    32         console.log('第一次成功,第二次失败');
    33     })
    34 },function f2() {
    35     p2.then(function f3() {
    36         console.log('第一次失败,第二次成功');
    37     }).catch(function f4() {
    38         console.log('2次都失败了');
    39     })
    40 });
    使用Promise ,异步请求逻辑逻辑清晰

    如果不用Promise实现上述代码: 

     1 function test() {
     2     $.ajax({
     3         url:'test.py',
     4         success:function (res) {
     5             function f1() {
     6                 $.ajax({
     7                     url:'test.py',
     8                     success:function () {
     9                         console.log('2次都成功了');
    10                     },
    11                     error:function () {
    12                         console.log('第一次成功,第二次失败');
    13                     }
    14                 })
    15             }
    16             f1();
    17         },
    18         error:function(res){
    19             console.log('fail');
    20             function f2() {
    21                 $.ajax({
    22                     url:'test.py',
    23                     success:function () {
    24                         console.log('第一次失败,第二次成功');
    25                     },
    26                     error:function () {
    27                         console.log('2次都失败了');
    28                     }
    29                 })
    30             }
    31             f2();
    32         }
    33     })
    34 }
    35 test();
    可读性查,回调地狱

    批量操作Promise对象:

    除了上面一个一个Promise 对象的用,还有多个Promise对象一起使用的,  

    Promise.all() 和 Promise.race()  

     1 let p = new Promise(function (a,b) {
     2     //这里写 异步代码
     3     $.ajax({
     4         url:'test1.py',
     5         success:function (res) {
     6             a();
     7         },
     8         error:function(res){
     9             b();
    10         }
    11     })
    12 });
    13 
    14 let p2 = new Promise(function (a,b) {
    15     $.ajax({
    16         url:'test1.py',
    17         success:function (res) {
    18             a();
    19         },
    20         error:function (res) {
    21             b();
    22         }
    23     })
    24 });
    25 
    26 // 一个一个的使用 还是麻烦 垃圾
    27 // p.then(function f1() {
    28 //     p2.then(function f3() {
    29 //         console.log('2次都成功了');
    30 //     }).catch(function f4() {
    31 //         console.log('第一次成功,第二次失败');
    32 //     })
    33 // },function f2() {
    34 //     p2.then(function f3() {
    35 //         console.log('第一次失败,第二次成功');
    36 //     }).catch(function f4() {
    37 //         console.log('2次都失败了');
    38 //     })
    39 // });
    40 
    41 // 批量的用 all 是全部执行成功
    42 // race 是看谁执行的快
    43 Promise.all([p,p2]).then(function f() {
    44     console.log('两次都成功了');
    45 }).catch(function () {
    46     console.log('不是两个都成功,一个失败,或两个都失败了');
    47 });
    48 
    49 Promise.race([p,p2]).then(function f() {
    50     console.log('有一个已经执行完了');
    51 }).catch(function f() {
    52     console.log('全部失败');
    53 });
    批量操作Promise
     1 let p = new Promise(function (a,b) {
     2     //这里写 异步代码
     3     $.ajax({
     4         url:'test3.py',
     5         success:function (res) {
     6             a(res);
     7         },
     8         error:function(res){
     9             b(res);
    10         }
    11     })
    12 });
    13 
    14 let p2 = new Promise(function (a,b) {
    15     $.ajax({
    16         url:'test2.py',
    17         success:function (res) {
    18             a(res);
    19         },
    20         error:function (res) {
    21             b(res);
    22         }
    23     })
    24 });
    25 
    26 // 批量的用 all 是全部执行成功
    27 // race 是看谁执行的快,如果在比赛中发现有一个已经失败,失败
    28 Promise.all([p,p2]).then(function f(res) {
    29     // console.log(res);//  [data1 ,data2] 重要
    30     console.log('两次都成功了');
    31 }).catch(function (res) {
    32     // console.log(res);// 第一个失败的 数据
    33     console.log('不是两个都成功,一个失败,或两个都失败了');
    34 });
    35 
    36 Promise.race([p,p2]).then(function f(res) {
    37     console.log(res); // 第一个执行完的 数据  重要
    38     console.log('有一个已经执行完了');
    39 }).catch(function f(res) {
    40     console.log(res);// 第一个检测到的那个,失败的那个的数据
    41     console.log('检测有一个失败,或全部失败');
    42 });
    all() 和 race() 中的传参问题

    封装函数 用于生成Promise对象:

    我们发现 Promise对象之后url 不同,因此可以封装一个函数 专门用来生成Promise对象: 

     1 function get_promise(url){
     2     return new Promise(function (a,b) {
     3         $.ajax({
     4             url:url,
     5             success:function (res) {
     6                 a(res);
     7             },
     8             error:function (res) {
     9                 b(res);
    10             }
    11         })
    12     })
    13 }
    14 let p = get_promise('test.py');
    15 let p2 = get_promise('test2.py');
    16 
    17 Promise.all([p,p2]).then(function (res) {
    18     console.log('两次都成功了');
    19     console.log('第一个数据');
    20     console.log(res[0]);
    21     console.log('第二个数据');
    22     console.log(res[1]);
    23 })
    封装一个用于生成Promise对象的函数
     1 // function get_promise(url){
     2 //     return new Promise(function (a,b) {
     3 //         $.ajax({
     4 //             url:url,
     5 //             success:function (res) {
     6 //                 a(res);
     7 //             },
     8 //             error:function (res) {
     9 //                 b(res);
    10 //             }
    11 //         })
    12 //     })
    13 // }
    14 function get_promise(url){
    15     return new Promise((a,b)=>{
    16         $.ajax({
    17             url:url,
    18             success:res=>{
    19                 a(res);
    20             },
    21             error:res=>{
    22                 b(res);
    23             }
    24         })
    25     })
    26 }
    27 
    28 let p = get_promise('test.py');
    29 let p2 = get_promise('test2.py');
    30 
    31 Promise.all([p,p2]).then(function (res) {
    32     console.log('两次都成功了');
    33     console.log('第一个数据');
    34     console.log(res[0]);
    35     console.log('第二个数据');
    36     console.log(res[1]);
    37 })
    再用上箭头函数,更好一点,更简洁
     1 function get_promise(url){
     2     return new Promise((a,b)=>{
     3         /*
     4         $.ajax({
     5             url:url,
     6             success:res=>{
     7                 a(res);
     8             },
     9             error:res=>{
    10                 b(res);
    11             }
    12         })*/
    13         // 这里写异步代码 
    14     })
    15 }

    注:上面的a, b形参名字,一般我们用 resolve 和 reject 来表示   

    ES8 :

    ES8 的 async 和 await :

     1     function block(sec) {
     2         while(1){
     3             if(new Date().getSeconds() === sec){
     4                 break;
     5             }
     6         }
     7     }
     8     function getData(url){
     9         // block(15); //模拟 正在 从url 获取数据  ...
    10         return 'success';
    11     }
    12 
    13     async function test() {
    14         return (await getData('test.py'));
    15     }
    16     let p = test();
    17     p.then(function (res) {
    18         console.log(res);
    19     });
    20     console.log('hello world1');
    21 /*
    22 * function前面加上async关键字,表示该function需要执行异步代码。
    23 * async function函数体内可以使用await关键字,且await关键字只能出现在async function函数体内。
    24 * await关键字可以跟在任意变量或者表达式之前,await后面 的将会是个异步过程
    25 *
    26 * 1,如果没有 async 内没有使用 await ,那么,将会是同步过程
    27 * 2,如果 async 中使用了 await
    28 *      第一个await 时,此时阻塞两个地方一个是主程序,一个是第一个await 后的代码
    29 *      然后 第一个await 后代码执行完毕后,然后执行 主程序,最后再执行 第一个await后的代码
    30 * */

    vue 框架:

    前端回顾:

    vue 的思想: 数据来驱动视图,  它改变 了原先 获取dom 渲染dom 的思想

    后端有MVC(django 中的MTV 模式  ),M - M , V - T ,C - V

    前端呢,又基于MVC 改进成了 MVVM ,Model ,  View, VIewModel ,

    MVVM中的   VM  和 C  和 django 中的 v(视图层函数)功能一致:都是给view提供处理好的数据的,  

    vue 的 常用指令 :  

     1 <!DOCTYPE html>
     2 <html lang="zh-CN">
     3 <head>
     4     <meta charset="utf-8">
     5     <meta http-equiv="X-UA-Compatible" content="IE=edge">
     6     <meta name="viewport" content="width=device-width, initial-scale=1">
     7     <title>hello world</title>
     8 </head>
     9 <body>
    10     <div class="box">
    11         {{name}}
    12         {{motto}}
    13     </div>
    14     <script src="vue.js"></script>
    15     <script>
    16         const app = new Vue({
    17             el:'.box', // 1,指定 vue 的作用域
    18             data:{     // 2,放入数据
    19                 name:'tom',
    20                 motto:'Life is short , I learn Python!'
    21             }
    22         })
    23     </script>
    24 </body>
    25 </html>
    vue的简单使用

    v-text  和 v-html :  

     1 <!DOCTYPE html>
     2 <html lang="zh-CN">
     3 <head>
     4     <meta charset="utf-8">
     5     <meta http-equiv="X-UA-Compatible" content="IE=edge">
     6     <meta name="viewport" content="width=device-width, initial-scale=1">
     7     <title>hello world</title>
     8 </head>
     9 <body>
    10     <div class="box">
    11         {{name}}
    12         <div v-text="motto"></div>
    13         <div v-html="hobby"></div>
    14     </div>
    15     <script src="vue.js"></script>
    16     <script>
    17         const app = new Vue({
    18             el:'.box', // 1,指定 vue 的作用域
    19             data:{     // 2,放入数据
    20                 name:'tom',
    21                 motto:'Life is short , I learn Python!',
    22                 hobby:`<ul>
    23                             <li>学习</li>
    24                             <li>游戏</li>
    25                             <li>电影</li>
    26                         </ul>`
    27             }
    28         })
    29     </script>
    30 </body>
    31 </html>
    View Code

    v-if:  

     1 <!DOCTYPE html>
     2 <html lang="zh-CN">
     3 <head>
     4     <meta charset="utf-8">
     5     <meta http-equiv="X-UA-Compatible" content="IE=edge">
     6     <meta name="viewport" content="width=device-width, initial-scale=1">
     7     <title>hello world</title>
     8 </head>
     9 <body>
    10     <div class="box" >
    11         <div v-if="age > 18 ">你已经成年了</div>
    12         <div v-else-if="age < 18 ">你还未成年</div>
    13         <div v-else>你刚好18</div>
    14     </div>
    15     <script src="vue.js"></script>
    16     <script>
    17         const app = new Vue({
    18             el:'.box', // 1,指定 vue 的作用域
    19             data:{     // 2,放入数据
    20                 age:22
    21             },
    22             methods:{
    23 
    24             }
    25         })
    26     </script>
    27 </body>
    28 </html>
    View Code

    它底层是 通过控制 appendChild 来实现的,不会一次性将所有标签都放到页面,哪个条件成立,显示谁。

    v-show : 

    v-show 是通过style 中的display 来控制的,  

     1 <!DOCTYPE html>
     2 <html lang="zh-CN">
     3 <head>
     4     <meta charset="utf-8">
     5     <meta http-equiv="X-UA-Compatible" content="IE=edge">
     6     <meta name="viewport" content="width=device-width, initial-scale=1">
     7     <title>hello world</title>
     8 </head>
     9 <body>
    10     <div class="box" >
    11         <div v-show="isShow">Hello world</div>
    12     </div>
    13     <script src="vue.js"></script>
    14     <script>
    15         const app = new Vue({
    16             el:'.box', // 1,指定 vue 的作用域
    17             data:{     // 2,放入数据
    18                 isShow:true
    19             },
    20             methods:{
    21 
    22             }
    23         })
    24     </script>
    25 </body>
    26 </html>
    View Code

    v-for:  

     1 <!DOCTYPE html>
     2 <html lang="zh-CN">
     3 <head>
     4     <meta charset="utf-8">
     5     <meta http-equiv="X-UA-Compatible" content="IE=edge">
     6     <meta name="viewport" content="width=device-width, initial-scale=1">
     7     <title>hello world</title>
     8 </head>
     9 <body>
    10     <div class="box">
    11         <ul>
    12             <li v-for="(course,index) in course_lists" :key="index">{{course}}{{index}}</li>
    13         </ul>
    14     </div>
    15     <script src="vue.js"></script>
    16     <script>
    17         const app = new Vue({
    18             el:'.box', // 1,指定 vue 的作用域
    19             data:{     // 2,放入数据
    20                 course_lists:['python','django','flask']
    21             }
    22         })
    23     </script>
    24 </body>
    25 </html>
    View Code

    v-bind:   

    动态绑定属性

     1 <!DOCTYPE html>
     2 <html lang="zh-CN">
     3 <head>
     4     <meta charset="utf-8">
     5     <meta http-equiv="X-UA-Compatible" content="IE=edge">
     6     <meta name="viewport" content="width=device-width, initial-scale=1">
     7     <title>hello world</title>
     8 </head>
     9 <body>
    10     <div class="box">
    11         <img v-bind:src="url" alt="">
    12     </div>
    13     <script src="vue.js"></script>
    14     <script>
    15         const app = new Vue({
    16             el:'.box', // 1,指定 vue 的作用域
    17             data:{     // 2,放入数据
    18                 url:'https://www.baidu.com/img/baidu_jgylogo3.gif'
    19             }
    20         })
    21     </script>
    22 </body>
    23 </html>
    View Code

    简写:  冒号 :  

    v-on:

    v-on:click   

    简写:@click  

    绑定事件,   

     1 <!DOCTYPE html>
     2 <html lang="zh-CN">
     3 <head>
     4     <meta charset="utf-8">
     5     <meta http-equiv="X-UA-Compatible" content="IE=edge">
     6     <meta name="viewport" content="width=device-width, initial-scale=1">
     7     <title>hello world</title>
     8 </head>
     9 <body>
    10     <div class="box" >
    11         <button v-on:click="myClick('tom')">Come on</button>
    12     </div>
    13     <script src="vue.js"></script>
    14     <script>
    15         const app = new Vue({
    16             el:'.box', // 1,指定 vue 的作用域
    17             data:{     // 2,放入数据
    18             },
    19             methods:{
    20                 myClick:function(arg){
    21                     console.log('我是 ',arg);
    22                 }
    23             }
    24         })
    25     </script>
    26 </body>
    27 </html>
    View Code

    @mouseenter  

    @mouseleave  等等...  

    当绑定多个事件的时候,如下:

     1 <!DOCTYPE html>
     2 <html lang="zh-CN">
     3 <head>
     4     <meta charset="utf-8">
     5     <meta http-equiv="X-UA-Compatible" content="IE=edge">
     6     <meta name="viewport" content="width=device-width, initial-scale=1">
     7     <title>hello world</title>
     8 </head>
     9 <body>
    10     <div class="box" >
    11         <button v-on="{mouseenter:enter,mouseleave:leave}">Come on</button>
    12     </div>
    13     <script src="vue.js"></script>
    14     <script>
    15         const app = new Vue({
    16             el:'.box', // 1,指定 vue 的作用域
    17             data:{     // 2,放入数据
    18             },
    19             methods:{
    20                 enter:function () {
    21                     console.log('进入');
    22                 },
    23                 leave:function () {
    24                     console.log('离开');
    25                 }
    26 
    27             }
    28         })
    29     </script>
    30 </body>
    31 </html>
    View Code

    v-model: 

     1 <!DOCTYPE html>
     2 <html lang="zh-CN">
     3 <head>
     4     <meta charset="utf-8">
     5     <meta http-equiv="X-UA-Compatible" content="IE=edge">
     6     <meta name="viewport" content="width=device-width, initial-scale=1">
     7     <title>hello world</title>
     8 </head>
     9 <body>
    10     <div class="box" >
    11         <input type="text" v-model="username">
    12         {{username}}
    13 
    14         <textarea name="" id="" cols="30" rows="10" v-model="article"></textarea>
    15         {{article}}
    16 
    17         <select name="" id="" v-model="choices">
    18             <option value="0">aaa</option>
    19             <option value="1">bbb</option>
    20             <option value="2">ccc</option>
    21         </select>
    22         {{choices}}
    23         <select name="" id="" v-model="choices2" multiple>
    24             <option value="0">aaa</option>
    25             <option value="1">bbb</option>
    26             <option value="2">ccc</option>
    27         </select>
    28         {{choices2}}
    29     </div>
    30     <script src="vue.js"></script>
    31     <script>
    32         const app = new Vue({
    33             el:'.box', // 1,指定 vue 的作用域
    34             data:{     // 2,放入数据
    35                 username:'',
    36                 article:'',
    37                 choices:'',
    38                 choices2:[],
    39             },
    40             methods:{
    41 
    42             }
    43         })
    44     </script>
    45 </body>
    46 </html>
    实时渲染

    指令修饰符:  

    如果想失去光标的时候,再渲染,可以用 点 给指令加上小的功能,  

    这里使用 

    .lazy   

     1 <!DOCTYPE html>
     2 <html lang="zh-CN">
     3 <head>
     4     <meta charset="utf-8">
     5     <meta http-equiv="X-UA-Compatible" content="IE=edge">
     6     <meta name="viewport" content="width=device-width, initial-scale=1">
     7     <title>hello world</title>
     8 </head>
     9 <body>
    10     <div class="box" >
    11         <input type="text" v-model.lazy="username">
    12         {{username}}
    13     </div>
    14     <script src="vue.js"></script>
    15     <script>
    16         const app = new Vue({
    17             el:'.box', // 1,指定 vue 的作用域
    18             data:{     // 2,放入数据
    19                 username:'',
    20             },
    21             methods:{
    22 
    23             }
    24         })
    25     </script>
    26 </body>
    27 </html>
    View Code

    .number :转为number 类型,

     1 <!DOCTYPE html>
     2 <html lang="zh-CN">
     3 <head>
     4     <meta charset="utf-8">
     5     <meta http-equiv="X-UA-Compatible" content="IE=edge">
     6     <meta name="viewport" content="width=device-width, initial-scale=1">
     7     <title>hello world</title>
     8 </head>
     9 <body>
    10     <div class="box" >
    11 <!--        <input type="text" v-model="price">-->
    12 <!--        {{ typeof price}}-->
    13 
    14 <!--        但是数据库中希望是  number 类型-->
    15         <input type="text" v-model.lazy.number="price">
    16         {{ typeof price}}
    17         <pre>    i love you</pre>
    18     </div>
    19     <script src="vue.js"></script>
    20     <script>
    21         const app = new Vue({
    22             el:'.box', // 1,指定 vue 的作用域
    23             data:{     // 2,放入数据
    24                 price:''
    25             },
    26             methods:{
    27 
    28             }
    29         })
    30     </script>
    31 </body>
    32 </html>
    View Code

    补充:HTML中的 pre 标签 可以打印数据的原始状态, 多个空格也能展示出来, 

    .trim: 

     1 <!DOCTYPE html>
     2 <html lang="zh-CN">
     3 <head>
     4     <meta charset="utf-8">
     5     <meta http-equiv="X-UA-Compatible" content="IE=edge">
     6     <meta name="viewport" content="width=device-width, initial-scale=1">
     7     <title>hello world</title>
     8 </head>
     9 <body>
    10     <div class="box" >
    11         <input type="text" v-model.trim="motto">
    12     </div>
    13     <script src="vue.js"></script>
    14     <script>
    15         const app = new Vue({
    16             el:'.box', // 1,指定 vue 的作用域
    17             data:{     // 2,放入数据
    18                 motto:''
    19             },
    20             methods:{
    21             }
    22         })
    23     </script>
    24 </body>
    25 </html>
    此时,用户输入的内容如果 左右带有空格,都会被去掉

    自定义指令:  :  

     1 <!DOCTYPE html>
     2 <html lang="zh-CN">
     3 <head>
     4     <meta charset="utf-8">
     5     <meta http-equiv="X-UA-Compatible" content="IE=edge">
     6     <meta name="viewport" content="width=device-width, initial-scale=1">
     7     <title>hello world</title>
     8 </head>
     9 <body>
    10     <div class="box" >
    11         <div v-my="d">
    12             我是div 标签
    13         </div>
    14     </div>
    15     <script src="vue.js"></script>
    16     <script>
    17         Vue.directive('my',function (arg1,arg2) {
    18             console.log(arg1); // 指令操作的对象
    19             console.log(arg2); // 相关的数据对象
    20             if(arg2.value){
    21                 arg1.style.border = '1px solid red';
    22             }
    23         });
    24         const app = new Vue({
    25             el:'.box', // 1,指定 vue 的作用域
    26             data:{     // 2,放入数据
    27                 d:true
    28             },
    29             methods:{
    30             }
    31         })
    32     </script>
    33 </body>
    34 </html>
    View Code

    再加上 指令修饰符:

     1 <!DOCTYPE html>
     2 <html lang="zh-CN">
     3 <head>
     4     <meta charset="utf-8">
     5     <meta http-equiv="X-UA-Compatible" content="IE=edge">
     6     <meta name="viewport" content="width=device-width, initial-scale=1">
     7     <title>hello world</title>
     8 </head>
     9 <body>
    10     <div class="box" >
    11         <div v-my.flag1.flag2="d">
    12             我是div 标签
    13         </div>
    14     </div>
    15     <script src="vue.js"></script>
    16     <script>
    17         Vue.directive('my',function (arg1,arg2) {
    18             console.log(arg1); // 指令操作的对象
    19             console.log(arg2); // 相关的数据对象
    20             if(arg2.value){
    21                 arg1.style.border = '1px solid red';
    22                 if(arg2.modifiers.flag1 && arg2.modifiers.flag1){
    23                     arg1.style.backgroundColor = 'purple'; 
    24                 }
    25             }
    26         });
    27         const app = new Vue({
    28             el:'.box', // 1,指定 vue 的作用域
    29             data:{     // 2,放入数据
    30                 d:true
    31             },
    32             methods:{
    33             }
    34         })
    35     </script>
    36 </body>
    37 </html>
    View Code

    vue DOM 相关 :

     

    获取dom:

     1 <!DOCTYPE html>
     2 <html lang="zh-CN">
     3 <head>
     4     <meta charset="utf-8">
     5     <meta http-equiv="X-UA-Compatible" content="IE=edge">
     6     <meta name="viewport" content="width=device-width, initial-scale=1">
     7     <title>hello world</title>
     8 </head>
     9 <body>
    10     <div class="box" >
    11         <div ref="div1">div1</div>  <!-- 一定要是 ref  -->
    12         <div ref="div2">div2</div>
    13         <button @click="clickEvt">点我啊</button>
    14     </div>
    15     <script src="vue.js"></script>
    16     <script>
    17         const app = new Vue({
    18             el:'.box', // 1,指定 vue 的作用域
    19             data:{     // 2,放入数据
    20             },
    21             methods:{
    22                 clickEvt:function () {
    23                     // 这里的this 是 app
    24                     // this.$refs.div1.style.backgroundColor='red';
    25                     this.$refs.div2.style.backgroundColor='red';
    26                 }
    27             }
    28         })
    29     </script>
    30 </body>
    31 </html>
    通过this.$.refs 来获取dom

    计算属性:  

    它和 data 的区别是:它通常放一些动态的数据,   

     1 <!DOCTYPE html>
     2 <html lang="zh-CN">
     3 <head>
     4     <meta charset="utf-8">
     5     <meta http-equiv="X-UA-Compatible" content="IE=edge">
     6     <meta name="viewport" content="width=device-width, initial-scale=1">
     7     <title>hello world</title>
     8 </head>
     9 <body>
    10     <div class="box" >
    11         <table>
    12             <thead>
    13                 <tr>
    14                     <th>科目</th>
    15                     <th>成绩</th>
    16                 </tr>
    17             </thead>
    18             <tbody>
    19                 <tr>
    20                     <td>语文</td>
    21                     <td><input type="text" v-model.number="c"></td>
    22                 </tr>
    23                 <tr>
    24                     <td>数学</td>
    25                     <td><input type="text" v-model.number="m"></td>
    26                 </tr>
    27                 <tr>
    28                     <td>英语</td>
    29                     <td><input type="text" v-model.number="e"></td>
    30                 </tr>
    31                 <tr>
    32                     <td>总分</td>
    33                     <td>{{c+m+e}}</td>
    34                 </tr>
    35                 <tr>
    36                     <td>平均分</td>
    37                     <td>{{(c+m+e)/3}}</td>
    38                 </tr>
    39             </tbody>
    40         </table>
    41     </div>
    42 
    43     <script src="vue.js"></script>
    44     <script>
    45         const app = new Vue({
    46             el:'.box', // 1,指定 vue 的作用域
    47             data:{     // 2,放入数据
    48                 c:'',
    49                 m:'',
    50                 e:''
    51             },
    52             methods:{
    53             }
    54         })
    55     </script>
    56 </body>
    57 </html>
    计算 总分 和 平均分

    但是,有的时候,我们不希望在 模板中使用大量的逻辑,这时,就可以使用 计算属性, 

    数据的监听:  

     1 <!DOCTYPE html>
     2 <html lang="zh-CN">
     3 <head>
     4     <meta charset="utf-8">
     5     <meta http-equiv="X-UA-Compatible" content="IE=edge">
     6     <meta name="viewport" content="width=device-width, initial-scale=1">
     7     <title>hello world</title>
     8 </head>
     9 <body>
    10     <div class="box" >
    11         {{name}}
    12         <br>
    13         {{arr}}
    14         <br>
    15         {{obj}}
    16     </div>
    17 
    18     <script src="vue.js"></script>
    19     <script>
    20         const app = new Vue({
    21             el:'.box', // 1,指定 vue 的作用域
    22             data:{     // 2,放入数据
    23                 name:'tom',
    24                 arr:[1,2,3],
    25                 obj:{'name':'tom','age':18}
    26             },
    27             methods:{
    28             },
    29             computed:{
    30             },
    31             watch:{
    32                 name:{
    33                     handler:function (newVal,oldVal) {
    34                         console.log(newVal,oldVal);
    35                     }
    36                 },
    37                 arr:{
    38                     // 只能监听到 数组长度的变化,如果里面元素发生变化,是监听不到的
    39                     // 此时如果想要 修改里面元素 还想被监听到,就不能使用简单的 = 号了,
    40                     // 使用 app.$set(this.arr,0,'4'); 这是就可以被监听到了
    41                     handler:function (newVal,oldVal) {
    42                         console.log(newVal,oldVal);
    43 
    44                     },
    45                     // deep:true  没用,深度监听 也不可以
    46                 },
    47                 obj:{
    48                     // 只能监听到 整个对象的变化
    49                     handler:function (newVal,oldVal) {
    50                         console.log(newVal,oldVal);
    51                     },
    52                     deep:true // 但是,deep 只能监听 对象已有属性变化,如果新增还是监听不到,用  app.$set()
    53                 }
    54             }
    55         })
    56     </script>
    57 </body>
    58 </html>
    View Code

    vue 的 组件:

     1 <!DOCTYPE html>
     2 <html lang="zh-CN">
     3 <head>
     4     <meta charset="utf-8">
     5     <meta http-equiv="X-UA-Compatible" content="IE=edge">
     6     <meta name="viewport" content="width=device-width, initial-scale=1">
     7     <title>hello world</title>
     8 </head>
     9 <body>
    10     <div class="box" >
    11         <my_star></my_star>
    12     </div>
    13     <hr>
    14     <div class="box2" >
    15         <my_star></my_star>
    16     </div>
    17 
    18     <script src="vue.js"></script>
    19     <script>
    20         Vue.component('my_star',{
    21            template:`<div style="1px solid red;">我是div标签 by--{{title}}</div>`,
    22             data:function () {
    23                 return {
    24                     title:'tom'
    25                 }
    26             },
    27             methods:function () {
    28             }
    29         });
    30         const app1 = new Vue({
    31             el:'.box', // 1,指定 vue 的作用域
    32             data:{     // 2,放入数据
    33             },
    34             methods:{
    35             },
    36             computed:{
    37             },
    38             watch:{
    39             }
    40         });
    41         const app2 = new Vue({
    42             el:'.box2', // 1,指定 vue 的作用域
    43             data:{     // 2,放入数据
    44             },
    45             methods:{
    46             },
    47             computed:{
    48             },
    49             watch:{
    50             }
    51         })
    52     </script>
    53 </body>
    54 </html>
    全局注册 组件
     1 <!DOCTYPE html>
     2 <html lang="zh-CN">
     3 <head>
     4     <meta charset="utf-8">
     5     <meta http-equiv="X-UA-Compatible" content="IE=edge">
     6     <meta name="viewport" content="width=device-width, initial-scale=1">
     7     <title>hello world</title>
     8 </head>
     9 <body>
    10     <div class="box" >
    11         <my_star></my_star>
    12     </div>
    13     <script src="vue.js"></script>
    14     <script>
    15         let my_star = {
    16             template:`<div style="1px solid red;">我是div标签 by--{{title}}</div>`,
    17             data:function () {
    18                 return {
    19                     title:'tom'
    20                 }
    21             },
    22             methods:function () {
    23             }
    24         };
    25         const app1 = new Vue({
    26             el:'.box', // 1,指定 vue 的作用域
    27             data:{     // 2,放入数据
    28             },
    29             methods:{
    30             },
    31             computed:{
    32             },
    33             watch:{
    34             },
    35             components:{
    36                 my_star:my_star
    37             }
    38         });
    39 
    40     </script>
    41 </body>
    42 </html>
    局部注册 组件
    <!DOCTYPE html>
    <html lang="zh-CN">
    <head>
        <meta charset="utf-8">
        <meta http-equiv="X-UA-Compatible" content="IE=edge">
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <title>hello world</title>
    </head>
    <body>
        <div class="box" >
            <my_star></my_star>
        </div>
        <script src="vue.js"></script>
        <script>
            let star = {
                template:`<div style="1px solid blue;">我是子组件 --{{title}}</div>`,
                data:function () {
                    return {
                        title:'jane'
                    }
                },
                methods:function () {
                },
            };
            let my_star = {
                template:`<div style="1px solid red;">组件--{{title}}<star></star>     </div> `,
                data:function () {
                    return {
                        title:'tom'
                    }
                },
                methods:function () {
                },
                components: {
                    star:star
                }
            };
            const app1 = new Vue({
                el:'.box', // 1,指定 vue 的作用域
                data:{     // 2,放入数据
                },
                methods:{
                },
                computed:{
                },
                watch:{
                },
                components:{
                    my_star:my_star
                }
            });
    
        </script>
    </body>
    </html>
    子组件 内再注册 组件

    父子组件 通信 :

    父 ---->   子  

     1 <!DOCTYPE html>
     2 <html lang="zh-CN">
     3 <head>
     4     <meta charset="utf-8">
     5     <meta http-equiv="X-UA-Compatible" content="IE=edge">
     6     <meta name="viewport" content="width=device-width, initial-scale=1">
     7     <title>hello world</title>
     8 </head>
     9 <body>
    10     <div class="box" >
    11         <father></father>
    12     </div>
    13     <script src="vue.js"></script>
    14     <script>
    15         let son = {
    16             template:`<div>我是子组件 :[{{fa_say}}]</div>`,
    17             props:['fa_say']
    18         };
    19         let father = {
    20             template:`
    21                 <div>我是父组件  <son v-bind:fa_say="fa_say"></son> </div>
    22             `,
    23             components: {
    24                 son:son
    25             },
    26             data:function () {
    27                 return {
    28                     fa_say:'你好 son'
    29                 }
    30             }
    31 
    32         };
    33         const app1 = new Vue({
    34             el:'.box', // 1,指定 vue 的作用域
    35             data:{     // 2,放入数据
    36             },
    37             methods:{
    38             },
    39             computed:{
    40             },
    41             watch:{
    42             },
    43             components:{
    44                 father:father
    45             }
    46         });
    47 
    48     </script>
    49 </body>
    50 </html>
    View Code

    子父组件 通信 :

    子 --->  父  

    需要 儿子  先发射 emit  一个事件,  

     1 <!DOCTYPE html>
     2 <html lang="zh-CN">
     3 <head>
     4     <meta charset="utf-8">
     5     <meta http-equiv="X-UA-Compatible" content="IE=edge">
     6     <meta name="viewport" content="width=device-width, initial-scale=1">
     7     <title>hello world</title>
     8 </head>
     9 <body>
    10     <div class="box" >
    11         <father></father>
    12     </div>
    13     <script src="vue.js"></script>
    14     <script>
    15         let son = {
    16             template:`<div>我是子组件
    17                 <button @click="myEvt">点我</button>
    18             </div>`,
    19             methods: {
    20                 myEvt:function () {
    21                     this.$emit('sonEmit','我是你的儿子');
    22                 }
    23             }
    24         };
    25         let father = {
    26             template:`
    27                 <div>我是父组件  <son @sonEmit="myEvt"></son> </div>
    28             `,
    29             components: {
    30                 son:son
    31             },
    32             methods:{
    33                 myEvt:function (data) {
    34                     console.log(data);
    35                 }
    36             }
    37 
    38         };
    39         const app1 = new Vue({
    40             el:'.box', // 1,指定 vue 的作用域
    41             data:{     // 2,放入数据
    42             },
    43             methods:{
    44             },
    45             computed:{
    46             },
    47             watch:{
    48             },
    49             components:{
    50                 father:father
    51             }
    52         });
    53 
    54     </script>
    55 </body>
    56 </html>
    子父组件 通信

    非父子组件 通信 :

    这时需要一个第三方 来作为调度,  

     1 <!DOCTYPE html>
     2 <html lang="zh-CN">
     3 <head>
     4     <meta charset="utf-8">
     5     <meta http-equiv="X-UA-Compatible" content="IE=edge">
     6     <meta name="viewport" content="width=device-width, initial-scale=1">
     7     <title>hello world</title>
     8 </head>
     9 <body>
    10     <div class="box" >
    11         <c1></c1>
    12         <c2></c2>
    13 
    14     </div>
    15     <script src="vue.js"></script>
    16     <script>
    17         let middle = new Vue();
    18 
    19         let c1 = {
    20             template:` <div>
    21             组件1
    22             <button @click="myEvt">发送消息</button>
    23             </div> `,
    24             methods:{
    25                 myEvt:function () {
    26                     middle.$emit('myEmit','我是组件1,你呢?')
    27                 }
    28             }
    29         };
    30         let c2 = {
    31             template:` <div>组件2</div> `,
    32             mounted:function (res) {
    33                 // mounted 是当 组件加载之后  就执行的函数
    34                 middle.$on('myEmit',res=>{
    35                     // console.log(this); // 要注意this 的问题,  
    36                     console.log('组件二中:  ',res);
    37                 })
    38             }
    39 
    40         };
    41 
    42         const app1 = new Vue({
    43             el:'.box', // 1,指定 vue 的作用域
    44             data:{     // 2,放入数据
    45             },
    46             methods:{
    47             },
    48             computed:{
    49             },
    50             watch:{
    51             },
    52             components:{
    53                 c1:c1,
    54                 c2:c2
    55             }
    56         });
    57 
    58     </script>
    59 </body>
    60 </html>
    View Code

    混合   :

    共用一个代码块,  

     1 <!DOCTYPE html>
     2 <html lang="zh-CN">
     3 <head>
     4     <meta charset="utf-8">
     5     <meta http-equiv="X-UA-Compatible" content="IE=edge">
     6     <meta name="viewport" content="width=device-width, initial-scale=1">
     7     <title>hello world</title>
     8 </head>
     9 <body>
    10     <div class="box" >
    11         <c1></c1>
    12         <hr>
    13         <c2></c2>
    14 
    15     </div>
    16     <script src="vue.js"></script>
    17     <script>
    18         let base = {
    19             data() {
    20                 return {
    21                     title:'hello world'
    22                 }
    23             },
    24             methods:{
    25                 // 也可以注册事件
    26             }
    27         };
    28         let c1 = {
    29             template:` <div>{{title}}</div> `,
    30             methods:{
    31             },
    32             mixins:[base]
    33         };
    34         let c2 = {
    35             template:` <div>{{title}}</div> `,
    36             methods:{
    37             },
    38             mixins:[base]
    39         };
    40 
    41         const app1 = new Vue({
    42             el:'.box', // 1,指定 vue 的作用域
    43             data:{     // 2,放入数据
    44             },
    45             methods:{
    46             },
    47             computed:{
    48             },
    49             watch:{
    50             },
    51             components:{
    52                 c1:c1,
    53                 c2:c2
    54             }
    55         });
    56 
    57     </script>
    58 </body>
    59 </html>
    View Code

    组件中 开槽 slot:  

     1 <!DOCTYPE html>
     2 <html lang="zh-CN">
     3 <head>
     4     <meta charset="utf-8">
     5     <meta http-equiv="X-UA-Compatible" content="IE=edge">
     6     <meta name="viewport" content="width=device-width, initial-scale=1">
     7     <title>hello world</title>
     8 </head>
     9 <body>
    10     <div class="box" >
    11         <c1>
    12             <a href="http://www.baidu.com">百度一下</a>
    13         </c1>
    14     </div>
    15     <script src="vue.js"></script>
    16     <script>
    17         let c1 = {
    18             template:` <div>  <slot></slot>  </div> `,
    19             methods:{
    20             },
    21         };
    22         const app1 = new Vue({
    23             el:'.box', // 1,指定 vue 的作用域
    24             data:{     // 2,放入数据
    25             },
    26             methods:{
    27             },
    28             computed:{
    29             },
    30             watch:{
    31             },
    32             components:{
    33                 c1:c1,
    34             }
    35         });
    36 
    37     </script>
    38 </body>
    39 </html>
    View Code
     1 <!DOCTYPE html>
     2 <html lang="zh-CN">
     3 <head>
     4     <meta charset="utf-8">
     5     <meta http-equiv="X-UA-Compatible" content="IE=edge">
     6     <meta name="viewport" content="width=device-width, initial-scale=1">
     7     <title>hello world</title>
     8 </head>
     9 <body>
    10     <div class="box" >
    11         <c1>
    12             <a slot="s1" href="http://www.baidu.com">百度一下</a>
    13             <a slot="s2" href="http://www.google.com">谷歌一下</a>
    14         </c1>
    15     </div>
    16     <script src="vue.js"></script>
    17     <script>
    18         let c1 = {
    19             template:` <div>
    20                              <slot name="s1"></slot>
    21                              <slot name="s2"></slot>
    22                         </div> `,
    23             methods:{
    24             },
    25         };
    26         const app1 = new Vue({
    27             el:'.box', // 1,指定 vue 的作用域
    28             data:{     // 2,放入数据
    29             },
    30             methods:{
    31             },
    32             computed:{
    33             },
    34             watch:{
    35             },
    36             components:{
    37                 c1:c1,
    38             }
    39         });
    40 
    41     </script>
    42 </body>
    43 </html>
    View Code

    vue 路由: 

    vue通过 路由  和 组件 可以构建一个 单页面的应用,  

     1 <!DOCTYPE html>
     2 <html lang="zh-CN">
     3 <head>
     4     <meta charset="utf-8">
     5     <meta http-equiv="X-UA-Compatible" content="IE=edge">
     6     <meta name="viewport" content="width=device-width, initial-scale=1">
     7     <title>hello world</title>
     8 </head>
     9 <body>
    10     <div class="box" >
    11         <router-link to="/">首页</router-link> <!--router-link 底层是 a 标签  -->
    12         <router-link to="/course">课程</router-link>
    13 
    14         <router-view></router-view>  <!-- 用于放 url 中path对应的组件 -->
    15     </div>
    16     <script src="vue.js"></script>
    17     <script src="vue-router.js"></script>
    18     <script>
    19         //1, 定义路由 和 组件的匹配规则
    20         let url = [
    21             {
    22                 path:'/',
    23                 component:{
    24                     template: `<div>这是组件1,根目录</div> `
    25                 }
    26             },
    27             {
    28                 path:'/course',
    29                 component:{
    30                     template: `<div>这是组件2,课程目录</div> `
    31                 }
    32             }
    33         ];
    34         // 2 实例化  VueRouter 对象
    35         let router = new VueRouter({
    36             routes:url
    37         });
    38         // 3把 实例化的 router 放到 app1中
    39         const app1 = new Vue({
    40             el:'.box',
    41             router:router,
    42 
    43         });
    44 
    45     </script>
    46 </body>
    47 </html>
    简单路由 demo

    给url 起别名:  

     1 <!DOCTYPE html>
     2 <html lang="zh-CN">
     3 <head>
     4     <meta charset="utf-8">
     5     <meta http-equiv="X-UA-Compatible" content="IE=edge">
     6     <meta name="viewport" content="width=device-width, initial-scale=1">
     7     <title>hello world</title>
     8 </head>
     9 <body>
    10     <div class="box" >
    11         <router-link :to="{name:'home'}">首页</router-link> <!--router-link 底层是 a 标签  -->
    12         <router-link :to="{name:'course'}">课程</router-link>
    13 
    14         <router-view></router-view>  <!-- 用于放 url 中path对应的组件 -->
    15     </div>
    16     <script src="vue.js"></script>
    17     <script src="vue-router.js"></script>
    18     <script>
    19         //1, 定义路由 和 组件的匹配规则
    20         let url = [
    21             {
    22                 path:'/',
    23                 name:'home',// 起别名
    24                 component:{
    25                     template: `<div>这是组件1,根目录</div> `
    26                 }
    27             },
    28             {
    29                 path:'/course',
    30                 name:'course', // 起别名
    31                 component:{
    32                     template: `<div>这是组件2,课程目录</div> `
    33                 }
    34             }
    35         ];
    36         // 2 实例化  VueRouter 对象
    37         let router = new VueRouter({
    38             routes:url
    39         });
    40         // 3把 实例化的 router 放到 app1中
    41         const app1 = new Vue({
    42             el:'.box',
    43             router:router,
    44 
    45         });
    46 
    47     </script>
    48 </body>
    49 </html>
    View Code

    路由的参数  : 

     1 <!DOCTYPE html>
     2 <html lang="zh-CN">
     3 <head>
     4     <meta charset="utf-8">
     5     <meta http-equiv="X-UA-Compatible" content="IE=edge">
     6     <meta name="viewport" content="width=device-width, initial-scale=1">
     7     <title>hello world</title>
     8 </head>
     9 <body>
    10     <div class="box" >
    11         <router-link :to="{name:'home'}">首页</router-link> <!--router-link 底层是 a 标签  -->
    12         <router-link :to="{name:'course'}">课程</router-link>
    13         <router-link :to="{name:'user',params:{username:'xxx'},query:{age:18}}">用户</router-link>
    14 
    15         <router-view></router-view>  <!-- 用于放 url 中path对应的组件 -->
    16     </div>
    17     <script src="vue.js"></script>
    18     <script src="vue-router.js"></script>
    19     <script>
    20         //1, 定义路由 和 组件的匹配规则
    21         let url = [
    22             {
    23                 path:'/',
    24                 name:'home',// 起别名
    25                 component:{
    26                     template: `<div>这是组件1,根目录</div> `
    27                 }
    28             },
    29             {
    30                 path:'/course',
    31                 name:'course', // 起别名
    32                 component:{
    33                     template: `<div>这是组件2,课程目录</div> `
    34                 }
    35             },
    36             {
    37                 path:'/user/:name',
    38                 name:'user', // 起别名
    39                 component:{
    40                     template: `<div>我是【{{this.$route.params.username}}】,我今年【{{this.$route.query.age}}】 岁</div> `
    41                 },
    42                 mounted:function () {
    43                     console.log(this.$route);
    44                 }
    45             }
    46         ];
    47         // 2 实例化  VueRouter 对象
    48         let router = new VueRouter({
    49             routes:url
    50         });
    51         // 3把 实例化的 router 放到 app1中
    52         const app1 = new Vue({
    53             el:'.box',
    54             router:router,
    55 
    56         });
    57 
    58     </script>
    59 </body>
    60 </html>
    View Code

    手动路由:

    需要用 this.$router ,

    注: router  是 VueRouter 的实例化对象, 而 route 只是当前url 的信息,  

    this.$router.push() 就可以改变路由,  

     1 <!DOCTYPE html>
     2 <html lang="zh-CN">
     3 <head>
     4     <meta charset="utf-8">
     5     <meta http-equiv="X-UA-Compatible" content="IE=edge">
     6     <meta name="viewport" content="width=device-width, initial-scale=1">
     7     <title>hello world</title>
     8 </head>
     9 <body>
    10     <div class="box" >
    11         <router-link :to="{name:'home'}">首页</router-link> <!--router-link 底层是 a 标签  -->
    12 
    13         <router-view></router-view>  <!-- 用于放 url 中path对应的组件 -->
    14     </div>
    15     <script src="vue.js"></script>
    16     <script src="vue-router.js"></script>
    17     <script>
    18         //1, 定义路由 和 组件的匹配规则
    19         let url = [
    20             {
    21                 path:'/',
    22                 name:'home',// 起别名
    23                 component:{
    24                     template: `<div>这是组件1,根目录
    25                                 <button @click="clickEvt">点击登录</button>
    26                               </div> `,
    27                     methods:{
    28                     clickEvt:function () {
    29                         console.log(this.$route);
    30                         console.log(this.$router);
    31                         // console.log(this.$el);
    32                         // console.log(this.$data);
    33 
    34                         this.$router.push('/login');  // $router.push 方法 手动路由,
    35                         }
    36                     }
    37                 },
    38 
    39             },
    40             {
    41                 path:'/login',
    42                 name:'login', // 起别名
    43                 component:{
    44                     template: `<div>这是登录页面</div> `
    45                 }
    46             },
    47 
    48         ];
    49         // 2 实例化  VueRouter 对象
    50         let router = new VueRouter({
    51             routes:url
    52         });
    53         // 3把 实例化的 router 放到 app1中
    54         const app1 = new Vue({
    55             el:'.box',
    56             router:router,
    57 
    58         });
    59 
    60     </script>
    61 </body>
    62 </html>
    手动路由

    路由下配置子路由:   

     1 <!DOCTYPE html>
     2 <html lang="zh-CN">
     3 <head>
     4     <meta charset="utf-8">
     5     <meta http-equiv="X-UA-Compatible" content="IE=edge">
     6     <meta name="viewport" content="width=device-width, initial-scale=1">
     7     <title>hello world</title>
     8 </head>
     9 <body>
    10     <div class="box" >
    11         <router-link :to="{name:'home'}">首页</router-link> <!--router-link 底层是 a 标签  -->
    12         <router-link :to="{name:'user'}">查看用户</router-link> <!--router-link 底层是 a 标签  -->
    13 
    14         <router-view></router-view>  <!-- 用于放 url 中path对应的组件 -->
    15     </div>
    16     <script src="vue.js"></script>
    17     <script src="vue-router.js"></script>
    18     <script>
    19         //1, 定义路由 和 组件的匹配规则
    20         let url = [
    21             {
    22                 path:'/',
    23                 name:'home',// 起别名
    24                 component:{
    25                     template: `<div>这是组件1,根目录
    26                                 <button @click="clickEvt">点击登录</button>
    27                               </div> `,
    28                     methods:{
    29                     clickEvt:function () {
    30                         this.$router.push('/login');
    31                         }
    32                     }
    33                 },
    34             },
    35             {
    36                 path:'/user',
    37                 name:'user', // 起别名
    38                 component:{
    39                     template: `<div>这是用户页面
    40                             <hr>
    41                             <router-link :to="{name:'userDetail1'}">用户详情1</router-link>
    42                             <router-link :to="{name:'userDetail2'}">用户详情2</router-link>
    43                             <router-view></router-view>
    44                         </div> `
    45                 },
    46                 children:[
    47                     {
    48                         path:'userDetail1',
    49                         name:'userDetail1',
    50                         component:{
    51                             template: `<div>详情页面1</div> `
    52                         },
    53                     },
    54                     {
    55                         path:'userDetail2',
    56                         name:'userDetail2',
    57                         component:{
    58                             template: `<div>详情页面2</div> `
    59                         },
    60                     }
    61 
    62 
    63 
    64                 ]
    65             },
    66 
    67         ];
    68         // 2 实例化  VueRouter 对象
    69         let router = new VueRouter({
    70             routes:url
    71         });
    72         // 3把 实例化的 router 放到 app1中
    73         const app1 = new Vue({
    74             el:'.box',
    75             router:router,
    76 
    77         });
    78 
    79     </script>
    80 </body>
    81 </html>
    配置子路由
     1 <!DOCTYPE html>
     2 <html lang="zh-CN">
     3 <head>
     4     <meta charset="utf-8">
     5     <meta http-equiv="X-UA-Compatible" content="IE=edge">
     6     <meta name="viewport" content="width=device-width, initial-scale=1">
     7     <title>hello world</title>
     8 </head>
     9 <body>
    10     <div class="box" >
    11         <router-link :to="{name:'home'}">首页</router-link> <!--router-link 底层是 a 标签  -->
    12         <router-link :to="{name:'user'}">查看用户</router-link> <!--router-link 底层是 a 标签  -->
    13 
    14         <router-view></router-view>  <!-- 用于放 url 中path对应的组件 -->
    15     </div>
    16     <script src="vue.js"></script>
    17     <script src="vue-router.js"></script>
    18     <script>
    19         //1, 定义路由 和 组件的匹配规则
    20         let url = [
    21             {
    22                 path:'/',
    23                 name:'home',// 起别名
    24                 component:{
    25                     template: `<div>这是组件1,根目录
    26                                 <button @click="clickEvt">点击登录</button>
    27                               </div> `,
    28                     methods:{
    29                     clickEvt:function () {
    30                         this.$router.push('/login');
    31                         }
    32                     }
    33                 },
    34             },
    35             {
    36                 path:'/user',
    37                 name:'user', // 起别名
    38                 redirect:{
    39                     name:'userDetail1'
    40                 },
    41                 component:{
    42                     template: `<div>这是用户页面
    43                             <hr>
    44                             <router-link :to="{name:'userDetail1'}">用户详情1</router-link>
    45                             <router-link :to="{name:'userDetail2'}">用户详情2</router-link>
    46                             <router-view></router-view>
    47                         </div> `
    48                 },
    49                 children:[
    50                     {
    51                         path:'userDetail1',
    52                         name:'userDetail1',
    53                         component:{
    54                             template: `<div>详情页面1</div> `
    55                         },
    56                     },
    57                     {
    58                         path:'userDetail2',
    59                         name:'userDetail2',
    60                         component:{
    61                             template: `<div>详情页面2</div> `
    62                         },
    63                     }
    64 
    65 
    66 
    67                 ]
    68             },
    69 
    70         ];
    71         // 2 实例化  VueRouter 对象
    72         let router = new VueRouter({
    73             routes:url
    74         });
    75         // 3把 实例化的 router 放到 app1中
    76         const app1 = new Vue({
    77             el:'.box',
    78             router:router,
    79 
    80         });
    81 
    82     </script>
    83 </body>
    84 </html>
    redirect 直接到 一个子路由

    路由钩子函数:

     1 <!DOCTYPE html>
     2 <html lang="zh-CN">
     3 <head>
     4     <meta charset="utf-8">
     5     <meta http-equiv="X-UA-Compatible" content="IE=edge">
     6     <meta name="viewport" content="width=device-width, initial-scale=1">
     7     <title>hello world</title>
     8 </head>
     9 <body>
    10     <div class="box" >
    11         <router-link :to="{name:'home'}">首页</router-link> <!--router-link 底层是 a 标签  -->
    12         <router-link :to="{name:'user'}">查看用户</router-link> <!--router-link 底层是 a 标签  -->
    13 
    14         <router-view></router-view>  <!-- 用于放 url 中path对应的组件 -->
    15     </div>
    16     <script src="vue.js"></script>
    17     <script src="vue-router.js"></script>
    18     <script>
    19         //1, 定义路由 和 组件的匹配规则
    20         let url = [
    21             {
    22                 path:'/',
    23                 name:'home',// 起别名
    24                 component:{
    25                     template: `<div>这是组件1,根目录
    26                                 <button @click="clickEvt">点击登录</button>
    27                               </div> `,
    28                     methods:{
    29                     clickEvt:function () {
    30                         this.$router.push('/login');
    31                         }
    32                     }
    33                 },
    34 
    35             },
    36             {
    37                 path:'/login',
    38                 name:'login', // 起别名
    39                 component:{
    40                     template: `<div>这是登录页面</div> `
    41                 }
    42             },
    43             {
    44                 path:'/user',
    45                 name:'user', // 起别名
    46                 component:{
    47                     template: `<div>这是用户页面</div> `
    48                 }
    49             },
    50 
    51         ];
    52         // 2 实例化  VueRouter 对象
    53         let router = new VueRouter({
    54             routes:url
    55         });
    56         // 路由钩子函数
    57         router.beforeEach(function (to,from,next) {
    58             console.log(to);   // 去哪个 route
    59             console.log(from); // 从哪个 route 来
    60             console.log(next); // 下一步 干什么
    61             if (to.path === '/user' ){
    62                 next('/login'); // 如果用户没登录 就查看 user ,要跳到 login
    63             }else{
    64                 next(); // 正常情况 直接next();  如果没有 next() 或者 next(false);这样就不跳转了,
    65             }
    66 
    67 
    68         });
    69 
    70         // 3把 实例化的 router 放到 app1中
    71         const app1 = new Vue({
    72             el:'.box',
    73             router:router,
    74 
    75         });
    76 
    77     </script>
    78 </body>
    79 </html>
    基本用法 
     1 <!DOCTYPE html>
     2 <html lang="zh-CN">
     3 <head>
     4     <meta charset="utf-8">
     5     <meta http-equiv="X-UA-Compatible" content="IE=edge">
     6     <meta name="viewport" content="width=device-width, initial-scale=1">
     7     <title>hello world</title>
     8 </head>
     9 <body>
    10     <div class="box" >
    11         <router-link :to="{name:'home'}">首页</router-link> <!--router-link 底层是 a 标签  -->
    12         <router-link :to="{name:'user'}">查看用户</router-link> <!--router-link 底层是 a 标签  -->
    13 
    14         <router-view></router-view>  <!-- 用于放 url 中path对应的组件 -->
    15     </div>
    16     <script src="vue.js"></script>
    17     <script src="vue-router.js"></script>
    18     <script>
    19         //1, 定义路由 和 组件的匹配规则
    20         let url = [
    21             {
    22                 path:'/',
    23                 name:'home',// 起别名
    24                 component:{
    25                     template: `<div>这是组件1,根目录
    26                                 <button @click="clickEvt">点击登录</button>
    27                               </div> `,
    28                     methods:{
    29                     clickEvt:function () {
    30                         this.$router.push('/login');
    31                         }
    32                     }
    33                 },
    34             },
    35             {
    36                 path:'/login',
    37                 name:'login', // 起别名
    38                 component:{
    39                     template: `<div>这是登录页面</div> `
    40                 }
    41             },
    42             {
    43                 path:'/user',
    44                 name:'user', // 起别名
    45                 meta:{   // 元信息配置
    46                     must_login:true,
    47                 },
    48                 component:{
    49                     template: `<div>这是用户页面</div> `
    50                 }
    51             },
    52 
    53         ];
    54         // 2 实例化  VueRouter 对象
    55         let router = new VueRouter({
    56             routes:url
    57         });
    58         // 路由钩子函数
    59         router.beforeEach(function (to,from,next) {
    60             console.log(to);   // 去哪个 route
    61             console.log(from); // 从哪个 route 来
    62             console.log(next); // 下一步 干什么
    63             if (to.meta.must_login){
    64                 next('/login'); // 如果用户没登录 就查看 user ,要跳到 login
    65             }else{
    66                 next(); // 正常情况 直接next();  如果没有 next() 或者 next(false);这样就不跳转了,
    67             }
    68 
    69 
    70         });
    71 
    72         // 3把 实例化的 router 放到 app1中
    73         const app1 = new Vue({
    74             el:'.box',
    75             router:router,
    76 
    77         });
    78 
    79     </script>
    80 </body>
    81 </html>
    配置 route 里的元信息 meta

    还有 router.afterEach():  不过它没有 next 操作,  

    命名的 router-view   

     1 <!DOCTYPE html>
     2 <html lang="zh-CN">
     3 <head>
     4     <meta charset="utf-8">
     5     <meta http-equiv="X-UA-Compatible" content="IE=edge">
     6     <meta name="viewport" content="width=device-width, initial-scale=1">
     7     <title>hello world</title>
     8 </head>
     9 <body>
    10     <div class="box" >
    11         <router-link :to="{name:'home'}">首页</router-link> <!--router-link 底层是 a 标签  -->
    12         <router-link :to="{name:'user'}">查看用户</router-link> <!--router-link 底层是 a 标签  -->
    13         <router-view name="head"></router-view>  <!--专门展示 头部 head -->
    14         <router-view></router-view>
    15         <router-view name="foot"></router-view> <!--专门展示 尾部 foot  -->
    16     </div>
    17     <script src="vue.js"></script>
    18     <script src="vue-router.js"></script>
    19     <script>
    20         let url = [
    21             {
    22                 path:'/',
    23                 name:'home',// 起别名
    24                 component:{
    25                     template: `<div>这是组件1,根目录
    26                                 <button @click="clickEvt">点击登录</button>
    27                               </div> `,
    28                     methods:{
    29                     clickEvt:function () {
    30                         this.$router.push('/login');
    31                         }
    32                     }
    33                 },
    34             },
    35             {
    36                 path:'/user',
    37                 name:'user', // 起别名
    38                 components: {
    39                     head:{
    40                         template: `<div>头部页面 </div> `
    41                     },
    42                     foot:{
    43                         template: `<div>尾部页面 </div> `
    44                     }
    45 
    46                 },
    47 
    48             },
    49 
    50         ];
    51         let router = new VueRouter({
    52             routes:url,
    53             mode:'history' // 可以整洁 地址栏中的 url
    54         });
    55         const app1 = new Vue({
    56             el:'.box',
    57             router:router,
    58 
    59         });
    60 
    61     </script>
    62 </body>
    63 </html>
    View Code

    其他:  

    mode = 'history' 小参数

    vue 生命周期: 

    https://www.cnblogs.com/GGGG-XXXX/articles/9467297.html

     1 <!DOCTYPE html>
     2 <html lang="zh-CN">
     3 <head>
     4     <meta charset="utf-8">
     5     <meta http-equiv="X-UA-Compatible" content="IE=edge">
     6     <meta name="viewport" content="width=device-width, initial-scale=1">
     7     <title>hello world</title>
     8 </head>
     9 <body>
    10     <div class="box" >
    11        {{username}}
    12     </div>
    13     <script src="vue.js"></script>
    14     <script src="vue-router.js"></script>
    15     <script>
    16         const app1 = new Vue({
    17             el:'.box',
    18             data:{
    19                 username:'tom'
    20             },
    21             methods:{
    22                 func:function () {
    23                     console.log('hello');     
    24                 }
    25             },
    26             beforeCreate(){ // 1, 钩子函数 1  
    27                 console.group('beforeCreate');
    28                 console.log(this.$el);   //undefined
    29                 console.log(this.username); //undefined
    30                 console.log(this.func); //undefined
    31             },
    32             created(){ // 2, 钩子函数 2
    33                 console.group('created');
    34                 console.log(this.$el); //undefined
    35                 console.log(this.username); // tom
    36                 console.log(this.func); // ƒ () { ... }
    37 
    38             },
    39             beforeMount(){ // 3, 钩子函数 3
    40                 console.group('beforeMount 页面真实加载完成之前 , 下面就要编译 dom, 就是做编译 一些例如 router-link router-view 等的工作');
    41                 console.log(this.$el); //  <div>...</div>
    42                 console.log(this.username); // tom
    43                 console.log(this.func); // ƒ () { ... }
    44             },
    45             mounted(){ // 4, 钩子函数 4  *******常用******
    46                 console.group('mounted 页面真实加载完成之后');
    47                 console.log(this.$el); //  <div>...</div>
    48                 console.log(this.username); // tom
    49                 console.log(this.func); // ƒ () { ... }
    50             },
    51             beforeUpdate(){ // 5, 钩子函数 5   *******常用******
    52                 console.group('beforeUpdate  更改数据 之前 ');
    53                 console.log(this.$el); //  <div>...</div>
    54                 console.log(this.username); // tom
    55                 console.log(this.func); // ƒ () { ... }
    56             },
    57             updated(){ // 6, 钩子函数 6    *******常用******
    58                 console.group('updated  更改数据 之后');
    59                 console.log(this.$el); //  <div>...</div>
    60                 console.log(this.username); // tom
    61                 console.log(this.func); // ƒ () { ... }
    62             },
    63 
    64 
    65             beforeDestroy(){ // 7, 钩子函数 7  app.$destroy(); 会触发它们,
    66                 console.group('beforeDestroy');
    67                 console.log(this.$el); 
    68                 console.log(this.username); 
    69                 console.log(this.func); 
    70             },
    71             destroyed(){ // 8, 钩子函数 8
    72                 console.group('destroyed 一旦销毁之后 vue 的实例对象就不能再用了');
    73                 console.log(this.$el); 
    74                 console.log(this.username); 
    75                 console.log(this.func); 
    76             },
    77 
    78         });
    79 
    80     </script>
    81 </body>
    82 </html>
    生命周期

    element  :

    https://element.eleme.cn/#/zh-CN

    现在很多网站都是 vue +  element 来搭,不会用 jquery 和 bootstrap ,

    但是,前后端不分离还是会用 jquery 和 bootstrap 来搭 

    导航条:

     1 <!DOCTYPE html>
     2 <html lang="zh-CN">
     3 <head>
     4     <meta charset="utf-8">
     5     <meta http-equiv="X-UA-Compatible" content="IE=edge">
     6     <meta name="viewport" content="width=device-width, initial-scale=1">
     7     <title>hello world</title>
     8 
     9 
    10     <script src="vue.js"></script>
    11     <script src="vue-router.js"></script>
    12     <!-- element -->
    13     <link rel="stylesheet" href="element/index.css">
    14     <script src="element/index.js"></script>
    15     <!-- 引入样式 -->
    16 <!--    <link rel="stylesheet" href="https://unpkg.com/element-ui/lib/theme-chalk/index.css">-->
    17     <!-- 引入组件库 -->
    18 <!--    <script src="https://unpkg.com/element-ui/lib/index.js"></script>-->
    19     <style>
    20         .el-menu{
    21             display: flex;
    22             justify-content: center;
    23         }
    24     </style>
    25 </head>
    26 <body>
    27     <template id="header">
    28         <div class="page_head">
    29 <!--            <el-menu :default-active="activeIndex" class="el-menu-demo" mode="horizontal" @select="handleSelect">-->
    30             <el-menu :default-active="activeIndex" class="el-menu-demo" mode="horizontal" >
    31                   <el-menu-item index="0">首页</el-menu-item>
    32                   <el-menu-item index="1">免费课程</el-menu-item>
    33                   <el-menu-item index="2">轻课</el-menu-item>
    34                   <el-menu-item index="3">学位课程</el-menu-item>
    35                   <el-menu-item index="4">智能题库</el-menu-item>
    36             </el-menu>
    37 
    38         </div>
    39     </template>
    40     <div class="box">
    41         <my_header></my_header>
    42     </div>
    43     <script>
    44         let my_header = {
    45             template:'#header',// 这里是使用 选择器
    46             data(){
    47                 return {
    48                     activeIndex:'0',
    49                 }
    50             }
    51         };
    52         const app = new Vue({
    53             el:'.box',
    54             components: {
    55                 my_header:my_header,
    56             }
    57         });
    58     </script>
    59 </body>
    60 </html>
    View Code
     1 <!DOCTYPE html>
     2 <html lang="zh-CN">
     3 <head>
     4     <meta charset="utf-8">
     5     <meta http-equiv="X-UA-Compatible" content="IE=edge">
     6     <meta name="viewport" content="width=device-width, initial-scale=1">
     7     <title>hello world</title>
     8 
     9 
    10     <script src="vue.js"></script>
    11     <script src="vue-router.js"></script>
    12     <!-- element -->
    13     <link rel="stylesheet" href="element/index.css">
    14     <script src="element/index.js"></script>
    15     <!-- 引入样式 -->
    16 <!--    <link rel="stylesheet" href="https://unpkg.com/element-ui/lib/theme-chalk/index.css">-->
    17     <!-- 引入组件库 -->
    18 <!--    <script src="https://unpkg.com/element-ui/lib/index.js"></script>-->
    19     <style>
    20         .el-menu{
    21             display: flex;
    22             justify-content: center;
    23         }
    24     </style>
    25 </head>
    26 <body>
    27     <template id="header">
    28         <div class="page_head">
    29 <!--            <el-menu :default-active="activeIndex" class="el-menu-demo" mode="horizontal" @select="handleSelect">-->
    30             <el-menu :default-active="activeIndex" class="el-menu-demo" mode="horizontal" :router="true">
    31                   <el-menu-item index="/">首页</el-menu-item>
    32                   <el-menu-item index="/course">免费课程</el-menu-item>
    33                   <el-menu-item index="2">轻课</el-menu-item>
    34                   <el-menu-item index="3">学位课程</el-menu-item>
    35                   <el-menu-item index="4">智能题库</el-menu-item>
    36             </el-menu>
    37 
    38         </div>
    39     </template>
    40     <div class="box">
    41         <my_header></my_header>
    42         <router-view></router-view>
    43     </div>
    44     <script>
    45         let my_header = {
    46             template:'#header',// 这里是使用 选择器
    47             data(){
    48                 return {
    49                     activeIndex:'/',
    50                 }
    51             }
    52         };
    53         let url = [
    54             {
    55                 path:'/',
    56                 component:{
    57                     template:`<div>这是首页</div>`
    58                 },
    59             },
    60             {
    61                 path:'/course',
    62                 component:{
    63                     template:`<div>这是免费课程页面</div>`
    64                 },
    65             },
    66         ];
    67         let router = new VueRouter({
    68             routes:url,
    69             mode:'history',
    70         });
    71         const app = new Vue({
    72             el:'.box',
    73             router:router,
    74             components: {
    75                 my_header:my_header,
    76             }
    77         });
    78     </script>
    79 
    80 
    81 
    82 </body>
    83 </html>
    element el-menu 组件中 router 属性开启

    npm 管理项目   :

    https://www.cnblogs.com/GGGG-XXXX/articles/9503423.html

    npm run 可以运行 package.json 中的脚本,  

    webpack 打包工具   :

    默认入口文件 index.js ,出口文件  main.js  ,   webpack 中的文件支持 es6 的 export  和 import   

    vue-cli   :

    https://files.cnblogs.com/files/zach0812/vue-cli%E6%90%AD%E5%BB%BA%E9%A1%B9%E7%9B%AE.zip

    下到全局: npm install vue-cli -g  

    然后切换到工作目录: vue init webpack 项目名字   

    vuex : 

    https://www.cnblogs.com/GGGG-XXXX/articles/9467325.html

    npm install vuex --save 

    为了解决组件间通信麻烦的问题,出现了 vue-x  ,它是用来管理共用数据的

    mpvue 中使用: 

    https://files.cnblogs.com/files/zach0812/vuex%E7%9A%84%E7%94%A8%E6%B3%95state.zip

    axios : 

    npm install axios --save  

    它是向后端发送ajax 的工具,当然,你也可以使用原生 js ,或者使用jquery ,

    axios 不能注册到 vue 的根实例中,但是,我们还想通过this.$ 来使用axios 

    可以通过加到原型中来干: 

    如果安装失败可以:

    npm cache clean --force

    vue-cookie :

    将数据保存到 本地浏览器,

     
  • 相关阅读:
    大型站点技术架构PDF阅读笔记(一):
    【大话QT之十三】系统软件自己主动部署实现方案
    VS编译duilib项目时候的错误解决方法整理
    Missing iOS Distribution signing identity for …, 在打包的时候发现证书过期了。
    Django项目国际化
    Codeforces Round #297 (Div. 2) 525D Arthur and Walls(dfs)
    BZOJ 2209: [Jsoi2011]括号序列 [splay 括号]
    NOIP2016DAY1题解
    清北学堂入学测试P4751 H’s problem(h)
    BZOJ 3173: [Tjoi2013]最长上升子序列 [splay DP]
  • 原文地址:https://www.cnblogs.com/zach0812/p/12389913.html
Copyright © 2020-2023  润新知