DjangoWeb应用开发实战笔记
Django模板标签笔记
第六章笔记
django模板引擎
DTL;Django模板语言
Jinja2
{% url %} 引用路由的配置地址,生成相应的路由地址
一般是{% url '命名空间:views,py中的函数'%}
改变了命名空间的话,需要重新跑一便数据库
makemirations
并不是数据库的原因
我知道了,写反了
是{% url 'views,py中的函数:命名空间'%}
常用的内置标签
with标签
{% with %}将上下文重新命名
{% block xxx %}重写父类的模板标签
# total=number无需用空格分开,否则抛出异常
{% with total=number %}
{{ total }}
{% endwith %}
for标签
特殊的变量来获取for标签的循环信息,总之就是获取索引信息
{% if forloop.counter==1 %} # 获取当前循环的索引,从1开始计算;用法通常用if来判断
forloop.counter() # 获取当前的索引,从0开始计算
.revcounter 索引从最大处开始递减,直到索引为1的位置
.revcounter() 索引从最大处开始递减,直到索引为0的位置
.first 当遍历元素第一项为真时候
.last 当遍历元素最后一项为真时候
.parentloop 嵌套的for循环中,获取上一层的For循环
for... empty
如果给定数组为空或无法找到,则for标记可以采用可选子句,该子句的文本将显示:{% empty %}
自定义标签
在项目根目录下新建个文件夹(与manage.py同级,也就是想当个应用),然后把该文件夹name加入到settings中,在该文件夹下兴建个templates文件夹和__init__.py文件,接着在templates文件夹下兴建个xx.py文件
该文件就是要导入的标签
可用{% load xx %}
具体自定义标签流程
#在该文件中,首先导入template模块,从django中,
#然后创建一个模板对象
register = template.Library()
然后定义模板节点类xxx,需要继承template.Node。
class ReversalNode(template.Node):
def __init__(self, value):
self.value = str(value) # 这里的value数据是由下面的do_reversal111函数中传进来的
# 数据反转处理
def render(self, context): # 数据处理渲染的函数名不可随便写
return self.value[::-1]
#在该类中需要实现标签的功能
# 然后在声明并把该模板节点类注册
注册用装饰器
@register.tag(name='') # name可以自定义
#在装饰器下方编写函数
#函数的作用是把用改标签定义的字符串传进来,然后在返回修改后的字符,这里实现的功能是反转字符串
@register.tag(name='reversal1') # 这里定义标签名称,下方就是标签函数的内容
def do_reversal(parse, token):
'''
函数参数parse是解析器对象,当Django运行时,他将所有标签和过滤器进行加载并生成到parse对象
在解析模板文件里面的标签时,Django就会从parse对象查找对应的标签信息
函数参数token时模板文件使用标签时所传递的数据对象,主要包括标签名和数据内容
do_reversal对参数token使用split_contents()方法(Django内置方法)进行取值处理,从中获取数据value,并将value传递给
自定义模板节点类ReversalNode
'''
try:
# tag_name是代表标签名,即reversal
# value是由标签传递的数据
tag_name, value = token.split_contents() # 在index.html中传进来的字符串就是这里的token;
# 然后再把它传给value,再把value传给上面的函数类并返回
except:
raise template.TemplateSyntaxError('syntax')
# 调用自定义的模板节点类
return ReversalNode(value) #ReversalNode类是将value执行字符串反转处理,并生成模板节点对象,用于模板引擎解析HTML语言
这里采用的django内置的玩意:
split_contents()方法取值处理 # 方法按空格分隔字符串,但不会分隔引号包裹的部分。
tips:自定义标签和内置标签的区别在于需要在项目里搭建目录环境,在使用时需要在模板文件导入自定义标签文件。
自定义过滤器
过滤器可同时使用多个,用|分隔开
过滤器还可传入参数,过滤器和参数之间用冒号分隔,且两者之间不能留有空格。之后的参数和冒号之间也不能有空格
开发流程
在项目根目录下新建个文件夹,然后把该文件夹name加入到settings中,在该文件夹下兴建个templates文件夹和__init__.py文件,接着在templates文件夹下兴建个xx.py文件
该文件就是要导入的过滤器
可用{% load xx %}
在该文件中,首先导入template模块,从django中,
然后创建一个模板对象
register = template.Library()
然后申明并定义过滤器
@register.filter(name='xxx') 过滤器的名字,不懈的话默认为下方的函数名
定义过滤器函数
@register.filter(name='replace') # 对函数do_replace()由装饰器@register.filterl处理,并对其进行注册操作
def do_replace(value, agrs):# value代表当前过滤器的模板上下文
oldValue = agrs.split(':')[0] # args代表过滤器器的参数,函数将过滤器agrs以冒号分隔,用于参数value进行字符串替换操作
newValue = agrs.split(':')[1]
return value.replace(oldValue, newValue) # 将处理结果返回
字符串replace用法
srt = 'je kk'
a = srt.replace('je','ss') # replace返回一个对象
print(a) # ss kk
前端页面
<div>替换前:{{ value }}</div>
<br>
<div>替换后:
{{ value | replace1:'Python:Django' }} <!--第一个参数需存在在value中,才会与第二个参数进行替换-->
</div>
一般模板变量(模板上下文)没有匹配到的话并不会报错
就是他发挥作用与否,你很难知道,所以一般写模板变量之前必须确定该变量是否有效,即是否在views.py中定义了,定义了的话是否从数据表中提取的,提取出来的字段是什么类型的,这些都应该清楚
常见过滤器
内置过滤器的源码位置
django/template/defaultfilters.py
注:去掉_
这里是为了让他不显示,这里使用 '&_#124;' 来转义markdown表格中的'|',但包裹着{{}}中却不可以转义
内置过滤器 | 说明 | 使用形式 |
---|---|---|
add | 加法 | {{ value |add:"2" }} |
addslashes | 添加斜杠 | {{ value |addslashes }} |
capfirst | 首字母大写 | {{ value |capfirst}} |
center | 文本居中 | {{ value |center:"15"}} |
cut | 切除字符 | {{ value |cut:"arg" }} |
date | 日期格式化 | {{ value |data:"D d M Y"}} 可用的日期格式字符串,python的datetime模快中有 |
default | value为False或者0时才设置默认值 | { value |default:"nothing" } |
default_if_none | 如果value的意义为None,为其设置默认值 | {{ value |default_if_none:"null"}} |
dictsort | 字典排序,前提value是列表包含的字典,按照字典的关键字属性值排序 | {{ value |dictsort:"name"}} |
dictsortreversed | 字典反向排序前提value是列表包含的字典,按照字典的关键字属性值反序排序 | {{ value |dictsortreversed:"name"}} |
divisibleby | 整除判断,如果value能被arg整除,则返回True | {{ value |divisibleby:"arg" }} |
escape | 转义HTML中的特殊字符,value输出为html元素标签时候 | {{value |escape}} |
escapejs | 转义js代码,替换value中的某些字符,适应js或json格式 | {{value |escapejs}} |
filesizeformat | 文件尺寸人性化显示,如果value为123456789,输出将是117.7 MB。 | {{value |filesizeformat}} |
first | 返回列表中的第一个元素 | {{value |first}} |
floatformat | 浮点数格式化,若无参数默认保持1位,有的话按参数来 | {{value |floatformat:"arg"}} |
force_escape | 强制立刻转义HTML字符串 | {{ body|linebreaks|force_escape }} |
get_digit | 获取数字,从右边开始 | {{ value |get_digit:"2" }} |
iriencode | 转换IRI,转换为url中适应的编码(ASCII) | {{ value |iriencode }} |
join | 字符列表链接,类似于Python的join() | {{ value |join:" // " }} |
json_script | 生成script标签,带json数据,可接收一个参数表示script的Id | {{ value |json_script:"hello-data" }} |
last | 最后一个 | {{ value |last }} |
length | 长度 | {{ value |length }} |
length_is | 长度等于,等于参数则返回true | {{ value|length_is:"4" }} |
linebreaks | 行转换,整个文本被p标签包裹,换行符用\n表示 | {{ value |linebreaks }} |
linebreaksbr | 行转换,换行符用\n表示 | {{ value |linebreaksbr }} |
linenumbers | 显示带行号的文本 | {{ value |linenumbers }} |
ljust | 给定宽度左对齐 | "{{ value |ljust:"10" }} " |
lower | 小写 | {{ value |lower }} |
make_list | 分割成字符列表 | {{ value |make_list }} |
phone2numeric | 电话号码,中的字母转化为等效数字 | {{ value |phone2numeric }} |
pluralize | 复数形式,可指定参数 | {{ num_walruses|pluralize:"es" }} |
pprint | 调试 | 用于调试的过滤器,也就是 pprint.pprint() |
random | 从列表中随机获取 | {{ value |random }} |
rjust | 右对齐给定宽度的值 | "{{ value |rjust:"10" }} " |
safe | 安全确认 | 将字符串标记为安全,不需要转义。 |
safeseq | 列表安全确认,它首先将变量转换为字符串 | {{ some_list|safeseq|join:", " }} |
slice | 切片 | {{ some_list|slice:":2" }} |
slugify | 转换成ASCII | {{ value |slugify }} |
stringformat | 字符串格式化 | {{ value |stringformat:"E" }} |
striptags | 去除HTML中的标签 | {{ value |striptags }} |
time | 时间格式化 | {{ value |time:"H:i" }} |
timesince | 从何时开始,包含用作比较点的日期的变量 | {{ blog_date|timesince:comment_date }} |
timeuntil | 到何时多久,包含用作比较点的日期的变量 | {{ conference_date|timeuntil:from_date }} |
title | 所有单词首字母大写 | {{ value |title }} |
truncatechars | 截断字符 | {{ value |truncatechars:9 }} |
truncatechars_html | 截断字符,但是会保留HTML标记。 | {{ value |truncatechars_html:9 }} |
truncatewords | 截断单词 | 参悟 |
truncatewords_html | 截断单词 | 参悟 |
unordered_list | 无序列表 | 参悟 |
upper | 大写 | 参悟 |
urlencode | 转义url | 参悟 |
urlize | url转成可点击的链接 | 参悟 |
urlizetrunc | urlize的截断方式 | 参悟 |
wordcount | 单词计数 | 参悟 |
wordwrap | 单词包裹 | 参悟 |
yesno | 将True,False和None,映射成字符串‘yes’,‘no’,‘maybe’ | 参悟 |
Jinja2模板引擎的用法
一般是和Django两个模板共存的,在项目所在的settings.py文件夹兴建个jinja2.py文件,然后编写如下函数
from django.contrib.staticfiles.storage import staticfiles_storage
from django.urls import reverse
from jinja2 import Environment
# 将jinja2模版设置到项目环境
def environment(**options):
env = Environment(**options) #jinja2的类Environment实例化
env.globals.update({ # 实例化的对象env用于对接Django的运行环境
'static': staticfiles_storage.url,
'url': reverse,
})
return env
接着就是将该定义的enviroment()函数写道配置文件settings.py中。
在配置属性TEMPLATES中新增Jinja2模板引擎
{
'BACKEND': 'django.template.backends.jinja2.Jinja2', # BACKEND设置Jinja2模板引擎
'DIRS': [
os.path.join(BASE_DIR, 'templates'), # DIRS指向项目的模板文件夹templates
],
'APP_DIRS': True,
'OPTIONS': {
'environment': 'MyDjango.jinja2.environment' # MyDjango为settings.py所在的文件夹
},
},
jinja2区别于django的语法
{{ value['name'] }}<!--dingo内置模板不支持[]提取值-->
jinja2的模板语法
在继承模板标签上和django一样,在他的static函数,url函数和过滤器使用情况来看,他们更象函数,都加了(),static(' '),url(''),replace(' '),过滤器和参数之间并没有用分号连接。
for函数的模板变量也不一样
loop.index 循环的当前迭代(索引从1开始)
loop.index() 循环的当前迭代(索引从0开始)
loop.revindex 循环结束时的迭代次数(索引从1开始)
loop.revindex() 循环结束时的迭代次数(索引从0开始)
loop.first 如果是第一次迭代,就为True
loop.last 如果是最后依次迭代,就为True
xx.length 序列中的项目数,即总循环数
xx.cycle 辅助函数,用于在序列列表之间循环
xx,depth 当前递归循环的深度,从1级开始
xx.depth() 当前递归循环的深度,从0级开始
xx.previtem 上一次迭代中的对象
xx.nextitem 下一次迭代中的对象
xx.changed(value) 若上次迭代的值,与当前迭代的值不同则返回True
常用过滤器的名称也不一样
abs {{value | abs}} 设置数值的绝对值
default {{value | default('new')}} 设置默认值
escape {{value | escape}} 转义字符,转成HTML语法
first {{value | first}} 获取上下文的第一个元素
last {{value | first}} 获取上下文的最后一个元素
length {{value | length}} 获取上下文的长度
join {{value | join('-')}} 功能与python的join语法一致
safe 将上下文转义处理
int 将上下文转换为int类型
float 将上下文转换为float类型
lower 将字符串转化为小写
upper 将字符串转化为大写
replace {{value | replace('a','b')}}字符串的替换
truncate {{value | truncate(9,true)}} 字符串的阶段
striptags 删除字符串中所有的HTML标签
trim 截取字符串前面和后面的空白字符
string 将上下文转换成字符串
wordcount 计算长字符串的单词个数
自定义过滤器
该自定义标签并不需要像django导入模板
jinja2的过滤器并不是写在新创建的文件里,而是写在刚刚定义jinja2的
jinja2.py文件中
具体
定义个函数,该函数名作为过滤器,该函数的逻辑就是过滤器的处理手段,
# 关键字参数的jinja2,默认值,如果有参数,则是其他参数
def myReplace(value, old='Jinja2', new='Django'):
return str(value).replace(old, new)
然后env.filters把过滤器注册到Jinja2引擎
env.filters['myReplace'] = myReplace # env.filters把过滤器注册到Jinja2引擎
return env
第七章模型与数据库笔记
ORM框架为数据库提供了统一的框架的API
在models.py中实际上是定义不同类型的字段
djnago\db\models\fields的init和files文件里中有各种模型字段
下方有28个数据字段
__all__ = [
'AutoField', 'BLANK_CHOICE_DASH', 'BigAutoField', 'BigIntegerField',
'BinaryField', 'BooleanField', 'CharField', 'CommaSeparatedIntegerField',
'DateField', 'DateTimeField', 'DecimalField', 'DurationField',
'EmailField', 'Empty', 'Field', 'FieldDoesNotExist', 'FilePathField',
'FloatField', 'GenericIPAddressField', 'IPAddressField', 'IntegerField',
'NOT_PROVIDED', 'NullBooleanField', 'PositiveIntegerField',
'PositiveSmallIntegerField', 'SlugField', 'SmallIntegerField', 'TextField',
'TimeField', 'URLField', 'UUIDField',
]
1.自增长类型,int,长度11为
3.自增长类型,bigint,长度20位
6.字符类型
待补充...
模型字段的参数
possibles = {
"verbose_name": None,
"primary_key": False,
"max_length": None,
"unique": False,
"blank": False,
"null": False,
"db_index": False,
"default": NOT_PROVIDED,
"editable": True,
"serialize": True,
"unique_for_date": None,
"unique_for_month": None,
"unique_for_year": None,
"choices": [],
"help_text": '',
"db_column": None,
"db_tablespace": None,
"auto_created": False,
"validators": [],
"error_messages": None,
}
特殊参数:
日期类DateField和TimeField的特殊参数auto_now_add和auto_now,字段FileFiled和ImageField的特殊参数upload_to
str
可用于外键查询,比如模型A设有外键字段F,外键字段F关联模型B,当查询模型A时,外键字段F会将模型B的函数__str__返回值作为字段内容
__str__只返回字符串类型的字段,如果字段是振兴或者日期型的,就需要通过str()函数将其转换为字符类型
Meta
Meta有19个属性;列出几个常用的属性
abstract
这个属性是定义当前的模型是不是一个抽象类。所谓抽象类是不会对应数据库表的。一般我们用它来归纳一些公共属性字段,然后继承它的子类可以继承这些字段。
Options.abstract
如果abstract = True 这个model就是一个抽象类
app_label
这个选型只在一种情况下使用,就是你的模型不在默认的应用程序包下的models.py文件中,这时候需要指定你这个模型是哪个应用程序的。
Options.app_label
如果一个model定义在默认的models.py,例如如果你的app的models在myapp.models子模块下,你必须定义app_label让Django知道它属于哪一个app
app_label = 'myapp'
db_table
db_table是指定自定义数据库表明的。Django有一套默认的按照一定规则生成数据模型对应的数据库表明。
Options.db_table
定义该model在数据库中的表名称
db_table = 'Students'
如果你想使用自定义的表名,可以通过以下该属性
table_name = 'my_owner_table'
db_teblespace
Options.db_teblespace
定义这个model所使用的数据库表空间。如果在项目的settin中定义那么它会使用这个值
get_latest_by
Options.get_latest_by
在model中指定一个DateField或者DateTimeField。这个设置让你在使用model的Manager上的lastest方法时,默认使用指定字段来排序
managed
Options.managed
默认值为True,这意味着Django可以使用syncdb和reset命令来创建或移除对应的数据库。默认值为True,如果你不希望这么做,可以把manage的值设置为False
order_with_respect_to
这个选项一般用于多对多的关系中,它指向一个关联对象,就是说关联对象找到这个对象后它是经过排序的。指定这个属性后你会得到一个get_xxx_order()和set_xxx_order()的方法,通过它们你可以设置或者回去排序的对象
ordering
这个字段是告诉Django模型对象返回的记录结果集是按照哪个字段排序的。这是一个字符串的元组或列表,没有一个字符串都是一个字段和用一个可选的表明降序的'-'构成。当字段名前面没有'-'时,将默认使用升序排列。使用'?'将会随机排列
ordering=['order_date'] # 按订单升序排列
ordering=['-order_date'] # 按订单降序排列,-表示降序
ordering=['?order_date'] # 随机排序,?表示随机
ordering=['-pub_date','author'] # 以pub_date为降序,在以author升序排列
permissions
permissions主要是为了在Django Admin管理模块下使用的,如果你设置了这个属性可以让指定的方法权限描述更清晰可读。Django自动为每个设置了admin的对象创建添加,删除和修改的权限。
permissions = (('can_deliver_pizzas','Can deliver pizzas'))
proxy
这是为了实现代理模型使用的,如果proxy = True,表示model是其父的代理 model
unique_together
unique_together这个选项用于:当你需要通过两个字段保持唯一性时使用。比如假设你希望,一个Person的FirstName和LastName两者的组合必须是唯一的,那么需要这样设置:
unique_together = (("first_name", "last_name"),)
一个ManyToManyField不能包含在unique_together中。如果你需要验证关联到ManyToManyField字段的唯一验证,尝试使用signal(信号)或者明确指定through属性。
verbose_name
verbose_name的意思很简单,就是给你的模型类起一个更可读的名字一般定义为中文,我们:
verbose_name = "学校"
verbose_name_plural
这个选项是指定,模型的复数形式是什么,比如:
verbose_name_plural = "学校"
如果不指定Django会自动在模型名称后加一个’s’
默认情况为返回值为函数名+外键
开发自定义ORM框架流程
Model类继承并重写元类进而实现
具体时编写模型基本类(field),模型字段(字符,整数等),元类,,然后再编写Model类继承元类
最后在编写自己的数据表,达到ORM框架,可以执行相应SQL语句的目的。
代码待分析
# 模型字段的基本类
class Field(object):
def __init__(self, name, column_type):
self.name = name
self.column_type = column_type
def __str__(self):
return '<%s:%s>' % (self.__class__.__name__, self.name)
# 模型字段的字符类型
class StringField(Field):
def __init__(self, name):
super().__init__(name, 'varchar(100)')
# 模型字段的整数类型
class IntegerField(Field):
def __init__(self, name):
super().__init__(name, 'bigint')
# 定义元类ModelMetaclass,控制Model对象的创建
class ModelMetaclass(type): # 继承元类,并重写元类type的__new__方法
def __new__(cls, name, bases, attrs):
mappings = dict()
for k, v in attrs.items():
# 保存类属性和列的映射关系到mappings字典
if isinstance(v, Field):
print('Found mapping: %s==>%s' % (k, v)) # 先执行这个元类
mappings[k] = v
for k in mappings.keys():
# 将类属性移除,使定义的类字段不污染User类属性
attrs.pop(k)
# 假设表名和为类名的小写,创建类时添加一个__table__类属性
attrs['__table__'] = name.lower()
# 保存属性和列的映射关系,创建类时添加一个__mappings__类属性
attrs['__mappings__'] = mappings
return super().__new__(cls, name, bases, attrs)
# 定义Model类
class Model(metaclass=ModelMetaclass):
def __init__(self, *args, **kwargs):
self.kwargs = kwargs
super().__init__()
def save(self):
fields, params = [], []
for k, v in self.__mappings__.items():
fields.append(v.name)
params.append(str(self.kwargs[k]))
sql = 'insert into %s (%s) values (%s)' # 这里的%s是
sql = sql % (self.__table__, ','.join(fields), ','.join(params))
print('SQL: %s' % sql)
# 定义模型User
class User(Model):
# 定义类的属性到列的映射:
id = IntegerField('id')
name = StringField('username')
email = StringField('email')
password = StringField('password')
# 创建实例对象
u = User(id=123, name='Dj', email='Dj@dd.gg', password='111') # 实例化并生成相应的SQL语句
# 调用save()方法;模型类save()的方法
u.save() # 只要在ORM框架里实现数据库连接,并执行SQL语句即可实现数据库的操作
数据迁移
执行makemigrations后,会在migrations生成个0001_initial.py文件,这是models.py定义生成的数据表的脚本代码。
脚本代码被migrate指令执行。根据脚本代码创建相应内容的数据表
Django内置的功能数据表分别是:
会话Session、用户认证管理和Admin后台管理系统
通过新增的模型创建数据表,删除对应模型字段等
都可用makemigrations和migrate指令;
Django会将该文件的执行记录保存在数据表django_migrations中
migrate还可以指定应用下的模型字段更新删除,找到那个makemigrations生成的数据表脚本文件,然后执行migrate时指定 应用名 脚本文件 即可
还提供了sqlmigrate指令
用来执行sql语句
和migrate差不多
sqlmigrate 应用名 脚本文件名;
这样可以在命令行中看到生成的sql语句;但它并不会执行,也就是不会生成相应的数据表
数据导入导出
当用数据可视化工具时,导入某个表的数据时,如果当前表设有外键字段,就必须将外键字段关联的数据表的数据导入,在执行当前数据表的数据导入操作
django还为我们提供数据导入导出的指令操作
loaddata;dumpdata来实现数据的导入导出操作(导入导出均为json格式)
一般导入导出最好为整个应用或整个项目
导出会经常碰到导出为空;有可能自己没写数据
导入loaddata碰到编码报错,解码问题
数据表关系
数据表存在的关系
一对一 OneToOneField
两个表的字段id不会重复,并且同一表中不会有重复ID(这句话咋理解);一张数据表设有很多字段,将常用的字段抽取出来组成一个新的数据表。
一对多 ForeignKey (最常用)
第一张表的某一行数据可以与第二张表的一道多行数据进行关联,但是第二张表的每一行数据只能与第一张表的某一行进行关联。
多对多 ManyToManyField
设有特殊的参数如下(3种数据库关系):
to 必选参数,关联的模型名称
ondelete:必选参数,设置数据的删除模式,删除模式包括:CASCADE、PROTECT、SET_NULL、SET_DEFAULT、SET和DO_NOTHING
limit_choices_to:设置外键的下拉框选项,用于模型表单和后台系统
related_name:用于模型之间的关联查询,如反向查询
related_query_name:设置模型的查询名称,用于filter或get查询,若设置参数related_name,则以该参数为默认值,若没有设置,则以模型名称的小写为默认值。
to_field:设置外键与其他模型字段的关联性,默认关联主键,若要关联其他字段,则该字段必须具有唯一性
db_constraint:在数据库中是否创建外键约束,默认为True
swappable:设置关联模型的替换功能,默认值为True,比如模型A关联模型B,想让模型C继承并替换模型B,使得模型A与模型C之间关联
symmetrical:仅限于ManytoManyField,设置多对多字段之间的对称模式
through:仅限于ManytoManyField,设置自定义模型C的字段,确认模型C的哪些模型字段用于管理模型A和B的多对多关系
db_table:仅限于ManytoManyField,设置和存储多对多关系的数据表设置表名称
数据表操作
json类型的数据格式外面时大括号[]
可在shell中实现
python manage.py shell
然后就是导入models的数据了
python manage.py shell
from index.models import * # 导入整个模块,你要知晓数据表的名字
报错;
IntegrityError: FOREIGN KEY constraint failed
外键字段的名称要以数据表为主,有时候他自动给外键名后加_id后缀
,有可能外键字段对应的那个表的外键字段名为id
具体插入数据过程
v = Vocation() # 模型数据表实例化
v.job = '教师'
v.title = '教书育人'
v.payment = 100 # 字段属性不要错,整形与字符串
v.name_id = 3 # 外键
v.save() # 保存
v,id # 查看新增的数据主键(一般就是第几个)
还有其他三种方式可进行数据插入
1.使用create方法实现数据插入
v = Vocation.objects.create(job='jj',title='hh',payment='0',name_id=4)
v.id
2.同样使用create方法,但数据以字典格式表示
d = dict(job='zz',title='xx',payment=00,name_id=4) # IntegerField字段00允许,01不可
v = Vocation.objects.create(**d)
v.id
3.在实例化时直接设置属性值
v = Vocation(job='aa',title='ss',payment=1,name_id=4)
v.save()
v.id
为保证插入的数据不重复,我们需要对数据进行去重操作,如果插入的数据不存在,则插入
默认情况插入是不考虑是否有重复数据的
正常是在插入数据之前查询,然后再插入
django提供了get_or_create方法
get_or_create方法根据模型字段的值与数据表中的数据进行判断
处主键除外,只要有一个数据不同就插入,插入返回True,否则就不插入
,返回False.
d = dict(job='zz',title='xx',payment=00,name_id=4)
v = Vocation.objects.get_or_create(**d)
v[0].id # 这里返回的是个元组,一般取第一个参数,一般也只有第一个参数
判断当前数据在数据表里是否存在(update_or_create)
若存在,则更新,否则,新增
修改的数据加在defaults参数上
d = dict(job='zz',title='xx',payment=00,name_id=4)
v = Vocation.objects.update_or_create(**d,defaults={'title':'java'})
v[0].title # Out[35]: 'java'
对模型执行数据批量插入操作(bulk_create)
将数据对象以列表或元组的形式传入bulk_create方法即可。
v1 = Vocation(job='aa1',title='ss1',payment=1,name_id=4)
v2 = Vocation(job='aa2',title='ss2',payment=1,name_id=4)
obj_list = [v1,v2]
v = Vocation.objects.bulk_create(obj_list)
v # [<Vocation: None>, <Vocation: None>]
数据修改
一般先查询
v = name.objects.get(id=xxx)
v.xxx= xxx
v.save() # 即可
还可用update更新
批量更新一条或多条数据,查询方法使用filter
# filter以列表格式返回,查询结果可能是一条或多条数据
Vocation.objects.filter(job='aa').update(job='u_aa') # Out[43]: 2
## 更新数据以字典格式表示
d = dict(job='uu_aa')
Vocation.objects.filter(job='u_aa').update(**d) # 2
### 不使用查询方法,默认对全表的数据进行更新
Vocation.objects.update(payment=6666) # Out[47]: 12
### 使用内置F方法实现数据对的自增或自减
### F方法还可以在annotate或filter方法里使用
from django.db.models import F
v = Vocation.objects.filter(job='uu_aa')
# 将payment字段整体加1
v.update(payment=F('payment')+1) # Out[50]: 2
###在django2.2以上新增了数据批量更新方法bulk_update,使用方法与bulk_creat类似
到这里我们已经学了,数据的新增,修改,
接着是删除
删除表中全部数据
Vocation.objects.all().delete()
删除一条id为1的数据
Vocation.objects.get(id=1).delete() # (1, {'index.Vocation': 1})
删除多条数据
Vocation.objects.filter(job='uu_aa').delete() # (2, {'index.Vocation': 2})
删除数据设有外键字段,同样会删除该字段
PersonInfo.objects.get(id=3).delete() # Vocation删除了2条数据,PersonInfo删除了1条数据
# Out[54]: (3, {'index.Vocation': 2, 'index.PersonInfo': 1})
一对多中的那个一都是被动的被另外一个数据表以ForeignKey关联
外键字段的on_delete字段用于设置数据删除模式
CASCADE 级联删除。Django 模拟 SQL 约束 ON DELETE CASCADE 的行为,并删除包含 ForeignKey 的对象。
PROTECT 通过提高ProtectedError的子类来 防止删除引用的对象
SET_NULL设置为ForeignKey空;这只有在null是 时才有可能 True
SET_DEFAULT[源代码]
将 设置ForeignKey为其默认值;ForeignKey必须设置默认值 。
SET() [源代码]
将 设置为ForeignKey传递给 的值 SET(),或者如果传入可调用对象,则为调用它的结果。在大多数情况下,需要传递一个可调用对象以避免在导入 models.py 时执行查询:
DO_NOTHING[源代码]
不采取行动。如果您的数据库后端强制执行参照完整性,IntegrityError除非您手动向数据库字段添加 SQL约束,否则这将导致错误。ON DELETE
书本中的更简洁
https://www.cnblogs.com/wkhzwmr/p/15592602.html
稍后补充;下一篇博文中有
数据查询
有单表查询,多表查询,子查询和联合查询等
;除了单表查询,其他查询待补()
使用ORM框架提供的API达到查询的目的
单表查询,即在一个表中查询
from index.models import *
## 全表查询
v = Vocation.objects.all()
v[0].job # Out[4]: '文员'
## 查询前3条数据
Sql语句中的LIMIT方法,全表查询返回的是个列表
查询某个字段用values
values_list方法,数据以列表返回,列表元素以元组表示
## 使用get方法查询返回的是单个字段`<Vocation: 2>`,查询字段必须是主键或者唯一约束的字段,并且查询的数据必须存在,若重复或不存在则报错
## 使用filter方式查询,返回的是个列表`<QuerySet [<Vocation: 2>]>`
查询字段没有限制,返回的是个列表,查询为空则返回空列表。
## SQL的and查询主要在filter里面添加多个查询条件,在django中表示用逗号(,)隔开即可
## SQL的or查询需要引入Q,编写格式:Q(filter=value)|Q(filter=value)
### 多个Q之间使用'|'隔开
##SQL:select * from index_vocation where job='网站设计' or id=9
from django.db.models import Q
v = Vocation.objects.filter(Q(job='网站设计' )|Q(id=9))
v # ` <QuerySet [<Vocation: 3>]>`
v[0].job # 网站设计
数据库的查询方法介绍了很多,还介绍了filter和get的匹配符
该下方就是大致看了下,代码没敲;这里又使用了很多其他关键字
多表查询又分为正向查询和反向查询
正向查询为多的那个表查询单个的表,也就是设有外键与其他表有关联的表,反向查询即相反
执行SQL语句
一些复杂的查询很难在使用ORM的API,所以引入SQL语句的执行方法
extra:结果集修改器,一种提供额外查询参数的机制
raw:执行原始SQL并返回模型实例对象
execute:直接执行自定义SQL
数据库事务
ACID
Atomicity:原子性
Consistency:一致性
隔离性:Isolation
持久性:Durability
多数据库的连接
https://www.cnblogs.com/wkhzwmr/p/15592602.html
笔记来源:Django Web应用开发实战