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 &#124;add:"2" }}
addslashes 添加斜杠 {{ value &#124;addslashes }}
capfirst 首字母大写 {{ value &#124;capfirst}}
center 文本居中 {{ value &#124;center:"15"}}
cut 切除字符 {{ value &#124;cut:"arg" }}
date 日期格式化 {{ value &#124;data:"D d M Y"}} 可用的日期格式字符串,python的datetime模快中有
default value为False或者0时才设置默认值 { value &#124;default:"nothing" }
default_if_none 如果value的意义为None,为其设置默认值 {{ value &#124;default_if_none:"null"}}
dictsort 字典排序,前提value是列表包含的字典,按照字典的关键字属性值排序 {{ value &#124;dictsort:"name"}}
dictsortreversed 字典反向排序前提value是列表包含的字典,按照字典的关键字属性值反序排序 {{ value &#124;dictsortreversed:"name"}}
divisibleby 整除判断,如果value能被arg整除,则返回True {{ value &#124;divisibleby:"arg" }}
escape 转义HTML中的特殊字符,value输出为html元素标签时候 {{value &#124;escape}}
escapejs 转义js代码,替换value中的某些字符,适应js或json格式 {{value &#124;escapejs}}
filesizeformat 文件尺寸人性化显示,如果value为123456789,输出将是117.7 MB。 {{value &#124;filesizeformat}}
first 返回列表中的第一个元素 {{value &#124;first}}
floatformat 浮点数格式化,若无参数默认保持1位,有的话按参数来 {{value &#124;floatformat:"arg"}}
force_escape 强制立刻转义HTML字符串 {{ body&#124;linebreaks&#124;force_escape }}
get_digit 获取数字,从右边开始 {{ value &#124;get_digit:"2" }}
iriencode 转换IRI,转换为url中适应的编码(ASCII) {{ value &#124;iriencode }}
join 字符列表链接,类似于Python的join() {{ value &#124;join:" // " }}
json_script 生成script标签,带json数据,可接收一个参数表示script的Id {{ value &#124;json_script:"hello-data" }}
last 最后一个 {{ value &#124;last }}
length 长度 {{ value &#124;length }}
length_is 长度等于,等于参数则返回true {{ value&#124;length_is:"4" }}
linebreaks 行转换,整个文本被p标签包裹,换行符用\n表示 {{ value &#124;linebreaks }}
linebreaksbr 行转换,换行符用\n表示 {{ value &#124;linebreaksbr }}
linenumbers 显示带行号的文本 {{ value &#124;linenumbers }}
ljust 给定宽度左对齐 "{{ value &#124;ljust:"10" }}"
lower 小写 {{ value &#124;lower }}
make_list 分割成字符列表 {{ value &#124;make_list }}
phone2numeric 电话号码,中的字母转化为等效数字 {{ value &#124;phone2numeric }}
pluralize 复数形式,可指定参数 {{ num_walruses&#124;pluralize:"es" }}
pprint 调试 用于调试的过滤器,也就是 pprint.pprint()
random 从列表中随机获取 {{ value &#124;random }}
rjust 右对齐给定宽度的值 "{{ value &#124;rjust:"10" }}"
safe 安全确认 将字符串标记为安全,不需要转义。
safeseq 列表安全确认,它首先将变量转换为字符串 {{ some_list&#124;safeseq&#124;join:", " }}
slice 切片 {{ some_list&#124;slice:":2" }}
slugify 转换成ASCII {{ value &#124;slugify }}
stringformat 字符串格式化 {{ value &#124;stringformat:"E" }}
striptags 去除HTML中的标签 {{ value &#124;striptags }}
time 时间格式化 {{ value &#124;time:"H:i" }}
timesince 从何时开始,包含用作比较点的日期的变量 {{ blog_date&#124;timesince:comment_date }}
timeuntil 到何时多久,包含用作比较点的日期的变量 {{ conference_date&#124;timeuntil:from_date }}
title 所有单词首字母大写 {{ value &#124;title }}
truncatechars 截断字符 {{ value &#124;truncatechars:9 }}
truncatechars_html 截断字符,但是会保留HTML标记。 {{ value &#124;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应用开发实战

posted @ 2021-11-22 19:10  索匣  阅读(195)  评论(0编辑  收藏  举报