diff --git "a/\347\254\254\344\272\214\346\234\237\350\256\255\347\273\203\350\220\245/4\347\217\255/4\347\217\255_LiPing/\347\254\254\345\215\201\345\233\233\345\221\250/.keep" "b/\347\254\254\344\272\214\346\234\237\350\256\255\347\273\203\350\220\245/4\347\217\255/4\347\217\255_LiPing/\347\254\254\345\215\201\345\233\233\345\221\250/.keep" new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git "a/\347\254\254\344\272\214\346\234\237\350\256\255\347\273\203\350\220\245/4\347\217\255/4\347\217\255_LiPing/\347\254\254\345\215\201\345\233\233\345\221\250/\347\254\254\344\270\200\350\212\202.md" "b/\347\254\254\344\272\214\346\234\237\350\256\255\347\273\203\350\220\245/4\347\217\255/4\347\217\255_LiPing/\347\254\254\345\215\201\345\233\233\345\221\250/\347\254\254\344\270\200\350\212\202.md" new file mode 100644 index 0000000000000000000000000000000000000000..17ffa5c3f9e6c16e6425e5c3efb0f940b646f23c --- /dev/null +++ "b/\347\254\254\344\272\214\346\234\237\350\256\255\347\273\203\350\220\245/4\347\217\255/4\347\217\255_LiPing/\347\254\254\345\215\201\345\233\233\345\221\250/\347\254\254\344\270\200\350\212\202.md" @@ -0,0 +1,135 @@ +# 第十四周-第一节课 + +## 字段类型 + +> 有限使用, 尽量使用和数据库一致的数据类型 + +- `BooleanField` + + 代表true或者false, 也就是代表1和0; + +- `IntegerField` + +- `BigIntField` + +- `FloatField` + +- `DecimalField` + + ------ + +- `CharField` + + ``` + 在mysql中对应的就是varchar, 所以必须指定长度 + name = models.CharField(max_length=200) + ``` + +- `TextField` + + > 遇到大的文本和图片, 文件. 推荐做法是存当前的URI或者URL, 然后通过路径从静态资源服务器, 文档数据库或者云服务器中获取该文件 + +------ + +- `DateField` + +- `DateTimeField` + +- `AutoField` + + 如果没有指定主键, 当前模型会自动将一个自增id的`IntegerField`做为主键. + +- `ImageField` + +- `EmailField` + + 当前django提供用来做特殊约束和校验的字段. + +- `UUIDField` + + > 一般来说, uuid会用作当前数据表的主键 + +## 字段选项/约束 + +- `primary_key` + + 将当前字段设置为主键 + + ``` + id = models.AutoField(max_length=191, primary_key=True) + ``` + +- `null` + + 默认为False, 如果为True, 当前字段可以为NULL. + +- `blank` + + 代表空白字符`""`, 默认为False, 如果是True, 当前字段允许为空 + + ``` + password = models.CharField(max_length=200, blank=False) + ``` + +- `unique` + + 默认为False, 如果为True, 重复记录会报错 + +- `default` + + 默认值 + +- 时间类型字段 + + - auto_now_add + + ``` + create_time = models.DateTimeField(auto_now_add=True) + ``` + + - auto_now + + ``` + update_time = models.DateTimeField(auto_now=True) + ``` + +## 创建测试应用myblog + +``` +class Person(models.Model): + name = models.CharField(max_length=200, primary_key=True) + email = models.EmailField() + update_time = models.DateTimeField(auto_now=True) + create_time = models.DateTimeField(auto_now_add=True) + + null_test = models.CharField(max_length=200, null=True) + blank_test = models.CharField(max_length=200, blank=True) +``` + +## 调试 + +- 修改`manage.py`进行debug调试 + + ``` + print(sys.argv) + # sys.argv = ['manage.py', 'migrate'] + execute_from_command_line(sys.argv) + ``` + +- 修复`migrations` + + 执行`python manage.py migrate`命令其实是按顺序执行**未同步**的migrations. + + - 更改`migrations`中的文件解决问题 + + - 删除 + + ``` + migrations + ``` + + 文件推倒重来 + + - `django`会在数据表`django_migrations`中创建同步记录 + - 删除对应的同步记录 + - 如果有创建表的记录, 需要删除表 \ No newline at end of file diff --git "a/\347\254\254\344\272\214\346\234\237\350\256\255\347\273\203\350\220\245/4\347\217\255/4\347\217\255_LiPing/\347\254\254\345\215\201\345\233\233\345\221\250/\347\254\254\344\270\211\350\212\202.md" "b/\347\254\254\344\272\214\346\234\237\350\256\255\347\273\203\350\220\245/4\347\217\255/4\347\217\255_LiPing/\347\254\254\345\215\201\345\233\233\345\221\250/\347\254\254\344\270\211\350\212\202.md" new file mode 100644 index 0000000000000000000000000000000000000000..ef21d4afe67c5352e14097781eeb72ca7d3bd359 --- /dev/null +++ "b/\347\254\254\344\272\214\346\234\237\350\256\255\347\273\203\350\220\245/4\347\217\255/4\347\217\255_LiPing/\347\254\254\345\215\201\345\233\233\345\221\250/\347\254\254\344\270\211\350\212\202.md" @@ -0,0 +1,325 @@ +# 第十四周-第三节课 + +## QuerySet + +- Create + + ``` + import os + import random + import django + + + def create_reader_test(): + for i in range(100): + reader = Reader( + name=f"name_{i}", + password=f"password_{i}", + email="email_{i}@163.com", + whether_vip=random.choice([True, False]) + ) + reader.save() + + + if __name__ == "__main__": + # 设置环境变量 + os.environ.setdefault("DJANGO_SETTINGS_MODULE", "mysite.settings") + django.setup() + from myblog.models import Reader + create_reader_test() + ``` + + - 入库前对当前字段进行检验 + + ``` + # 通过clean_fields主动对字段进行自检 + # 如果当前字段可以为None, 则需要将当前字段置入exclude中 + reader.clean_fields(exclude=['password']) + ``` + +- Retrieve + + Django的`orm`是一条执行链 + + - all + + 获取所有记录, 没事不要乱用 + + - get + + 获取一条记录, 如果有多条记录则会报错 + + ``` + item = Writer.objects.get(id=1) + item = Writer.objects.get(name="name_0") + ``` + + - filter + + > 类似sql中的where + + - 比较运算 + + - `=` + + ``` + query_set = Writer.objects.filter(name="name_0") + ``` + + - `>=` + + 通过`字段名__gte`的形式 + + ``` + query_set = Writer.objects.filter(id__gte=100) + ``` + + - `>` + + ``` + query_set = Writer.objects.filter(id__gt=100) + ``` + + - `<=` + + ``` + query_set = Writer.objects.filter(id__lte=100) + ``` + + - `<` + + ``` + query_set = Writer.objects.filter(id__lt=100) + ``` + + - 模拟匹配 + + - `__startswith` + + ``` + query_set = Writer.objects.filter(name__startswith="name") + ``` + + - `__endswith` + + ``` + query_set = Writer.objects.filter(name__endswith="name") + ``` + + - `__icontains` + + ``` + query_set = Writer.objects.filter(name__icontains="23") + ``` + + - 逻辑取反 + + ``` + query_set = Writer.objects.exclude(name__icontains="23") + ``` + + - Limit + + `sql`中的limit在django中其实就是对`QuerySet`对象进行切片. + + ``` + # 先返回all产生的所有记录集合, 然后进行切片 + query_set = Writer.objects.all()[0: 10] + ``` + + - 排序 + + ``` + query_set = Writer.objects.all().order_by("name") + + # 切片操作后调用会报错 + query_set = Writer.objects.all()[0: 10].order_by("name") + ``` + +- Update + + 对模型对象重新赋值后, 调用`save()` + +- Delete + + - 删除一条记录 + + 模型对象调用`delete()` + + ``` + item = Writer.objects.get(name="44_modify") + item.delete() + ``` + + - 删除多条记录 + + QuerySet对象调用`delete()` + + > 如果要清空表, 如果表非常大, 那么特别浪费时间. + > + > 正确做法还是通过客户端truncate table来清空表 + + ``` + query_set = Writer.objects.filter(id__gt=99).delete() + ``` + +## 使用原始SQL + +使用`Raw`语句执行`sql`语句, django同样会帮我们转换为模型对象 + +``` +raw_query_set = Writer.objects.raw(f"SELECT * FROM {Writer._meta.db_table} where id > 10") + for item in raw_query_set: + print(item) +``` + +## 模型继承 + +- 普通继承 + + ``` + * 继承后要重写内嵌类Meta + class Reader(Person): + whether_vip = models.BooleanField(default=False) + + class Meta: + pass + ``` + +- 多重继承 + + > 如果当前模型对象没有指定主键, 那么django会自动帮我们建立一个名为id的主键字段 + > + > 可以通过重新赋值id字段来解决id冲突 + > + > *通过抽象类来作为继承基类, 实现类来实现内部的功能 + + ``` + class Student(models.Model): + student_id = models.AutoField(primary_key=True) + name = models.CharField(max_length=100) + + + class Book(models.Model): + book_id = models.AutoField(primary_key=True) + book_name = models.CharField(max_length=100) + + + class Borrow(Student, Book): + pass + ``` + +## 实例方法 + +- 自定义输出 + + ``` + def __str__(self): + return f"Writer<{self.id}, {self.name}>" + ``` + +- 刷新 + + ``` + def refresh_from_db(self, using=None, fields=None): + pass + + # 指定更新字段 + item.refresh_from_db(fields=['name']) + ``` + +- 字段验证 + + ``` + def clean_fields(self, exclude=None): + pass + ``` + +- 获取最新记录 + + ``` + # 需要在meta中设置get_latest_by = ['id'] + item = Writer.objects.latest() + ``` + +## 高级 + +- 指定数据库 + + 在`settings`中配置目标数据库的连接 + + ``` + DATABASES = { + 'default': { + 'ENGINE': 'django.db.backends.mysql', + 'NAME': 'polls', + 'USER': 'root', + 'PASSWORD': 'qwe369', + 'HOST': '127.0.0.1', + 'PORT': '3306' + }, + 'myblog': { + 'ENGINE': 'django.db.backends.mysql', + 'NAME': 'myblog', + 'USER': 'root', + 'PASSWORD': 'qwe369', + 'HOST': '127.0.0.1', + 'PORT': '3306' + } + } + ``` + + `orm`通过`using`参数指定数据库 + + ``` + def create_writer_test(): + for i in range(1): + writer = Writer( + name=f"name_myblog_{i}", + password=f"password_{i}", + email=f"email_{i}@163.com", + _type="签约作者" + ) + writer.clean_fields(exclude=['email']) + writer.save(using="myblog") + ``` + +- 事务 + + - 基于HTTP请求的事务 + + 每个请求封装在一个事务中, 如果**视图**出现异常, 那么模型层的提交就会回滚 + + ``` + from django.db import transaction + from django.utils import timezone + + + def index(request): + """ + :param request: 请求对象 + :return: + """ + latest_question_list = Question.objects.order_by('-pub_date')[:5] + context = { + 'latest_question_list': latest_question_list + } + q = Question( + question_text='现在几点', + pub_date=timezone.now() + ) + q.save() + return render(request, 'polls/index.html', context) + ``` + + - 基于视图具体逻辑 + + ``` + def viewfunc(request): + # This code executes in autocommit mode (Django's default). + do_stuff() + + with transaction.atomic(): + # This code executes inside a transaction. + do_more_stuff() + ``` \ No newline at end of file diff --git "a/\347\254\254\344\272\214\346\234\237\350\256\255\347\273\203\350\220\245/4\347\217\255/4\347\217\255_LiPing/\347\254\254\345\215\201\345\233\233\345\221\250/\347\254\254\344\272\214\350\212\202.md" "b/\347\254\254\344\272\214\346\234\237\350\256\255\347\273\203\350\220\245/4\347\217\255/4\347\217\255_LiPing/\347\254\254\345\215\201\345\233\233\345\221\250/\347\254\254\344\272\214\350\212\202.md" new file mode 100644 index 0000000000000000000000000000000000000000..64384defc7f2061564034deb164c6484938ce24e --- /dev/null +++ "b/\347\254\254\344\272\214\346\234\237\350\256\255\347\273\203\350\220\245/4\347\217\255/4\347\217\255_LiPing/\347\254\254\345\215\201\345\233\233\345\221\250/\347\254\254\344\272\214\350\212\202.md" @@ -0,0 +1,164 @@ +# 第十四周-第二节课 + +## 内嵌类Meta + +通过一个内嵌类Meta来定义元数据, 元数据又被称为中介数据, 用于描述数据得数据. + +> 简单地讲, Meta就是通过属性来描述model对象, 为其提供额外得功能. + +- `abstract` + + 将当前模型类转换成抽象类, 当进行migrate的时候会被忽略. + + > 因为migrate是对实体表进行修改, 而抽象是一个虚的概念, 所以不存在实体. + +- `app_label` + + 指定当前model从属于哪个已经注册的应用 + + > 使用场景一般为应用只编写视图层来处理业务逻辑. 模型层统一由一个models模块来管理, 所以要区分所属应用 + +- `db_table` + + 自定义表名, 如果不指定表名则默认为`应用名_模型名` + + > 第一种使用情况为目标表已经存在. + > + > 第二种为开发没有管理表的权限, 需要dba建表再开发. + > + > 第三种为规范数据库的表名命名, 而不是使用django默认的命名规范. + +- `managed` + + 默认为True, 如果为False, 当前migrate会忽略该模型. + + - 虽然设置了managed为False, 但是如果没有主键的化, 依然会自动创建主键. + + > 很多公司都会由专人DBA来管理数据库. + > + > 独立开发流程: 创建模型-> migrate + > + > 公司合作开发流程: dba建表->创建模型 + +- `ordering` + + 设置排序字段, 默认排序规则为升序 + + - `-`表示降序 + + ``` + ordering = ['-order_date'] + ordering = ['-pub_date', 'author'] + ``` + + - `?`表示随机的意思 + + ``` + ordering = ['?'] + ``` + +- `get_lastest_by` + + 设置获取最后一条记录的排序规则 + +- `indexes` + + 设置索引 + + ``` + class Meta: + indexes = [ + models.Index(fields=['last_name', 'first_name']), + models.Index(fields=['first_name'], name='first_name_idx'), + ] + ``` + +- `unique_together` + + 多字段唯一性约束 + + ``` + unique_together = ("driver", "restaurant") + ``` + +## 模型继承 + +- 普通继承 + + ``` + class Person(models.Model): + name = models.CharField(max_length=191) + email = models.EmailField() + update_time = models.DateTimeField(auto_now=True) + create_time = models.DateTimeField(auto_now_add=True) + + null_test = models.CharField(max_length=200, null=True) + blank_test = models.CharField(max_length=200, blank=True) + + class Meta: + abstract = True + + + class Reader(Person): + whether_vip = models.BooleanField(default=False) + ``` + +- 多重继承 + + 如果当前模型对象没有指定主键, 那么django会自动帮我们创建名为id的主键字段. + + 为了解决多重继承产生的id冲突, 你需要覆盖id字段. + + ``` + from django.db import models + + # Create your models here. + class Student(models.Model): + # db_column为数据库中的字段 + student_id = models.AutoField(primary_key=True, db_column="id") + name = models.CharField(max_length=200) + + + class Book(models.Model): + book_id = models.AutoField(primary_key=True, db_column="id") + book_name = models.CharField(max_length=200) + + + class BorrowRecord(Student, Book): + _id = models.AutoField(primary_key=True, db_column="id") + borrow_time = models.DateTimeField(auto_now_add=True) + ``` + +## 实例方法 + +- 获取最新记录 + + ``` + get_lastest_by = ['id'] + item = model.objects.latest() + ``` + +- 自定义输出 + + ``` + def __str__(self): + return f"id:{self.id}, {self.question_text}" + ``` + +- 刷新当前记录 + + ``` + refresh_from_db + ``` + +- 字段验证 + + 比如EmailField调用clean_fields会验证当前格式是否正确 + +- 字段唯一性验证 + + ``` + # 在meta中设置唯一性字段 + unique_together = ['name', 'email'] + reader.validate_unique(exclude=['null_test', 'create_time', 'update_time', 'id']) + ``` \ No newline at end of file