Pycharm开发Django项目外键和表关系

mb60090aff439bf 2021-10-26 10:14:52
编程语言 Python 数据 字段 一对一

外键和表关系

外键:

在​​MySQL​​中,表有两种引擎,一种是​​InnoDB​​,另外一种是​​myisam​​。如果使用的是​​InnoDB​​引擎,是支持外键约束的。外键的存在使得​​ORM​​框架在处理表关系的时候异常的强大。因此这里我们首先来介绍下外键在​​Django​​中的使用。

类定义为​​class ForeignKey(to,on_delete,**options)​​。第一个参数是引用的是哪个模型,第二个参数是在使用外键引用的模型数据被删除了,这个字段该如何处理,比如有​​CASCADE​​、​​SET_NULL​​等。这里以一个实际案例来说明。比如有一个​​User​​和一个​​Article​​两个模型。一个​​User​​可以发表多篇文章,一个​​Article​​只能有一个​​Author​​,并且通过外键进行引用。那么相关的示例代码如下:

class User(models.Model):
username = models.CharField(max_length=20)
password = models.CharField(max_length=100)


class Article(models.Model):
title = models.CharField(max_length=100)
content = models.TextField()

author = models.ForeignKey("User",on_delete=models.CASCADE)
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.

以上使用​​ForeignKey​​来定义模型之间的关系。即在​​article​​的实例中可以通过​​author​​属性来操作对应的​​User​​模型。这样使用起来非常的方便。示例代码如下:

article = Article(title='abc',content='123')
author = User(username='张三',password='111111')
article.author = author
article.save()

# 修改article.author上的值
article.author.username = '李四'
article.save()
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.

为什么使用了​​ForeignKey​​后,就能通过​​author​​访问到对应的​​user​​对象呢。因此在底层,​​Django​​为​​Article​​表添加了一个​​属性名_id​​的字段(比如author的字段名称是author_id),这个字段是一个外键,记录着对应的作者的主键。以后通过​​article.author​​访问的时候,实际上是先通过​​author_id​​找到对应的数据,然后再提取​​User​​表中的这条数据,形成一个模型。

如果想要引用另外一个​​app​​的模型,那么应该在传递​​to​​参数的时候,使用​​app.model_name​​进行指定。以上例为例,如果​​User​​和​​Article​​不是在同一个​​app​​中,那么在引用的时候的示例代码如下:

# User模型在user这个app中
class User(models.Model):
username = models.CharField(max_length=20)
password = models.CharField(max_length=100)

# Article模型在article这个app中
class Article(models.Model):
title = models.CharField(max_length=100)
content = models.TextField()

author = models.ForeignKey("user.User",on_delete=models.CASCADE)
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.

如果模型的外键引用的是本身自己这个模型,那么​​to​​参数可以为​​'self'​​,或者是这个模型的名字。在论坛开发中,一般评论都可以进行二级评论,即可以针对另外一个评论进行评论,那么在定义模型的时候就需要使用外键来引用自身。示例代码如下:

class Comment(models.Model):
content = models.TextField()
origin_comment = models.ForeignKey('self',on_delete=models.CASCADE,null=True)
# 或者
# origin_comment = models.ForeignKey('Comment',on_delete=models.CASCADE,null=True)
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.

外键删除操作:

如果一个模型使用了外键。那么在对方那个模型被删掉后,该进行什么样的操作。可以通过​​on_delete​​来指定。可以指定的类型如下:

  1. ​CASCADE​​:级联操作。如果外键对应的那条数据被删除了,那么这条数据也会被删除。
  2. ​PROTECT​​:受保护。即只要这条数据引用了外键的那条数据,那么就不能删除外键的那条数据。
  3. ​SET_NULL​​:设置为空。如果外键的那条数据被删除了,那么在本条数据上就将这个字段设置为空。如果设置这个选项,前提是要指定这个字段可以为空。
  4. ​SET_DEFAULT​​:设置默认值。如果外键的那条数据被删除了,那么本条数据上就将这个字段设置为默认值。如果设置这个选项,前提是要指定这个字段一个默认值。
  5. ​SET()​​:如果外键的那条数据被删除了。那么将会获取​​SET​​函数中的值来作为这个外键的值。​​SET​​函数可以接收一个可以调用的对象(比如函数或者方法),如果是可以调用的对象,那么会将这个对象调用后的结果作为值返回回去。
  6. ​DO_NOTHING​​:不采取任何行为。一切全看数据库级别的约束。

以上这些选项只是Django级别的,数据级别依旧是RESTRICT!


表关系:

表之间的关系都是通过外键来进行关联的。而表之间的关系,无非就是三种关系:一对一、一对多(多对一)、多对多等。以下将讨论一下三种关系的应用场景及其实现方式。

一对多:

  1. 应用场景:比如文章和作者之间的关系。一个文章只能由一个作者编写,但是一个作者可以写多篇文章。文章和作者之间的关系就是典型的多对一的关系。
  2. 实现方式:一对多或者多对一,都是通过ForeignKey来实现的。还是以文章和作者的案例进行讲解。
    class User(models.Model): username = models.CharField(max_length= 20) password = models.CharField(max_length= 100) class Article(models.Model): title = models.CharField(max_length= 100) content = models.TextField() author = models.ForeignKey( "User",on_delete=models.CASCADE)
    那么以后在给Article对象指定author,就可以使用以下代码来完成:
    article = Article(title='abc',content='123')author = User(username= 'zhiliao',password='111111') # 要先保存到数据库中 author.save() article.author = author article.save()
    并且以后如果想要获取某个用户下所有的文章,可以通过article_set来实现。示例代码如下:
    user = User.objects.first() # 获取第一个用户写的所有文章 articles = user.article_set.all() for article in articles: print(article)

一对一:

  1. 应用场景:比如一个用户表和一个用户信息表。在实际网站中,可能需要保存用户的许多信息,但是有些信息是不经常用的。如果把所有信息都存放到一张表中可能会影响查询效率,因此可以把用户的一些不常用的信息存放到另外一张表中我们叫做UserExtension。但是用户表User和用户信息表UserExtension就是典型的一对一了。
  2. 实现方式:Django为一对一提供了一个专门的Field叫做OneToOneField来实现一对一操作。示例代码如下:
    class User(models.Model): username = models.CharField(max_length= 20) password = models.CharField(max_length= 100) class UserExtension(models.Model): birthday = models.DateTimeField(null= True) school = models.CharField(blank= True,max_length=50) user = models.OneToOneField( "User", on_delete=models.CASCADE)
    UserExtension模型上增加了一个一对一的关系映射。其实底层是在UserExtension这个表上增加了一个user_id,来和user表进行关联,并且这个外键数据在表中必须是唯一的,来保证一对一。

多对多:

  1. 应用场景:比如文章和标签的关系。一篇文章可以有多个标签,一个标签可以被多个文章所引用。因此标签和文章的关系是典型的多对多的关系。
  2. 实现方式:Django为这种多对多的实现提供了专门的Field。叫做ManyToManyField。还是拿文章和标签为例进行讲解。示例代码如下:
    class Article(models.Model): title = models.CharField(max_length= 100) content = models.TextField() tags = models.ManyToManyField( "Tag",related_name="articles") class Tag(models.Model): name = models.CharField(max_length= 50)
    在数据库层面,实际上Django是为这种多对多的关系建立了一个中间表。这个中间表分别定义了两个外键,引用到articletag两张表的主键。

related_name和related_query_name:

related_name:

还是以​​User​​和​​Article​​为例来进行说明。如果一个​​article​​想要访问对应的作者,那么可以通过​​author​​来进行访问。但是如果有一个​​user​​对象,想要通过这个​​user​​对象获取所有的文章,该如何做呢?这时候可以通过​​user.article_set​​来访问,这个名字的规律是​​模型名字小写_set​​。示例代码如下:

user = User.objects.get(name='张三')
user.article_set.all()
  • 1.
  • 2.

如果不想使用​​模型名字小写_set​​的方式,想要使用其他的名字,那么可以在定义模型的时候指定​​related_name​​。示例代码如下:

class Article(models.Model):
title = models.CharField(max_length=100)
content = models.TextField()
# 传递related_name参数,以后在方向引用的时候使用articles进行访问
author = models.ForeignKey("User",on_delete=models.SET_NULL,null=True,related_name='articles')
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.

以后在方向引用的时候。使用​​articles​​可以访问到这个作者的文章模型。示例代码如下:

user = User.objects.get(name='张三')
user.articles.all()
  • 1.
  • 2.

如果不想使用反向引用,那么可以指定​​related_name='+'​​。示例代码如下:

class Article(models.Model):
title = models.CharField(max_length=100)
content = models.TextField()
# 传递related_name参数,以后在方向引用的时候使用articles进行访问
author = models.ForeignKey("User",on_delete=models.SET_NULL,null=True,related_name='+')
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.

以后将不能通过​​user.article_set​​来访问文章模型了。

related_query_name:

在查找数据的时候,可以使用​​filter​​进行过滤。使用​​filter​​过滤的时候,不仅仅可以指定本模型上的某个属性要满足什么条件,还可以指定相关联的模型满足什么属性。比如现在想要获取写过标题为​​abc​​的所有用户,那么可以这样写:

users = User.objects.filter(article__title='abc')
  • 1.

如果你设置了​​related_name​​为​​articles​​,因为反转的过滤器的名字将使用​​related_name​​的名字,那么上例代码将改成如下:

users = User.objects.filter(articles__title='abc')
  • 1.

可以通过​​related_query_name​​将查询的反转名字修改成其他的名字。比如​​article​​。示例代码如下:

class Article(models.Model):
title = models.CharField(max_length=100)
content = models.TextField()
# 传递related_name参数,以后在方向引用的时候使用articles进行访问
author = models.ForeignKey("User",on_delete=models.SET_NULL,null=True,related_name='articles',related_query_name='article')
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.

那么在做反向过滤查找的时候就可以使用以下代码:

users = User.objects.filter(article__title='abc')
  • 1.


版权声明
本文为[mb60090aff439bf]所创,转载请带上原文链接,感谢
https://blog.51cto.com/u_15089909/4316422

  1. L'implémentation Python lit simplement le contenu d'Excel et signale les erreurs
  2. 用Python定义一个函数,接收n个数字,求这些参数数字的和
  3. Définissez une fonction en python, recevez n nombres et additionnez ces nombres de paramètres
  4. 上电Python写文件后,再断电后导致文件内容丢失
  5. 上電Python寫文件後,再斷電後導致文件內容丟失
  6. Une fois que Python est allumé pour écrire des fichiers, le contenu des fichiers est perdu après une panne de courant
  7. python套接字编程报错:ConnectionResetError: [WinError 10054] 远程主机强迫关闭了一个现有的连接。
  8. 【Python从入门到精通】(二)怎么运行Python呢?有哪些好的开发工具(PyCharm)
  9. 【Python从入门到精通】(二)怎么运行Python呢?有哪些好的开发工具(PyCharm)
  10. Python语法1
  11. 2018年度最受推荐的10本Python书籍(初学者必看)
  12. Les 10 livres Python les plus recommandés en 2018 (obligatoire pour les débutants)
  13. Syntaxe Python 1
  14. Python语法1
  15. 在python 运行celery时候 AttributeError: 'NoneType' object has no attribute 'Redis'错误
  16. Attributeerror: 'nonetype' Object has no attribute 'redis' Error when Celery is running in Python
  17. Syntaxe Python 1
  18. Python celery is a plug-in that focuses on distributed asynchronous task processing and task scheduling!
  19. Python celery is a plug-in that focuses on distributed asynchronous task processing and task scheduling!
  20. 在python,使用scrapy爬虫框架
  21. It's time for everyone to see your blog written in Django (including deployment tutorial video)
  22. Python扩展速记符 要求用for循环,if语句
  23. Python擴展速記符 要求用for循環,if語句
  24. Le sténographe d'extension Python nécessite une boucle pour, si instruction
  25. Python+人工智能就业班v5.0wumi
  26. python编程技术的题目,希望能得到解答
  27. Pandas determines the header row dynamically
  28. 关于#python#的问题:模拟登陆后能获取到cookie,就是cookie一天就过期
  29. pandas为dataframe添加新的数据行(rows)、在dataframe后面纵向添加一行数据(数据为列表list形式)、列有不匹配将会使用NA值进行填补
  30. pandas使用组合条件筛选、过滤数据行
  31. 热烈祝贺1024,求解Python3.10闪退问题
  32. Python基础题练习题库有没呢?
  33. python构建神经网络,正向和反向传播
  34. python爬虫输入数字翻页才成功,用变量代替不成功,为什么?
  35. 【Python 爬虫】 2、HTTP基本原理
  36. 【Python 爬虫】 1、爬虫基础概念
  37. Python中如何用find函数计数?
  38. 一文搞懂Python装饰器
  39. python数据结构之递归
  40. 关于#python#的问题:为什么这个open函数会报错
  41. Python:多输入数字求和(Python 程序控制结构)
  42. python忽略警告
  43. Python多维数组问题(编写程序统计成绩)
  44. 一步一步展示并总结Python的异常【建议收藏】
  45. Python中奇葩的round函数!
  46. 总结一下Python的模块加载解析
  47. 保姆级指导给Python库创建桌面快捷方式【赶紧收藏】
  48. 多图速成Python基础语法下篇【万字建议收藏】
  49. Python 命令行工具辅助getopt使用解析!
  50. 【python种子项目ppc】保姆级别指导给项目添加测试
  51. 【python种子项目ppc】一行代码生成项目与开发详细指导
  52. 保姆级教程带你开发优质的Python库之下篇【种子项目】
  53. 保姆级教程带你开发优质的Python库之中篇【命令行发行】
  54. 保姆级教程带你开发优质的Python库之上篇【建议收藏】
  55. python列表自动计算总分程序
  56. 某企业职工的月薪问题python 求解 不知道自己哪里写错了
  57. Python中外部函数对class类中的属性的调用
  58. 朋友股票亏惨了,我一怒用Python爬取了证券最新数据
  59. 习题8和9怎么写(Python基础)
  60. python数据分析,求任务4,5