Django路由系统
Django的路由系统让Django可以根据URI进行匹配,进而发送至特定的函数去处理用户请求。有点类似nginx的location功能。
Django的路由关系分为三种:普通关系、动态关系、分组分发。这三种关系都记录在urls.py中。
路由-普通关系
普通关系表示一个url对应一个函数,例如:
urlpatterns = [
url(r'^admin/', admin.site.urls),
url(r'^login/', views.login),
url(r'^detail/', views.detail),
]
路由-动态关系
动态关系表示通过正则的方式去实现动态匹配。例如:
urlpatterns = [
url(r'^detail/(\d+)/', views.detail), # 动态路由之:单参数的路由
url(r'^detail2/(\d+)/', views.detail2), # 动态路由之:多参数的路由
url(r'^detail3/(?P\d+)/(?P\d+)/', views.detail3), # 动态路由之:命名参数,两个参数分别被命名为p1和x2
url(r'^index/(\d+)/', views.index), # 分页显示
]
动态路由,也是动态关系的一种,动态路由其实通过映射也可以实现,需要自己来实现
主要代码实现1、url.py
配置url映射2、activator.py
根据url中获取的参数,通过反射调用指定 app/view.py 中的函数
如:
http://127.0.0.1:9000/app01/index/ ==》 执行app01/view.py文件中的index函数
http://127.0.0.1:9000/app02/index/ ==》 执行app02/view.py文件中的index函数
http://127.0.0.1:9000/app01/login/ ==》 执行app01/view.py文件中的login函数#具体代码:#总入口urls.py
from django.conf.urls importinclude, urlfrom django.contrib importadminfrom DynamicRouter.activator importprocess
urlpatterns=[#Examples:
#url(r'^$', 'DynamicRouter.views.home', name='home'),
#url(r'^blog/', include('blog.urls')),
url(r'^admin/', include(admin.site.urls)),
('^(?P(\w+))/(?P(\w+))/(?P(\d+))/(?P(\d+))/$',process),
('^(?P(\w+))/(?P(\w+))/(?P(\d+))/$',process),
('^(?P(\w+))/(?P(\w+))/$',process),
('^(?P(\w+))/$',process,{'function':'index'}),
]#activator.py代码
from django.shortcuts importrender_to_response,HttpResponse,redirectdef process(request,**kwargs):'''接收所有匹配url的请求,根据请求url中的参数,通过反射动态指定view中的方法'''app= kwargs.get('app',None)
function= kwargs.get('function',None)try:
appObj= __import__("%s.views" %app)
viewObj= getattr(appObj, 'views')
funcObj=getattr(viewObj, function)#执行view.py中的函数,并获取其返回值
result =funcObj(request,kwargs)except(ImportError,AttributeError) as e:#导入失败时,自定义404错误
return HttpResponse('404 Not Found')exceptException as e:#代码执行异常时,自动跳转到指定页面
return redirect('/app01/index/')return result
通过映射实现动态路由
路由-分组分发
什么是分组分发?一个Django项目里,通常会有很多的app,比如一些bbs论坛为例,他的项目里就有前端部分,供普通用户使用,这类url通常写作http://hostname/common/form.php 。 也有后端admin管理员部分,用来进行用户管理、帖子管理等功能。这类url通常有个特别,一般是http://hostname/admin/XXX。可以明显看到,这个论坛项目中,就有2个分组:common和admin。Django中也有这样的功能。
Django分组写法:
步骤1:导入include函数
from django.conf.urls import include
步骤2:创建url映射
urlpatterns = [
...
url(r'^common/', include("frontweb.urls")), # 多app项目的分组匹配
url(r'^admin/', include("manager.urls")), # 多app项目的分组匹配
]
上面代码中,定义了2个app,一个是frontweb,一个是manager。
步骤3:在app中创建对应的url
# manager\urls.py中 代码
from manager import views
urlpatterns = [
url(r'^assets', views.assets),
url(r'^userinfo', views.userinfo),
]
# frontweb\urls.py中 代码
from frontweb import views
urlpatterns = [
url(r'^index/(\d+)/', views.index),
url(r'^detail/(\d+)/', views.detail),
url(r'^userinfo', views.userinfo),
]
模板
模版的创建过程,对于模版,其实就是读取模版(其中嵌套着模版标签),然后将 Model 中获取的数据插入到模版中,最后将信息返回给用户。
模板的语法
1. 传普通字符串
# python中
return render(request, 'index.html', {'k1': 'v1'})
# html中引用k1的值
{{ k1 }}
2. 传入列表
# python中
return render(request, 'index.html', {'k2': [11,22,33,44]})
# html中引用k1的值
{{ k2 }}
{{ k2.0 }}
{{ k2.1 }}
{{ k2.2 }}
3. 传入字典
# python中
return render(request, 'index.html', {'k3': {'name': 'Bob', 'nid': 18}})
# html中引用k1的值
{{ k3 }}
{{ k3.name }}
{{ k3.nid}}
4. 模板中的for循环,还是以上边的传入列表k2为例
{% for item in k2 %}
{{ item }},
{{ forloop.counter }},
{{ forloop.counter0 }},
{{ forloop.first }},
{{ forloop.last }},
{{ forloop.revcounter }}
{% endfor %}
5. 模板中的if循环,以上边传入的k1为例
{% if k1 == 'v1' %}
V1
{% elif k1 == 'v2' %}
V2
{% else %}
777777
{% endif %}
6. 模板中的继承语法
母板:{% block title %}{% endblock %}
子板:{% extends "base.html" %}
{% block title %}{% endblock %}
7. 模板内置的一些方法(可以理解为函数,而模板中的变量就是传入的值)
{{ item.event_start|date:"Y-m-d H:i:s"}}
{{ bio|truncatewords:"30" }}
{{ my_list|first|upper }}
{{ name|lower }}
8. 自定义模板方法
自定义模板方法,有两种方式,一种是filter,另外一种是simple_tag
8.1 filter
步骤1:创建指定文件夹,名称必须为templatetags,文件夹放在对应的app目录下。
步骤2:创建任意的py文件,比如xx.py
from django import template
from django.utils.safestring import mark_safe
from django.template.base import Variable, Node, TemplateSyntaxError
register = template.Library()
#要点1: template.Library的返回值的变量,必须是register,不能是其他
#要点2:函数必须加装饰器register.filter,这样f1就是模板语言中的一个函数
@register.filter
def f1(value):
# 接收单个参数
return value + 'f111'
@register.filter
def f2(value, value2):
# 接收两个参数
return value + value2
步骤3:使用函数,在html模板的头部,执行{% load xx %},xx表示创建的py文件的文件名
{% load xx %}
步骤4:使用函数
# html中代码
{{ k1|f1 }} {# filter自定义方法之:1个参数 #}
# 输出 v1f111 # 其中v1是k1本身的值,f111是函数后加的字符串
# html中代码
{{ k1|f2:'F2:XXX' }}
{# filter自定义方法之:2个参数 #}
{% if k1|f1 == 'v1f111' %}
filter可以用作if语句的条件
{% endif %}
最终输出: v1F2:XXX 其中v1是k1的值, F2:XXX是前端传入的变量
Ps:从上边可以看出,filter方法构建的函数,默认不支持传入超过2个以上的参数,因此,如果需要传入多个参数,可以将"F2:XXX"写成 "F2:XXX,arg3,arg4",在python代码中,用split来拆分字符串,来获取参数。
限制:传参个数有限制,多个参数需要自行split进行切割
支持:可以作为模板中if语句的if条件
步骤5:注册app。最后一步非常重要,否则django会不知道去哪个路径下查找xx.py。
# 在settings.py中注册app
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'app01', # 新注册的app目录名称
]
8.2 用simple_tag 来自定义模板方法
创建simple_tag的步骤基本一致,唯独不同的有2个地方
不同点1: 函数的装饰器需要写为register.simple_tag
@register.simple_tag
def f3(value):
return value + 'f3333'
@register.simple_tag
def f4(value, arg1, arg2):
return value + arg1 + arg2
不同点2:前端html传参的时候
# html中的代码
{% f3 'simple_tag' %}
{# simple_tag自定义方法之:1个参数 #}
{% f4 'simple_tag' 'arg2' 'arg3' %}
{# simple_tag自定义方法之:多个参数 #}
# 输出
simple_tagf3333
simple_tagarg2arg3
Ps:用simple_tag来创建函数,不支持作为if语句中的条件
模板的渲染过程
看一张图就明白,
模板继承
母版页面
母版页面通常用来定义网页的基本框架结构,同时空出部分内容块来供子页面来自定义式的填充
# 母版的代码
{% block css %}{% endblock %} # 空出名为css的代码块部分,供子版来填充
{% block body %}{% endblock %} # 同上,只是名称不同而已
{% block js %}{% endblock %} #同上,只是名称不同而已
完整代码示例如下图:
子页面
{% extends 'layout.html' %} # 表示继承layoout.html母版页面
{% block css %} #自定义样式
...
{% endblock %}
{% block body %} # 填充html内容
{% for item in assets_list %}
{{ item.hostname }}{{ item.port }}{% endfor %}
{% endblock %}
{% block js %} # 自定义js
...
{% endblock %}
重复利用的小插件
一般情况下,在页面中,会有一些元素是相似度很高的,或许只有装饰文件不同而已。比如京东首页中,家电数码、个性美妆、手机通讯等部分。通常的做法是把这些相似的部分,做成类似小插件一样的html代码,在使用的时候引用即可。
{% include "xx.html" %}
Django中的Model
在Django的model中,提供了两类操作,一种是创建数据库表(CURD),一种是操作数据库的数据
Django数据库表间的三种关系
Django的数据库表中,有三种关系:一对一,一对多,多对多。
假设有两张表userinfo和user_type 。
class userinfo(models.Model):
nid = models.AutoField(primary_key=True)
name = models.CharField(max_length=30, verbose_name='用户名',editable=TabError)
email = models.EmailField(db_index=True)
memo = models.TextField()
# 普通用户,超级用户
class UserType(models.Model):
name = models.CharField(max_length=32)
def __str__(self):
return self.name
一对一
即 user_type = OneToOneField("另外一张表")
这种情况下,每次创建一条userinfo数据,就需要userType表中一条数据与之对应。即,usertype表中的数据,只能被对应一次。
一对多
即 user_type = models.ForeignKey("UserType")
这是很常见的一种对应关系。比如一个usertype有两种用户,超级用户和普通用户,那么在这两种用户组中,可以分别存在很多人。
多对多
即 user_type = models.ManyToManyField("UserType")。
比如,一个user可以属于多个usergroup,一个usergroup可以包含多个user,这就是典型的多对多关系。
创建数据库表
步骤1:在app的models.py中写类,来创建表的每个字段
1、models.AutoField 自增列 = int(11)
如果没有的话,默认会生成一个名称为 id 的列,如果要显示的自定义一个自增列,必须将给列设置为主键 primary_key=True。2、models.CharField 字符串字段
必须 max_length 参数3、models.BooleanField 布尔类型=tinyint(1)
不能为空,Blank=True4、models.ComaSeparatedIntegerField 用逗号分割的数字=varchar
继承CharField,所以必须 max_lenght 参数5、models.DateField 日期类型 date
对于参数,auto_now=True 则每次更新都会更新这个时间;auto_now_add 则只是第一次创建添加,之后的更新不再改变。6、models.DateTimeField 日期类型 datetime
同DateField的参数7、models.Decimal 十进制小数类型 =decimal
必须指定整数位max_digits和小数位decimal_places8、models.EmailField 字符串类型(正则表达式邮箱) =varchar
对字符串进行正则表达式9、models.FloatField 浮点类型 =double10、models.IntegerField 整形11、models.BigIntegerField 长整形
integer_field_ranges={'SmallIntegerField': (-32768, 32767),'IntegerField': (-2147483648, 2147483647),'BigIntegerField': (-9223372036854775808, 9223372036854775807),'PositiveSmallIntegerField': (0, 32767),'PositiveIntegerField': (0, 2147483647),
}12、models.IPAddressField 字符串类型(ip4正则表达式,在1.10的django版本中,可能会被替换掉,统一使用models.GenericIPAddressField)13、models.GenericIPAddressField 字符串类型(ip4和ip6是可选的)
参数protocol可以是:both、ipv4、ipv6
验证时,会根据设置报错14、models.NullBooleanField 允许为空的布尔类型15、models.PositiveIntegerFiel 正Integer16、models.PositiveSmallIntegerField 正smallInteger17、models.SlugField 减号、下划线、字母、数字18、models.SmallIntegerField 数字
数据库中的字段有:tinyint、smallint、int、bigint19、models.TextField 字符串=longtext20、models.TimeField 时间 HH:MM[:ss[.uuuuuu]]21、models.URLField 字符串,地址正则表达式22、models.BinaryField 二进制23、models.ImageField 图片(以字符串形式保存,存储文件路径)24、models.FilePathField 文件(以字符串形式保存,存储文件路径)
models中的字段类型
1、null=True
数据库中字段是否可以为空2、blank=True
django的 Admin 中添加数据时是否可允许空值3、primary_key =False
主键,对AutoField设置主键后,就会代替原来的自增 id 列4、auto_now 和 auto_now_add
auto_now 自动创建---无论添加或修改,都是当前操作的时间
auto_now_add 自动创建---永远是创建时的时间5、choices
GENDER_CHOICE=(
(u'M', u'Male'),
(u'F', u'Female'),
)
gender= models.CharField(max_length=2,choices =GENDER_CHOICE)6、max_length7、default 默认值8、verbose_name Admin中字段的显示名称9、name|db_column 数据库中的字段名称10、unique=True 不允许重复11、db_index =True 数据库索引12、editable=True 在Admin里是否可编辑13、error_messages=None 错误提示14、auto_created=False 自动创建15、help_text 在Admin中提示帮助信息16、validators=[]17、upload-to
models中字段类型的可选参数
步骤2:执行python manager.py makemigrations && python manager.py migrate初始化数据库结构
操作数据库表-基本操作
基本数据访问
运行python manage.py shell并使用Django提供的高级Python API
# 导入student模型类,通过这个类我们可以与student数据表进行交互
>>> from app01.models import UserType
# 创建一个student类的实例并设置了字段name的值
>>> data_1 = UserType(name='外围人员')
# 调用该对象的save()方法,将对象保存到数据库中,Django会在后台执行一条INSERT语句
>>> s1.save()
# 再插入一条数据
>>> data_2 = UserType(name='核心人员')
>>> data_2 .save()
# 使用UserType.objects属性从数据库取出UserType表的记录集,这个属性有许多方法,UserType.objects.all()方法获取数据库中UserType类的所有对象,实际上Django执行了一条SQL SELECT语句
>>> usertype_list = UserType.objects.all()
>>> usertype_list
Out[6]: , , ]>
在代码中进行数据访问基本操作
增
方法1:
models.Tb1.objects.create(c1='xx', c2='oo') 增加一条数据,可以接受字典类型数据 **kwargs
方法2:
obj = models.Tb1(c1='xx', c2='oo')
obj.save()
删
models.Tb1.objects.filter(name='seven').delete() # 删除指定条件的数据
改
方法1:
models.Tb1.objects.filter(name='seven').update(gender='0') # 将指定条件的数据更新,均支持 **kwargs
方法2:
obj = models.Tb1.objects.get(id=1)
obj.c1 = '111'
obj.save() # 修改单条数据
查
models.Tb1.objects.get(id=123) # 获取单条数据,不存在则报错(不建议)
models.Tb1.objects.all() # 获取全部
models.Tb1.objects.filter(name='seven') # 获取指定条件的数据
obj = model.UserInfo.objects.filter(name='alex').values('id','email')
#sql: select id,email from userinfo where name = 'alex'
# 结果是个字典:[{'id':1 , 'email':'xxq@qq.com'}, {'id':2 , 'email':'qqqq@qq.com'},...]
obj = model.UserInfo.objects.filter(name='alex').value_list('id','email')
#sql: select id,email from userinfo where name = 'alex'
#结果是个元祖 [('1', 'xxq@qq.com'), ('2', 'qqq@qq.com'), (),....]
说明
执行models.Tb1.objects.all()等查询的结果,是一个queryset对象,而queryset是Django中定义的一个类
操作数据库单表-进阶操作
#获取个数#
#models.Tb1.objects.filter(name='seven').count()
#大于,小于---gt lt语句#
#models.Tb1.objects.filter(id__gt=1) # 获取id大于1的值#models.Tb1.objects.filter(id__lt=10) # 获取id小于10的值#models.Tb1.objects.filter(id__lt=10, id__gt=1) # 获取id大于1 且 小于10的值
#in#
#models.Tb1.objects.filter(id__in=[11, 22, 33]) # 获取id等于11、22、33的数据#models.Tb1.objects.exclude(id__in=[11, 22, 33]) # not in
#contains---like语句#
#models.Tb1.objects.filter(name__contains="ven") # contains就是like#models.Tb1.objects.filter(name__icontains="ven") # icontains 表示对大小写不敏感#models.Tb1.objects.exclude(name__icontains="ven")
#range ---between and语句#
#models.Tb1.objects.filter(id__range=[1, 2]) # 范围bettwen and
#其他类似#
#startswith,istartswith, endswith, iendswith,
#order by#
#models.Tb1.objects.filter(name='seven').order_by('id') # asc#models.Tb1.objects.filter(name='seven').order_by('-id') # desc 加上负号表示倒序
#limit 、offset#
#models.Tb1.objects.all()[10:20] # 分页获取
#group by
from django.db.models importCount, Min, Max, Sum#models.Tb1.objects.filter(c1=1).values('id').annotate(c=Count('num')) # 这里的value表示要根据id 进行groupby, 获取num列的个数#SELECT "app01_tb1"."id", COUNT("app01_tb1"."num") AS "c" FROM "app01_tb1" WHERE "app01_tb1"."c1" = 1 GROUP BY "app01_tb1"."id"
单表进阶操作-了不起的双下划线
操作数据库连表-进阶操作
双下划线的主要功能:1)大于小于等操作,参照上面的单表进阶操作 2)跨表操作
数据库结构说明:
classUserProfile(models.Model):
user_info= models.OneToOneField('UserInfo')
username= models.CharField(max_length=64)
password= models.CharField(max_length=64)def __unicode__(self):returnself.usernameclassUserInfo(models.Model):
user_type_choice=(
(0, u'普通用户'),
(1, u'高级用户'),
)
user_type= models.IntegerField(choices=user_type_choice)
name= models.CharField(max_length=32)
email= models.CharField(max_length=32)
address= models.CharField(max_length=128)def __unicode__(self):returnself.nameclassUserGroup(models.Model):
caption= models.CharField(max_length=64)
user_info= models.ManyToManyField('UserInfo')def __unicode__(self):returnself.captionclassHost(models.Model):
hostname= models.CharField(max_length=64)
ip=models.GenericIPAddressField()
user_group= models.ForeignKey('UserGroup')def __unicode__(self):return self.hostname
数据库表结构
操作数据库联表-双下划线跨表查询
两种表的联表查询案例
#表结构
classUserInfo(models.Model):
user= models.CharField(max_length=32)
pwd= models.CharField(max_length=32)classUserInfo(models.Model):
user= models.CharField(max_length=32)
pwd= models.CharField(max_length=32)
user_type= models.ForignKey('UserType')#创建UserInfo
1、UserInfo.objects.create(user='alex',pwd='123',user_type=UserType.objects.get(id=2)) #这种方法不推荐,实际查询了2次
2、 UserInfo.objects.create(user='alex',pwd='123',user_type_id=2) #推荐这种方法!!!这种是进阶用法
#普通查询:
UserInfo.objects.filter(user='alex')1、查询所有用户类型等于 普通用户 的所有用户名和密码(普通查询方法)
uid= UserType.objects.get(caption='普通用户').id #uid是一个对象
UserInfo.objects.filter(user_type_id=uid)#进阶跨表查询方法及取值方法
querset = UserInfo.objects.filter(user_type__caption='普通用户')
querset= UserInfo.objects.filter(user_type__id__gt=2)
【UserInfo对象,UserInfo对象,UserInfo对象,】
row=querset[0]
row.user
row.pwd
row.user_type.id
row.user_type.caption#在进行models.object.xxx查询时,使用: objects __#获取到某一样的对象后使用: row.外键字段.外键表的字段
#使用values和value_list跨表查询方法及取值
querset = UserInfo.objects.filter(user_type__caption='普通用户').values('user','user_type__caption')
【{'user': 'alex','user_type__caption': '普通用户'},{'user': 'eric','user_type__caption': '普通用户'},】 结果是一个字典对象形成的列表#取出单值
row =querset[0]
row['user']
row['user_type__caption']
2张表的联表创建及查询
三张表跨表操作classSomthing(models.Model):
name= models.CharField(max_length=32)classUserType(models.Model):
catption= models.CharField(max_length=32)
s= models.ForignKey('Somthing')#超级管理员,普通用户,游客,黑河
classUserInfo(models.Model):
user= models.CharField(max_length=32)
pwd= models.CharField(max_length=32)
user_type= models.ForignKey('UserType')#通过Userinfo表,查询Something表中name是xx
UserInfo.objects.filter(user_type__s__name='xx')#多个下滑连通过外键__ 则可以
3张表的联表查询
Model中的多对多操作补充
Django中创建多对多关系有两种方式:
方式1:手动创建第三张表,与其他两张表建立外键关系
class B2G(models.Model):
b_id = models.ForeignKey('Boy')
g_id = models.ForeignKey('Girl')
class Boy(models.Model):
username = models.CharField(max_length=16)
def __str__(self):
return str(self.id)
class Girl(models.Model):
name = models.CharField(max_length=16)
def __str__(self):
return str(self.id)
方式2:利用models.ManyToManyField来让django自动创建第三张表
class Boy(models.Model):
username = models.CharField(max_length=16)
def __str__(self):
return str(self.id)
class Girl(models.Model):
name = models.CharField(max_length=16)
b = models.ManyToManyField('Boy')
def __str__(self):
return str(self.id)
多对多基本操作
建立两张表的关系:即向第三张表中增加数据-获取两个对象,通过add方法建立关系
########### 增加数据 ###########
# 获取一个女孩对象
g1 = models.Girl.objects.get(id=1)
# 获取一个男孩对象
b1 = models.Boy.objects.get(id=1)
# 利用多对多字段“b”将男孩和女孩建立关系--一对一建立关系
g1.b.add(models.Boy.objects.get(id=1))
g1.b.add(1) # 也可以传入数字或者 数字列表*【1,2,3】
# 添加和女孩1和 男孩1,2,3,4关联--一对多建立关系
g1 = models.Girl.objects.get(id=1)
g1.b.add(*[1,2,3,4])
# 将多个boy与女孩1建立关联
# boys = models.Boy.objects.all()
# g1.b.add(*boys)
查询数据
# 获取一个女孩对象
g1 = models.Girl.objects.get(id=1)
# 获取和当前女孩有关系的所有男孩
boy_list = g1.b.all()
print(boy_list)
删除数据
# 删除第三张表中和女孩1关联的所有关联信息
g1 = models.Girl.objects.get(id=1)
g1.b.clear()
# 删除女孩1和男孩2,3的关联
g1 = models.Girl.objects.get(id=1)
g1.b.remove(*[2,3])
特别补充——反向添加:由于manytomany的存在,在Boy表中,还有一个隐含字段girl_set,他的作用与Gril中的b字段是一样的功能。
b1 = models.Boy.objects.get(id=1)
b1.girl_set.add(1)
b1.girl_set.add(models.Girl.objects.all())
b1.girl_set.add(*[1,2,3,4])
多对多跨表操作
首先要明白一点,通过第三张表进行跨表操作,是通过left outer join的形式进行查询的,on的条件就是A表的id与B表的id相等。
# 两张表关联查询
models.Girl.objects.all().values('id','name', 'b')
# 查询 第三张表b的 girl.id==b.id的 b.boy_id列
SQL:
SELECT "app01_girl"."id", "app01_girl"."name", "app01_girl_b"."boy_id" FROM "app01_girl" LEFT OUTER JOIN "app01_girl_b" ON ("app01_girl"."id" = "app01_girl_b"."girl_id")
# 三张表关联查询-跨表查询
models.Girl.objects.all().values('id','name', 'b__username')
SQL:
SELECT "app01_girl"."id", "app01_girl"."name", "app01_boy"."username" FROM "app01_girl" LEFT OUTER JOIN "app01_girl_b" ON ("app01_girl"."id" = "app01_girl_b"."girl_id") LEFT OUTER JOIN "app01_boy" ON ("app01_girl_
b"."boy_id" = "app01_boy"."id")
r = models.Boy.objects.exclude(girl__name=None).values('id','username', 'girl__name')
print(r)
print(r.query)
#SELECT "app01_boy"."id", "app01_boy"."username", "app01_girl"."name" FROM "app01_boy" LEFT OUTER JOIN "app01_girl_b" ON ("app01_boy"."id" = "app01_girl_b"."boy_id") LEFT OUTER JOIN "app01_girl" ON ("app01_girl_b".
#"girl_id" = "app01_girl"."id") WHERE NOT ("app01_boy"."id" IN (SELECT U0."id" AS Col1 FROM "app01_boy" U0 LEFT OUTER JOIN "app01_girl_b" U1 ON (U0."id" = U1."boy_id") LEFT OUTER JOIN "app01_girl" U2 ON (U1."girl_i
#d" = U2."id") WHERE U2."name" IS NULL))
原生SQL操作-更新
在Django的SQL ORM框架中,对于更新操作的支持并不好,因此需要借助原生的sql语句来完成更新操作
from django.db import connection
cursor = connection.cursor()
cursor.execute("""SELECT * from tb where name = %s""", ['Lennon'])
row = cursor.fetchone()