### Django
#### Django 数据库操作
##### Django ORM 单表操作
+ Django 可以通过开启命令行模式对模型 (models) 进行操作 : `python manage.py shell`
+ 操作方法
1. 增加操作
1. `类名.objects.create(属性名称=xxx)` : create 方法增加数据
2. `save()` : save 方法上传修改
3. 实例
```
obj = models.类()
obj.属性名 = "xxx"
...
obj.save()
```
2. 删除操作
1. 使用 delate 方法
1. 方法一 : `类名.objects.get("xxx").delete()`
2. 方法二 : `类名.objects.filter("xxx").delete()`
3. 修改操作
1. 使用 update 方法 (不能用 get 方法) : `类名.objects.filter("xxx").update(name="xxx")`
2. 使用 save 方法
3. 实例
```
obj = 类名.objects.get("xxx")
obj.name = "xxx"
...
obj.save()
```
4. 查询操作
1. get 方法 : 返回一个与给定筛选条件相匹配的对象
+ 返回结果有且只有一个,如果有多个符合筛选条件的对象或者没有符合筛选条件的 **报错**
+ 返回的是具体某个模型类的**对象**,而不是 QuerySet 列表对象
2. filter 方法 : 返回包含了与所给筛选条件相匹配的对象
+ 返回 QuerySet 列表对象.获取每个对象时,通过索引或便利
+ 可以传入多个关键字,底层的 sql 使用 and 来连接多个条件
3. all 方法 : 返回 所有 QuerySet 列表对象.获取具体每个对象时 通过索引或者遍历
4. order_by 方法 : 对查询结果排序
1. 正向排序
```python
StoreUser.objects.order_by("id")
```
2. 反向排序,在字段前添加 "-"
```python
StoreUser.objects.order_by("-id")
```
5. first 方法 : 返回第一条记录,返回具体的某个模型类对象 (object),而不是 QuerySet 列表对象
6. last 方法 : 返回最后一条记录,返回具体的某个模型类对象 (object),而不是 QuerySet 列表对象
5. 双下划线查询
| 条件 | 描述 | 举例 |
| -------------- | -------------------------------------------- | ---------------------------------------------------- |
| `__gt` | 大于 | `StoreUser.objects.filter(id__gt=4)` <==> `id > 4` |
| `__lt` | 小于 | `StoreUser.objects.filter(id__lt=4)` <==> `id < 4` |
| `__gte` | 大于等于 | `StoreUser.objects.filter(id__gte=4)` <==> `id >= 4` |
| `__lte` | 小于等于 | `StoreUser.objects.filter(id__lte=4)` <==> `id <= 4` |
| `__contains` | 模糊查询,相当于 SQL 语句中的 like(%keyword%) | `StoreUser.objects.filter(phone__contains="135")` |
| `__in` | 判断在范围 | `StoreUser.objects.filter(id__in=[1, 2, 3])` |
| `__isnull` | 判断为空 | `StoreUser.objects.filter(phone__isnull=Flase)` |
| `__startswith` | 获取指定内容开头的记录 | `StoreUser.objects.filter(phone__startswith="13")` |
6. 聚合查询 : MySQL 中的 max、min、sum、avg、count
+ 导包 : `from django.db.models import Sun, Avg, Max, Min, Count`
+ 依赖 : aggregate 是 Django ORM 中的终止语句
7. 分组查询 (annotate())
+ 按照年龄和性别统计用户个数
```
StoreUser.objects.all().values('age').annotate(count('age'))
StoreUser.objects.all().values('gender').annotate(count('gender'))
```
8. F 查询 : 在查询中, F() 的实例引用一个模型字段.在查询过滤器中也可以这样引用,以便比较同一个模型实例中的两个字段 **用于同一用户的不同信息查询、比较**
+ 引入 F 查询 : `from django.db.models import F`
+ F 查询 年龄 大于 会员等级的用户
```
from django.db.models import F
result = StoreUser.objects.filter(age__gt = F('level')).all()
```
9. Q 查询 : filter() 查询是 并联查询,如果需要使用 or、and、not 需要使用 Q 对象
+ 引入 Q 查询 : `from django.db.models import Q`
+ `|` : 或 or
+ `&` : 且 and
+ `~` : 非 not
+ 案例
1. 查询所有 19 岁的男生
```
StoreUser.objects.filter(age = 19, gender='男')
```
2. 查询所有 19 岁的用户 或男用户
```
StoreUser.object.filter(Q(age=19) | Q(gender='男')).all()
```
3. 查询所有不是 19 岁的员工
```
StoreUser.objects.filter(~Q(age=19)).all()
```
10. Djamgo 分页 : Django 本身携带分页函数,可以自动分页,但是也有限制查的方法,使用索引
```
StoreUser.objects.filter(~Q(age=19))[10]
```
##### Django 关系操作
1. 一对一 (OneToOneField)
1. `models.OneToField()` 参数
| 字段参数 | 描述 |
| --------------------- | ------------------------------------------------------------ |
| `to=关联表` | 设置要关联的表 |
| `to_field=关联字段名` | 设置要关联的字段 |
| `on_delete=处理办法` | 如果删除关联表之后的处理办法
1. `models.CASCADE` : 级联删除,删除关联表后删除此表
2. `models.DO_NOTGING` : 不做处理 |
2. 卖家与店铺一对一
1. 实例
````python
class StoreUser(models.Model):
...
class Store(models.Model):
...
store_user = models.OneToOneField(to=StoreUser, on_delete=models.CASCADE)
````
2. 增加店铺
```python
from Store.models import Store
store = Store()
store.store_name = "早餐店"
store.store_description = "包子"
store.store_logo = "img/1.png"
store.store_address = "北京"
store.store_user = StoreUser.objects.get(id=1)
```
3. 映射查询
1. 查询张三的店铺, 从 StoreUser 查 Store
```python
zhangsan = StoreUser.objects.filter(username="张三")
print(zhangsan.store.store_name)
```
2. 查询早餐店主人, 从 Store 查 StoreUser
```python
store = Store.objects.get(id=1)
print(store.store_name.nick_name)
```
2. 一对多 (ForeignKey)
1. `models.ForeignKey()`
2. 商品和店铺一对多
1. 实例
```python
class GoodsType(models.Model):
t_name = models.CharField(max_length=32)
class Goods(models.Model):
g_name = models.CharField(max_length=32)
g_price = models.FloatField()
goods_type = models.ForeignKey(to=GoodsType, on_delete=models.CASCADE)
```
2. 添加商品并关联商品类型
```python
goods = Goods()
goods.g_name = "苹果"
goods.g_price = 12.3
goods.goods_type = GoodsType.objects.get(id=1)
goods.save()
```
3. 映射查询
1. 查询物品类型, 从 Goods 表查 GoodsType 表
```python
goods = goods.objects.get(id=1)
print(goods.goods_type.t_name)
```
2. 查询商品类型对应商品,从 GoodsType 表查 Goods 表 (先获取类型,在获取 `类型名.小写关联表名_set.all()`)
```python
goods_type = GoodsType.objects.get(id=1)
# 获取该类型所有对应商品
print(goods_type.goods_set.all())
```
3. 多对多 (ManyToManyField)
1. `models.ManyToManyField()`
2. 商品类型和店铺多对多 (一个店铺有多种类型的商品,一个商品类型在多个店铺售卖)
1. 实例
```python
class Store(models.Model):
...
store_user = models.OneToOneField(to=StoreUser, on_delete=models.CASCADE)
class GoodsType(models.Model):
t_name = models.CharField(max_length=32)
t_store = models.ManyToManyField(to=Store)
```
2. 添加类型
```python
goods_type = GoodsType()
goods_type.t_name = "烧烤"
goods_type.save()
```
3. 类型关联店铺
```python
goods_type = GoodsType.object.get(id=1)
goods_type.t_store.add(Store.object.get(id=1))
goods_type.save()
```
4. 映射查询
1. 查询店铺对应类型, 从 Store 表 查 GoodsType 表
```python
store = Store.objects.get(id=1)
print(store.goodstype_set.all()) # 获取的是可迭代数据
for one in store.goodstype_set.all():
print(one.t_name)
```
2. 查询类型对应店铺, 从 Goods.Type 表 查 Store 表
```python
goods_type = GoodsType.objects.get(id=2)
store = goods_type.t_store.all()
for one in store:
print(one.store_name)
```
#### MVC 和 MVT 架构模式
##### MVC 架构模式
+ MVC (Model View Controller) : 分为三个基本部分 : 物理 Model、视图 View 和 控制器 Controller
+ M : Model (模型),代表数据存储层,和数据库进行交互
+ V : View (视图),产生 HTML 页面,代表系统中选择显示什么和怎么显示
+ C : Controller (控制器),接受请求,进行处理,与 M、V 进行交互,返回响应
##### MVT 架构模式
+ MVT (Model View Templates) : Django 框架分为三部分 : Model 模型、Template 模板、View 视图
+ Model (模型) : 负责业务对象与数据库的对象 (ORM)
+ View (视图) : 负责业务逻辑,并在适当的时候调用 Model 和 Templates
+ Templates (模板) : 负责把页面展示给用户
#### Django Form 请求
##### Django 请求
1. 常见的请求方式
1. get : 默认请求方式,请求数据以明文形式存储在路由,get的格式是以 ? 开头,键值对形式,以&分隔每个键值对,常用于向服务器获取资源
2. post : 请求数据隐藏发送,常用于向服务器提交资源
2. 请求对象
+ 视图函数中 request 是传递导视图的请求对象,包含请求的所有信息
+ request 对象类型是 "django.http.HttpRequest"
+ 常用属性
| 常用属性及常用位置 | 描述 |
| ------------------------------ | ----------------------------------- |
| `request.GET`(前端搜索功能) | 获取 get 请求数据的方法 |
| `request.POST`(后台注册) | 获取 post 请求数据方法 |
| `request.FILES`(后台注册) | 获取文件上传请求数据的方法 |
| `request.method`(后台注册) | 获取请求的方法 |
| `request.META` | 获取请求的详细参数 |
| `request.META.OS` | 获取请求端系统 |
| `request.META.HTTP_USER_AGENT` | 获取用户请求头,返回请求的浏览器版本 |
| `request.META.HTTP_HOST` | 获取请求的主机 |
| `request.META.HTTP_REFERER` | 获取请求的来源 |
##### Django 表单
1. HTML 表单 form
| 属性 | 说明 |
| ------------- | -------------------------------- |
| `action=""` | 提交的地址,默认为当前路由 |
| `method=""` | 提交的方法,默认是 get |
| `name=""` | 用来做传参的标识 |
| `type=submit` | 会自动提交当前表单数据到指定路由 |
2. 后端处理
+ CSRF 中间件 : 在 Django 1.4 版本之后 CSRF 在 setting 中默认开启,如果不开启会发生 CSRF 错误
```python
MIDDLEWARE = [
'django.middleware.security.SecurityMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.common.CommonMiddleware',
'django.middleware.csrf.CsrfViewMiddleware', # CSRF 校验
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
]
```
+ CSRF 跨站请求伪造 : 利用当前浏览器还在生效的 cookie 对指定网站进行操作
+ **Django 的 CSRF 验证使用**
1. 在 form 表单内部第一行, 插入 CSRF 校验, 使用 `\{% csrf_token %\}`
```html