一、model 文件中的类的建立:
对应的是数据库中的每个表,类中有什么字段,表就会对应的生成某个字段,主键id字段会自己生成;
数据库中的文件获取:只能通过模型类.objects来获取,不能通过模型类的实例获取;
对model中的代码进行增删改:先执行python manage.py makemigrations让修改动作保存到记录文件中,然后进行python manage.py migrate 让实际的操作应用到数据库中。
还有隐藏字段:_state 详情见https://www.liujiangblog.com/course/django/95第一章,模型和字段
__str__方法,用于返回实例对象的打印字符串;
get_abosolute_url()方法,返回每个模型实例的相应的访问url;
hash()方法,给模型实例提供唯一的哈希值,一旦生成就不允许修改
字段名:不能用,pass,两个下划线,下划线结尾
二、常用的Filed字段:
BooleanField:布尔类型,默认值时None,表单标签是checkboxinput,如果设置参数null=True,则表现为NullBooleanSelect选择框;
CharField:字符串类型,必须接收一个max_length参数,表单标签是text input;
DateField:日期类型,两个重要参数:(参数互斥,不能共存) auto_now:每当对象被保存时将字段设为当前日期,常用于保存最后修改时间。auto_now_add:每当对象被创建时,设为当前日期,常用于保存创建日期(注意,它是不可修改的)。设置上面两个参数就相当于给field添加了editable=False和blank=True属性。如果想具有修改属性,请用default参数。例子:pub_time = models.DateField(auto_now_add=True),自动添加发布时间。表单标签是DateInput;
DateTimeField:比上一个多了小时,分,秒的显示;
DecimalField:固定精度的十进制小数。相当于Python的Decimal实例,必须提供两个指定的参数!参数max_digits:最大的位数,必须大于或等于小数点位数 。decimal_places:小数点位数,精度。 当localize=False时,表单标签是NumberInput,否则是textInput类型。例子:储存最大不超过999,带有2位小数位精度的数,定义如下:models.DecimalField(..., max_digits=5, decimal_places=2);
EmailField:邮箱类型,默认max_length最大长度254位。使用这个字段的好处是,可以使用Django内置的EmailValidator进行邮箱格式合法性验证;
FileField:上传文件字段(不能设置主键),表单标签是ClearableFileInput标签;class FileField(upload_to=None, max_length=100, **options),upload_to用于设置上传地址的目录和文件名,也可以接收一个回调函数,该函数返回具体的路径字符串。回调函数中包含了instance参数和filename参数;
FilePathField:class FilePathField(path='', match=None, recursive=False, allow_files=True, allow_folders=False, max_length=100, **options);用来保存文件路径信息的字段;
ImageField:ImageField(upload_to=None, height_field=None, width_field=None, max_length=100, **options),同上,需提前安装pillow模块;这两个也需要在配置文件中,配置MEDIA_ROOT(上传文件在服务器的基本路径)和MEDIA_URL(指向上传文件的基本路径);假设你有一个ImageField字段,名叫mug_shot,那么在Django模板的HTML文件中,可以使用{{ object.mug_shot.url/size/name }}来获取该文件。其中的object用你具体的对象名称代替。
IntegerField:整数类型,表单标签是NumberInput或者TextInput;
GenericIPAddressField:class GenericIPAddressField(protocol='both', unpack_ipv4=False, **options),IPV4或者IPV6地址,字符串形式,例如192.0.2.30或者2a02:42fe::4。在HTML中表现为TextInput标签。参数protocol默认值为'both',可选'IPv4'或者'IPv6',表示你的IP地址类型。
TextField:用于储存大量的文本内容,表单标签是textarea;
URLField:一个用于保存URL地址的字符串类型,默认最大长度200;
UUIDField:用于保存通用唯一识别码(Universally Unique Identifier)的字段。注意不要写成default=uuid.uuid4()。
三、关系类型字段
外键要放在'多'的一方,对于关系字段,第一位置参数永远是关系对象,不能是verbose_name;
多对一:ForeignKey
其中on_delete后的参数
● CASCADE:模拟SQL语言中的ON DELETE CASCADE约束,将定义有外键的模型对象同时删除!
● 还有其他的参数,详情见https://www.liujiangblog.com/course/django/96,第一章,关系字段;
其中还有limit_choices_to等其他参数,详情见同上
多对多:ManyToManyField,只能选择一个模型设置该字段
里面有through参数,定义在
class Person(models.Model):
name = models.CharField(max_length=50)
class Group(models.Model):
name = models.CharField(max_length=128)
members = models.ManyToManyField(Person,
through='Membership', ## 自定义中间表
through_fields=('group', 'person'), )
class Membership(models.Model): # 这就是具体的中间表模型
group = models.ForeignKey(Group, on_delete=models.CASCADE)
person = models.ForeignKey(Person, on_delete=models.CASCADE)
inviter = models.ForeignKey(Person,on_delete=models.CASCADE,related_name="membership_invites", )
invite_reason = models.CharField(max_length=64)
定义了一个新的模型,用来保存Person和Group模型的多对多关系,并且同时增加了'邀请人'和'邀请原因'的字段。而且必须显式的指定through_fields参数,用于定义关系。through_fields参数指定从中间表模型Membership中选择哪两个字段,作为关系连接字段。
一对一:OneToOneField
四、创建表的时侯的模型元数据class Meta:
其下面的主要字段:
db_table,指定在数据库中,当前模型生成的数据表的表名;
ordering,排序,加'-'表示降序排列,不加则表示升序排列,可以在其后面再加字段,对什么进行排序;
idexes,接收一个应用在当前模型上的索引列表,models.Index(fields=['last_name', 'first_name']);
verbose_name,设置模型对象的名称。
五、模型的继承
1、想让抽象基类的子模型成为一个抽象基类,那必须显式的在该子模型的Meta中同样声明一个abstract=True;
2、在多表继承中,如不想让子类继承父类的ordering和get_latest_by参数,就必须在子类中显示的指出或重写;
3、声明一个代理模型只需在Meta中proxy的值设为True。
六、model的查询操作
1、创建对象:模型类的实例化构造,然后save( )方法保存;或者 类.objects.create( )方法创建
或者直接在模型类中增加create方法和自定义管理器并在其中添加创建对象的方法;
2、修改对象并保存:在其中千万不要忘记super().save( *args,**kwargs),这行确保了Django源码中关于save方法的代码会依然被执行。只有执行save方法后才会将数据写入数据库。
3、F表达式:entry = Entry.objects.get(name='刘江的博客')
>>> entry.number_of_pingbacks = F('number_of_pingbacks') + 1
>>> entry.save()
Django设计的这个F表达式在获取关联字段值的时候不用先去数据库中取值然后在Python内存里计算,而是直接在数据库中取值和计算,直接更新数据库,不需要在Python中操作,自然就不存在数据竞争和冲突问题了。
4、希望结果是哪个模型的实例,就用哪个,模型去调用;Blog.objects.xxx
5、QuerySet的切片:
Entry.objects.all()[:5] # 返回前5个对象
Entry.objects.all()[5:10] # 返回第6个到第10个对象
注意:不支持负索引!例如 Entry.objects.all()[-1]是不允许的
指定步长的时候,查询操作会立刻在数据库内执行,>>> Entry.objects.all()[:10:2]
6、字段查询:键名__字段=指定的内容
字段有:regex区分大小写的正则表达式匹配,iregex不区分大小写。。。等字段
7、Q对象
可以使用&或者|或~来组合Q对象,分别表示与、或、非逻辑。它将返回一个新的Q对象。
Q(question__startswith='Who')|Q(question__startswith='What')
这相当于:WHERE question LIKE 'Who%' OR question LIKE 'What%'
8、判断基于以下逻辑:
● 同一模型下,主键相等则实例相等
● 主键为None时,和任何实例都不相等
● 实例等于自己本身
● 代理模型的实例等于相同主键的父类实例
● 多表继承时,哪怕主键值相等,实例也不相等
七、不返回QuerySet的API
get() 获取单个对象,注意其查询的对象只能有一个,不然就报错;
create() 创建对象,无需save(),同时创建并且保存对象的方法;
get_or_create() 查询对象,如果没有找到就新建对象,建议只在post请求中这样使用,不然不安全;
update_or_create() 更新对象,如果没有找到就创建对象;
count() 统计对象的个数,永远不会引发异常;
latest() 获取最近的对象,其本质就是先排序,然后获取最前面的那个对象;
earliest() 获取最早的对象,获取最早先的对象;
first() 获取第一个对象,返回结果集的第一个对象,当没有找到好似就返回None;
last() 获取最后一个对象,返回结果集的最后一个对象;
aggregate() 聚合操作,见后面的章节;
exists() 判断queryset中是否有对象,查询其在不在;
update() 更新对象,对指定的字段执行更新操作,并返回匹配行数,
delete() 删除对象
八、注解与聚合
● aggregate: [ˈæɡrɪɡət ] ,聚合。做一些统计方面的工作。返回的是聚合后的数据字典;
● annotate: [ˈænəteɪt],注解。为返回的查询集添加一些额外的数据。返回的依然是查询集。
其中的Avg,Sum,Count,Max,Min等其他的聚合函数。