关于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计算三维矢量幅度的方法
Jun 15 Python
深入理解Python变量与常量
Jun 02 Python
用python的requests第三方模块抓取王者荣耀所有英雄的皮肤实例
Dec 14 Python
django settings.py 配置文件及介绍
Jul 15 Python
Python列表的切片实例讲解
Aug 20 Python
python+selenium 点击单选框-radio的实现方法
Sep 03 Python
基于python cut和qcut的用法及区别详解
Nov 22 Python
基于python及pytorch中乘法的使用详解
Dec 27 Python
解决pycharm中opencv-python导入cv2后无法自动补全的问题(不用作任何文件上的修改)
Mar 05 Python
Python任务调度模块APScheduler使用
Apr 15 Python
django 解决model中类写不到数据库中,数据库无此字段的问题
May 20 Python
Python中time标准库的使用教程
Apr 13 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
Codeigniter检测表单post数据的方法
2015/03/21 PHP
PHP结合jQuery插件ajaxFileUpload实现异步上传文件实例
2020/08/17 PHP
thinkPHP框架自动填充原理与用法分析
2018/04/03 PHP
JS 毫秒转时间示例代码
2013/09/22 Javascript
jQuery探测位置的提示弹窗(toolTip box)详细解析
2013/11/14 Javascript
用javascript为页面添加天气显示实现思路及代码
2013/12/02 Javascript
JS计算网页停留时间代码
2014/04/28 Javascript
浅析JavaScript函数的调用模式
2016/08/10 Javascript
基于BootstrapValidator的Form表单验证(24)
2016/12/12 Javascript
JavaScript实现图像模糊化的方法实例
2017/01/15 Javascript
Node.js之网络通讯模块实现浅析
2017/04/01 Javascript
layer实现关闭弹出层刷新父界面功能详解
2017/11/15 Javascript
详解webpack 打包文件体积过大解决方案(code splitting)
2018/04/10 Javascript
微信小程序登录时如何获取input框中的内容
2019/12/04 Javascript
浅谈Vue.use到底是什么鬼
2020/01/21 Javascript
js实现拾色器插件(ColorPicker)
2020/05/21 Javascript
Python基于有道实现英汉字典功能
2015/07/25 Python
Python黑魔法@property装饰器的使用技巧解析
2016/06/16 Python
Windows下的Python 3.6.1的下载与安装图文详解(适合32位和64位)
2018/02/21 Python
Python2实现的图片文本识别功能详解
2018/07/11 Python
Python3.6实现带有简单界面的有道翻译小程序
2019/04/16 Python
python用quad、dblquad实现一维二维积分的实例详解
2019/11/20 Python
python中如何使用insert函数
2020/01/09 Python
pandas分批读取大数据集教程
2020/06/06 Python
HTML5新特性之用SVG绘制微信logo
2016/02/03 HTML / CSS
亚马逊新加坡官方网站:Amazon.sg
2020/03/25 全球购物
中科创达面试题
2016/12/28 面试题
自我评价怎么写好呢?
2013/12/05 职场文书
中专生自我鉴定
2013/12/17 职场文书
大学生关于奋斗的演讲稿
2014/01/09 职场文书
工作说明书格式
2014/07/29 职场文书
幼儿园五一劳动节活动总结
2015/02/09 职场文书
2015年初中生自我评价范文
2015/03/03 职场文书
市场营销计划书
2019/04/24 职场文书
求职自荐信该如何书写?
2019/06/24 职场文书
你对自己的信用报告有过了解吗?
2019/07/09 职场文书