一、ORM(对象关系映射) 很多语言的web框架中都有这个概念
1、 为什么要有ORM?
    1. 写程序离不开数据,要使用数据就需要连接数据库,但是不同的数据库在sql语句上(mysql,oracle等)会有点区别,
        因此直接在你的项目中使用sql语句的话,不便于以后的修改,万一更换了数据库,那所有sql语句不就要重新写吗?
        所以这个时候ORM就体现出优点了,你只需要写ORM的代码,它就会根据你连接的数据库自动帮你翻译成对应的sql语句,
        也就是说无论你使用的是mysql还是oracle,ORM操作数据库的语句都是一样的。
        
        
    2. 不使用ORM时在Python程序中使用数据库的操作如下:
        1. 使用pymysql连接MySQL数据库的步骤
            1. import pymysql
            2. 建立连接
                conn = pymysql.connect(
                    host=‘127.0.0.1‘,       # 数据库的ip地址
                    port=3306,              # 数据库的端口
                    database=‘db1‘,         # 要使用哪个数据库
                    user=‘root‘,            # 用户名
                    password=‘123abc‘,      # 密码
                    charset=‘utf8‘          # 编码(记得别写utf-8)
                )
            3. 获取光标对象
                cursor = conn.cursor()                                     --> 默认返回((), ())
                cursor = conn.cursor(cursor=pymysql.cursors.DictCursor)    --> 默认返回[{}, {}]
            4. 执行sql语句
                cursor.execute(‘select * from userinfo‘)
                cursor.execute(‘select * from userinfo where username=%s and password=%s‘, [‘ming‘, ‘1234‘])
            5. 获取结果
                1. cursor.fetchone()        # 获取一条
                2. cursor.fetchall()        # 获取全部
                3. cursor.fetchmany(size)   # 获取size个
                
                
2、 ORM(Object Relational Mapping)是什么?
    1. 新的语法,不需要我们自己写SQL语句
    2. 我们按照新的语法写代码,他帮我翻译成SQL语句
    
    
3、 ORM优缺点
    ORM优点:
        1. 开发效率高
        2. 容易掌握
        3. 容易移植    
    ORM的缺点:
        1. 代码的执行效率低
        
        
4、ORM的映射
    python中的类        对应         数据库中的表
    类中的属性           对应         数据库中的字段
    类的对象             对应         数据库中的记录
    
    
5、ORM能做哪些事情
    1. 操作数据库中的表
    2. 操作数据库中的记录
    3. 不能操作数据库,建库还是得你自己用sql语句创建
    
    
6、Django中使用ORM的步骤
    1. 在settings那里设置databases,告诉Django框架连接哪个数据库
        DATABASES = {
            ‘default‘: {
                ‘ENGINE‘: ‘django.db.backends.mysql‘,  # 告诉Django要连接的是MySQL数据库
                ‘NAME‘: ‘db1‘,        # 数据库名称
                ‘HOST‘: ‘127.0.0.1‘,  # 数据库的IP
                ‘PORT‘: 3306,         # 数据库的端口
                ‘USER‘: ‘root‘,       # 连接数据的账号
                ‘PASSWORD‘: ‘123abc‘  # 连接数据库的密码
            }
        }
        
    2. 告诉Django框架用什么连接数据库
        在和settings.py同目录下的__init__.py文件中:
            import pymysql
            pymysql.install_as_MySQLdb()
            
    3. 在app下面的models.py这个文件中定义类
        from django.db import models
        class 类名(models.Model):
            pass
            
    4. 两个命令修改数据库中的表(DDL语言)
        1. python manage.py makemigrations     --> 在app/migrations上记录models.py的变更
        2. python manage.py migrate            --> 把变更记录翻译成SQL语句,去数据库执行
    
7、ORM创建字段的语法
    id = models.AutoField(primary_key=True)          # 创建自增的id主键
    password = models.CharField(max_length=20)       # varchar(20)
    publisher = models.ForeignKey(to=‘外键关联的类名‘)  # 创建外键publisher,会自动关联另一种表的主键
   book = models.ManyToManyField(to=‘Book‘)         # ORM帮我们自动创建的第三张表(用于多对多查询)
   age = models.IntegerField()  # 创建整型的字段
    
8、ORM记录操作语法
    1、取记录
        1.all取全部(列表)
        data = 类名.objects.all()  # 取到类的所有对象,也就是取到数据库中某个表的所有记录,返回一个列表,列表每个元素就是每一条记录
        data[0]                   # 代表第一个对象,对象对应着表中的第一条记录
        data[0].id                # 取第一个对象的id值,也就是取表中的第一条记录的id字段的值
        
        2.filter筛选(列表)[筛选出所有满足条件的对象组合成一个列表]
            filter筛选的结果是一个列表,即ret是列表,ret[0]才是筛选出来的对象,ret[0].id是这个对象的属性值,即记录的字段值
            ret = 类名.objects.filter(id=1) 
            
        3.get筛选(对象)[get只能得到一个对象,即使满足条件的不止一个,get也只能拿到第一个满足条件的对象]
            get筛选的结果是一个对象,即ret是对象
            ret = 类名.objects.get(id=1)
        
    2、新增记录
         # 把数据添加到数据库中
        类名.objects.create(类的属性(字段)=新的值)
        
    3、删除记录
        类名.objects.filter(id=1).delete()  # 筛选出id=1的对象(记录),然后在数据库中把它删除
        类名.objects.get(id=1).delete()
        
    4、修改记录
        1.基于对象的修改
      obj = 类名.objects.get(id=1)
          obj.name = ‘新的值‘     # 此时只是在python中修改了属性的值
          obj.save()             # 把改动提交到数据库
      get只能找一个对象,如果找不到或者找到的对象多于一个,会报错
          
         2.基于QuerySet的update修改
           类名.objects.filter(条件).update(字段=‘新值‘)
       如果filter找到的对象有多个,那么update就是批量更新这些对象
        
        
9、HTML中的特殊符号(模板语言)
    1、用传进来的参数替换msg
        {{ msg }}
    
    2、for循环
    {% for item in iterable %}
    内容
    {% endfor %}
    
    例如:
    {% for i in list1 %}
        <tr>
            <td>{{ forloop.counter }}</td>   // forloop代表for循环,forloop.counter代表循环到第几次,相当于序号
            <td>{{ i }}</td>
        </tr>
    {% endfor %}
  3、for empty  如果循环的对象内容为空,则执行empty的语句
    {% for item in iterable %}
      内容1
    {% empty %}
      内容2
    {% endfor %}
    例如:
    {% for book in author.book.all %}
        book.title
    {% empty %}
      暂无作品
    {% endfor %}
    4、if判断
    {% if 条件 %}
        内容1
    {% else %}
        内容2
    {% endif %}
    
10、request
    1、request.POST
    通过POST方法提交给服务器的数据都会存在request.POST里面,request.POST是一个类似于字典的类型,
    取值方法跟字典一样,可以根据键去取值,也可以通过get方法,例如:
    request.POST["name"]  # 拿到键为name的数据
    request.POST.get("name",None)  # 拿到键为name的数据,若这个数据不存在,则返回None
   request.POST.getlist(‘name‘)  # 当表单提交的数据是一个列表(多选的checkbox和select的提交),需要使用getlist获取这个列表
    
    2、request.GET
    通过GET方法提交给服务器的数据都会存在request.GET里面,request.GET是一个类似于字典的类型,
    取值方法跟字典一样,可以根据键去取值,也可以通过get方法,request.GET是从URL中取参数,例如:
    request.GET["id"]  # 拿到URL中参数为id的数据
    request.GET.get("id",None)  # 拿到URL中参数为id的数据,若这个参数不存在,则返回None
  注意:POST请求的URL中也是可以带参数的
    3、request.method
    request.method就是获取客户端提交数据的方式(POST、GET等)
    
    
        
二、 图书管理系统
1、 表结构
    0. 用户表
    1. 出版社
    2. 书籍
    3. 作者表
    4. 作者和书籍的关系表
    
2、用户表的创建
# 用户表
class Userinfo(models.Model):
    id = models.AutoField(primary_key=True)
    email = models.CharField(max_length=20)
    password = models.CharField(max_length=20)    
    
    
3、 出版社的增删改查
# 出版社表
class Publisher(models.Model):
    id = models.AutoField(primary_key=True)
    name = models.CharField(max_length=20)
    1. 查
        1. ORM: Publisher.objects.all()   --> 查询所有的出版社数据
        2. HTML中写for循环(模板语言)
            {% for i in [..., ...] %}
            {% endfor %}
    2. 增
        1. ORM创建数据
            Publisher.objects.create(name=‘新出版社名称‘)
    3. 删
        1. HTTP中URL添加参数
            /delete_publisher/?id=1
        2. 如何在Django中获取URL中的参数
            request.GET            --> 一个大字典
            request.GET.get(‘id‘)  --> 取值
        3. ORM中删除操作
            Publisher.objects.filter(id=1).delete()
    4. 改
        1. ORM修改
            obj.name = ‘新出版社名称‘
            obj.save()             --> 把改动提交到数据库
            
4、 书籍的增删改查
# 书籍表
class Book(models.Model):
    id = models.AutoField(primary_key=True)
    title = models.CharField(max_length=20)
    publisher = models.ForeignKey(to=‘Publisher‘)
    0. ORM中定义外键
        models.ForeignKey(to=‘外键关联的类名‘)
        注意事项:
            ORM在数据库中会给外键字段自动加_id
            
    1. 查询
        book_obj.publisher       --> 书籍关联的出版社对象
        book_obj.publisher_id    --> 书籍关联的出版社id(数据库中真正保存的那一列的值)
    2. 删除
        Book.objects.filter(id=1).delete()
        Book.objects.get(id=1).delete()
        
    3. 添加
        1. 添加页面把所有的出版社数据展示成select标签
        2. 模态框添加,区别于跳转到新页面添加!!!
        
        3. 添加(注意参数!!!)
          1. Book.objects.create(title=new_title, publisher=Publisher.objects.get(id=publisher_id)) # publisher是ORM帮我们创建的指向外键关联的表的对象
          2. Book.objects.create(title=new_title, publisher_id=publisher_id)  # publisher_id是一个在数据库中具体存放的值
    4. 编辑
        1. 模板语言 if 判断
            {% if publisher == book.publisher %}
                <option selected value="{{ publisher.id }}">{{ publisher.name }}</option>
            {% else %}
                <option value="{{ publisher.id }}">{{ publisher.name }}</option>
            {% endif %}
        2. 注意.save()            
        
5、作者表的增删改查
# 作者表(两张表要实现多对多的关系,需要借助第三张表才能实现)
class Author(models.Model):
    id = models.AutoField(primary_key=True)
    name = models.CharField(max_length=16)  # 作者名称
    age = models.IntegerField()  # 年龄
    book = models.ManyToManyField(to=‘Book‘)  # ORM帮我们自动创建的第三张表(用于多对多查询)
注意:book = models.ManyToManyField(to=‘Book‘)相当于创建了下面的第三张表,用来关联作者和书籍多对多的关系
class Author_Book(models.Model):
    id = models.AutoField(primary_key=True)
    author = models.ForeignKey(to=‘Author‘)
    book = models.ForeignKey(to=‘Book‘)
1. ORM多对多语法
    1. book = models.ManyToManyField(to=‘Book‘)
    2. 优势
        1. 帮我们创建第三张关系表
        2. 提供了很多方便的管理方法
            1. author_obj.book.all()               --> 查询作者关联的所有书籍
            2. author_obj.book.add(id1,id2)        --> 给作者添加关联书籍信息
            3. author_obj.book.set([id1, di2,...]) --> 给作者设置关联书籍信息
                        
2. 作者表的增删改查
    1. 查
        1. author_obj.book.all()   # ORM会自动帮我们实现连表查询,找出作者对应的所有信息
        2. 在Django的模板语言(HTML)中,方法不需要加括号
    2. 增
        1. author_obj.book.add(*[])  # ORM会自动帮我们实现连表查询,然后实现第三张表的增加
    3. 删除
        1. author_obj.delete()  # Django1.x的版本外键默认设置了级联操作,在作者表删除作者,第三张表也会自动删除对应的记录
        2. 补充Django2.0以上的版本
            外键需要手动设置级联操作 on_delete=models.CASCADE
            多对多需要手动设置级联操作 db_constraint=True
    4. 修改
        1. author_obj.book.set([])  # ORM会自动帮我们实现连表查询,然后实现第三张表的修改
            
            
三、Django小结
1、 新建Django项目的步骤
    1. 创建项目和创建APP
    2. 配置settings.py
        1. 检查Templates文件夹是否配置好
        2. 配置静态文件相关
            1. STATIC_URL = ‘/static/‘   --> 默认配好的
            2. STATICFILES_DIRS = [
                   os.path.join(BASE_DIR, ‘static‘),   --> 自己在项目目录下新建一个存放静态文件的文件夹:static
               ]
        3. 注释掉csrf相关的那一行
        4. 配置好数据库的连接信息
        DATABASES = {
            ‘default‘: {
                ‘ENGINE‘: ‘django.db.backends.mysql‘,  
                ...
            }
        }
      然后去和settings同级的__init__.py下:
        import pymysql
        pymysql.install_as_MySQLdb()
        5. 配置好app的信息
        INSTALLED_APPS = [
                ...
                ‘自己的app‘       --> 先创建APP再注册APP
           ]
    
2、 Django中知识点
    1. request                   --> 所有跟请求相关的数据都封装到这个对象
        1. request.method        --> 请求方法的全大写(GET/POST/...)
        2. request.GET           --> 获取URL中的参数(类似字典),POST请求的URL也可以带参数
            request.GET[‘key‘]
            request.GET.get(‘key‘, None)
        3. request.POST          --> 获取POST请求中携带的参数(类似字典)
    2. 基础的三个方法
        1. HttpResponse          --> 返回字符串
        2. render                --> 返回页面
            1. render(request, ‘xx.html‘)
            2. render(request, ‘xx.html‘, {‘key‘: value})
        3. redirect                --> 重定向
            1. redirect(‘/publisher/‘)                --> 重定向到当前项目的其他页面
            2. redirect(‘https://www.baidu.com‘)      --> 重定向到其他页面
四、Django流程图
