关于Django外键赋值问题详解


Posted in Python onAugust 13, 2017

本文主要给大家介绍关于Django外键赋值的相关内容,分享出来供大家参考学习,在开始之前,我们先来看一段代码:

class Article(models.Model):
 title = models.CharField(max_length=1024, default='')
 ...
 def __str__(self):
  return 'Article pk:%d %s' % (self.pk, self.title[:30])

class ArticleContent(models.Model):
 article = cached_fields.OneToOneField(Article)
 ...

写代码的的时候,发现了一个很奇怪的现象,当我给一个instance的外键(以_id结尾)赋值(数字)的时候 ,这个外键对应的instance的值并不会改变。

In [44]: ac = ArticleContent.objects.get(article_id=14269)
In [45]: ac.article_id
Out[45]: 14269
In [46]: ac.article_id = 14266
In [47]: ac.save()
In [48]: ac.article
Out[48]: <Article: Article pk:14266 EC: Russia, Ukraine to Meet in>
In [49]: ac.article.pk
Out[49]: 14266

如上面的代码所示,为了找到答案,我翻了一下Django的源码:

django/db/models/fields/related_descriptors.py 
  def __get__(self, instance, cls=None):
   """
   Get the related instance through the forward relation.

   With the example above, when getting ``child.parent``:

   - ``self`` is the descriptor managing the ``parent`` attribute
   - ``instance`` is the ``child`` instance
   - ``cls`` is the ``Child`` class (we don't need it)
   """
   if instance is None:
    return self

   # The related instance is loaded from the database and then cached in
   # the attribute defined in self.cache_name. It can also be pre-cached
   # by the reverse accessor (ReverseOneToOneDescriptor).
   try:
    rel_obj = getattr(instance, self.cache_name)
   except AttributeError:
    val = self.field.get_local_related_value(instance)
    if None in val:
     rel_obj = None
    else:
     qs = self.get_queryset(instance=instance)
     qs = qs.filter(self.field.get_reverse_related_filter(instance))
     # Assuming the database enforces foreign keys, this won't fail.
     rel_obj = qs.get()
     # If this is a one-to-one relation, set the reverse accessor
     # cache on the related object to the current instance to avoid
     # an extra SQL query if it's accessed later on.
     if not self.field.remote_field.multiple:
      setattr(rel_obj, self.field.remote_field.get_cache_name(), instance)
    setattr(instance, self.cache_name, rel_obj)

   if rel_obj is None and not self.field.null:
    raise self.RelatedObjectDoesNotExist(
     "%s has no %s." % (self.field.model.__name__, self.field.name)
    )
   else:
    return rel_obj

注释得非常到位,当我们请求ac.article的时候,会先去检查对应的cache(在这里是_article_cache,感兴趣可以去看cache_name的生成规则,就是外键名前面加下划线,后面加cache)存不存在,如果不存在那么就进行数据库请求,请求完之后会保存到cache中。

我们再看看__set__ ,代码太长就不贴了(就在__get__方法下面)。除了给外键字段(article)赋值外,还会将pk字段(article_id,是lh_field.attname的值)设置为None,这样下次请求的时候就能拿到正确的值。

以上都是ForeignKey的Magic,而当我们给article_id赋值的时候,只是在给一个普通的attribute赋值而已,没有任何magic,不会清理对应外键的cache,这时候拿到的instance仍然是cache中原来的那个instance。

总结

以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作能带来一定的帮助,如果有疑问大家可以留言交流,谢谢大家对三水点靠木的支持。

Python 相关文章推荐
Python中的map、reduce和filter浅析
Apr 26 Python
Python SQLAlchemy基本操作和常用技巧(包含大量实例,非常好)
May 06 Python
Python中设置变量作为默认值时容易遇到的错误
Apr 03 Python
在VS Code上搭建Python开发环境的方法
Apr 06 Python
Python常见MongoDB数据库操作实例总结
Jul 24 Python
python实现单链表中删除倒数第K个节点的方法
Sep 28 Python
对python的bytes类型数据split分割切片方法
Dec 04 Python
详解从Django Rest Framework响应中删除空字段
Jan 11 Python
python多进程下实现日志记录按时间分割
Jul 22 Python
pandas的排序和排名的具体使用
Jul 31 Python
python利用dlib获取人脸的68个landmark
Nov 27 Python
python中的3种定义类方法
Nov 27 Python
python爬虫实战之最简单的网页爬虫教程
Aug 13 #Python
详解python中executemany和序列的使用方法
Aug 12 #Python
mysql 之通过配置文件链接数据库
Aug 12 #Python
python+selenium开发环境搭建图文教程
Aug 11 #Python
Python实现的递归神经网络简单示例
Aug 11 #Python
Python调用系统底层API播放wav文件的方法
Aug 11 #Python
Django 导出 Excel 代码的实例详解
Aug 11 #Python
You might like
php初学者写及时补给skype用户充话费的小程序
2008/11/02 PHP
PHP的Yii框架中使用数据库的配置和SQL操作实例教程
2016/03/17 PHP
Yii2增加验证码步骤详解
2016/04/25 PHP
PHP文件操作简单介绍及函数汇总
2020/12/11 PHP
jquery Firefox3.5中操作select的问题
2009/07/10 Javascript
层序遍历在ExtJs的TreePanel中的应用
2009/10/16 Javascript
终于解决了IE8不支持数组的indexOf方法
2013/04/03 Javascript
JavaScript开发人员的10个关键习惯小结
2014/12/05 Javascript
angularJS 中$attrs方法使用指南
2015/02/09 Javascript
JS实现的仿淘宝交易倒计时效果
2015/11/27 Javascript
轻松实现Bootstrap图片轮播
2020/04/20 Javascript
利用JS判断字符串是否含有数字与特殊字符的方法小结
2016/11/25 Javascript
nodejs个人博客开发第四步 数据模型
2017/04/12 NodeJs
详解基于node的前端项目编译时内存溢出问题
2017/08/01 Javascript
JS如何实现在页面上快速定位(锚点跳转问题)
2017/08/14 Javascript
BootStrap点击保存后实现模态框自动关闭的思路(模态框)
2017/09/26 Javascript
es6在react中的应用代码解析
2017/11/08 Javascript
使用JS获取SessionStorage的值
2018/01/12 Javascript
fetch 如何实现请求数据
2018/12/20 Javascript
vue中touch和click共存的解决方式
2020/07/28 Javascript
vue pages 多入口项目 + chainWebpack 全局引用缩写说明
2020/09/21 Javascript
Python通过90行代码搭建一个音乐搜索工具
2015/07/29 Python
Python运维自动化之nginx配置文件对比操作示例
2018/08/29 Python
解决Pycharm 包已经下载,但是运行代码提示找不到模块的问题
2019/08/31 Python
Python数据分析模块pandas用法详解
2019/09/04 Python
Softmax函数原理及Python实现过程解析
2020/05/22 Python
使用CSS3编写灰阶滤镜来制作黑白照片效果的方法
2016/05/09 HTML / CSS
详解Canvas事件绑定
2018/06/27 HTML / CSS
从当地商店送来的杂货:Instacart
2018/08/19 全球购物
成功经营餐厅的创业计划书范文
2013/12/26 职场文书
物业招聘计划书
2014/01/10 职场文书
劲霸男装广告词
2014/03/21 职场文书
低碳环保倡议书
2014/04/14 职场文书
领导党的群众路线教育实践活动个人对照检查材料
2014/09/23 职场文书
作风转变年心得体会
2014/10/22 职场文书
创业计划书之零食店(进口)
2019/09/24 职场文书