碎片一:ORM一对一表
ORM一对一的表是完全可以写在一张表当中的,但是出于部分字段可能被经常调用,而部分字段偶尔调用,所以将一张表拆分开,形成一对一形式的表结构,下面两个表就是一对一关系,两个表的关系是一一对应的
#作者
class Author(models.Model):
'''作者数据表'''
id=models.AutoField(primary_key=True)
name=models.CharField(max_length=50,verbose_name='作者名称',null=False,unique=True)
book=models.ManyToManyField(to='Book') #Django自动建立多对多关系表
detail=models.OneToOneField(to='AuthorDetail') #建立一对一关系表
def __str__(self):
return '{},{},{}'.format(self.id,self.name,self.book)
#作者extends
class AuthorDetail(models.Model):
'''作者扩展表'''
id=models.AutoField(primary_key=True)
#爱好
hobby=models.CharField(max_length=50,verbose_name='爱好')
#地址
addr=models.CharField(max_length=200,verbose_name='地址')
def __str__(self):
return '{},{},{}'.format(self.id,self.hobby,self.addr)
上面的表,Author中的字段会被经常使用到,而AuthorDetail当中的字段不会经常使用到,所以就拆分成两个表,通过Django的OneToOneField进行一对一关系建立
1、什么时候使用一对一?
当一张表的某一些字段查询的比较频繁,另外一些字段查询的不是特别频繁,把不怎么常用的字段 单独拿出来做成一张表 然后用过一对一关联起来
2、使用一对一的优势:
既保证数据都完整的保存下来,又能保证大部分的检索更快
3、ORM中的用法:OneToOneField(to="")
作者表:
作者详情表:
4、一对一关系表在Django当中的查询
import os
if __name__=='__main__':
os.environ.setdefault('DJANGO_SETTINGS_MODULE','booksys.settings')
import django
django.setup()
from bookapp.models import *
#一对一查询
author_obj=Author.objects.get(id=1)
detail_obj=author_obj.detail
print(detail_obj.hobby,detail_obj.addr)
解析上面代码:
1、首先得到作者的对象author_obj
2、通过author_obj得到对应的作者详情对象detail_obj,然后打印出对象的属性值
篮球 成都
碎片二:ORM建立多对多表结果的三种方式
第一种:通过ManyToMany,ORM自动帮我们创建多对多关系表
在数据库当中会自动生成第三张表
第二种:自己手动添加第三张表,利用外键分别关联具有多对多关系的两个表
#书
class Book(models.Model):
'''书数据表'''
id=models.AutoField(primary_key=True)
title=models.CharField(max_length=50,verbose_name='书名',null=False,unique=True)
price=models.DecimalField(max_digits=5,decimal_places=2,default=99.99)
kucun=models.IntegerField(default=0)
maichu=models.IntegerField(default=0)
publisher=models.ForeignKey(to="Publisher",related_name='books')
def __str__(self):
return '{},{},{}'.format(self.id,self.title,self.publisher)
#作者
class Author(models.Model):
'''作者数据表'''
id=models.AutoField(primary_key=True)
name=models.CharField(max_length=50,verbose_name='作者名称',null=False,unique=True)
detail=models.OneToOneField(to='AuthorDetail',null=True) #建立一对一关系表
def __str__(self):
return '{},{}'.format(self.id,self.name)
#手动创建作者和书多对多关联的第三张表,此时在orm层面没有书和作者的多对多关系
class Author2Book(models.Model):
'''作者与书籍的多对多关系'''
id=models.AutoField(primary_key=True)
#外键author
author_id=models.ForeignKey(to='Author')
#外键book
book_id=models.ForeignKey(to='Book')
#创建联合唯一,防止重复
class Meta:
unique_together=('author_id','book_id')
引申:如何进行查询?
import os
if __name__=='__main__':
os.environ.setdefault('DJANGO_SETTINGS_MODULE','booksys.settings')
import django
django.setup()
from app02.models import *
#1、查找作者id为1的关联的书
book_obj=Author2Book.objects.filter(author_id=2).values('book_id')
books=Book.objects.filter(id__in=book_obj)
print(books)
解析上面的代码:
1、先获取到多对多关联表当中作者id为2的对象
2、直接获取对象当中的book_id的value
3、将获取到的book_id放到Book表进行查询,使用id__in=xxx,查询出对应的书籍对象并打印出来
<QuerySet [<Book: 1,《战狼3》,1,邮电大学出版社,成都市动物园>]>
该方式的缺点是关联查询比较麻烦,因为没办法使用ORM提供的便利方法
第三种:自己创建第三张表,使用ORM 的ManyToManyFiled()
#书
class Book(models.Model):
'''书数据表'''
id=models.AutoField(primary_key=True)
title=models.CharField(max_length=50,verbose_name='书名',null=False,unique=True)
price=models.DecimalField(max_digits=5,decimal_places=2,default=99.99)
kucun=models.IntegerField(default=0)
maichu=models.IntegerField(default=0)
publisher=models.ForeignKey(to="Publisher",related_name='books')
def __str__(self):
return '{},{},{}'.format(self.id,self.title,self.publisher)
#作者
class Author(models.Model):
'''作者数据表'''
id=models.AutoField(primary_key=True)
name=models.CharField(max_length=50,verbose_name='作者名称',null=False,unique=True)
book=models.ManyToManyField(to='Book',through='Author2Book',through_fields=('author_id','book_id')) #通过自定义的关联表来建立orm的多对多关系
detail=models.OneToOneField(to='AuthorDetail',null=True) #建立一对一关系表
def __str__(self):
return '{},{}'.format(self.id,self.name)
#手动创建作者和书多对多关联的第三张表
class Author2Book(models.Model):
'''作者与书籍的多对多关系'''
id=models.AutoField(primary_key=True)
#外键author
author_id=models.ForeignKey(to='Author')
#外键book
book_id=models.ForeignKey(to='Book')
#创建联合唯一,防止重复
class Meta:
unique_together=('author_id','book_id')
book=models.ManyToManyField(to='Book',through='Author2Book',through_fields=('author_id','book_id'))
详细解析上面这个代码:
上面这段代码是在Author表中通过ManyToManyField创建多对多关系,然后through是指通过我们自定义的关系表建立关系,through_fields是指通过哪些字段建立关系,需要注意的是through_fields中字段的位置有顺序的区别,比如Author表可以通过author_id找到的,那么author_id放在最前面,其他表也是这个道理,如果顺序不对,系统会报错
引申:如何进行查询?
import os
if __name__=='__main__':
os.environ.setdefault('DJANGO_SETTINGS_MODULE','booksys.settings')
import django
django.setup()
from app03.models import *
#1、查找作者id为1的关联的书
books=Author.objects.get(id=1).book.all()
print(books)
<QuerySet [<Book: 1,《战狼3》,1,邮电大学出版社,成都市动物园>, <Book: 2,《春思》,2,北京大学附属中学出版社,成都市动物园>]>
虽然使用了第三张表,但是查询的用法和ORM自动创建的多对多关系的查询用法是一样的
该方式的缺点是没有add()和remove()方法
引申:我们用哪种?
看情况:
1. 如果你第三张表没有额外的字段,就用第一种
2. 如果你第三张表有额外的字段,就用第三种或第一种
碎片三、CSRF的简单用法
1、什么是csrf?
csrf就是跨站请求伪造,也被称为“One Click Attack”或者Session Riding,通常缩写为CSRF或者XSRF,是一种对网站的恶意利用。尽管听起来像跨站脚本(XSS),但它与XSS非常不同,XSS利用站点内的信任用户,而CSRF则通过伪装成受信任用户的请求来利用受信任的网站。与XSS攻击相比,CSRF攻击往往不大流行(因此对其进行防范的资源也相当稀少)和难以防范,所以被认为比XSS更具危险性。
2、钓鱼网站的页面和正经网站的页面对浏览器来说有什么区别? (页面是怎么来的?)
钓鱼网站的页面是由 钓鱼网站的服务端给你返回的
正经网站的网页是由 正经网站的服务端给你返回的
3、Django中内置了一个专门处理csrf问题的中间件
django.middleware.csrf.CsrfViewMiddleware
这个中间件做的事情:
第一是在render返回页面的时候,在页面中塞了一个隐藏的input标签,会有csrf的key和value值,当进行请求时一并提交给服务端,服务端进行校验,看是否是原生的网站发来的请求
用法:
我们在页面上 form表单 里面 写上 {% csrf_token %}
<input type="hidden" name="csrfmiddlewaretoken" value="8gthvLKulM7pqulNl2q3u46v1oEbKG7BSwg6qsHBv4zf0zj0UcbQmpbAdijqyhfE">
第二是当你提交POST数据的时候,它帮你做校验,如果校验不通过就拒绝这次请求
4、{% csrf_token %}一定要加在form表单当中才能生效