关于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爬虫的基本写法
Jan 08 Python
Flask框架的学习指南之开发环境搭建
Nov 20 Python
纯python实现机器学习之kNN算法示例
Mar 01 Python
python实现批量按比例缩放图片效果
Mar 30 Python
python实现黑客字幕雨效果
Jun 21 Python
python 反编译exe文件为py文件的实例代码
Jun 27 Python
Python 实现输入任意多个数,并计算其平均值的例子
Jul 16 Python
selenium+PhantomJS爬取豆瓣读书
Aug 26 Python
python 求定积分和不定积分示例
Nov 20 Python
Python转换itertools.chain对象为数组的方法
Feb 07 Python
python剪切视频与合并视频的实现
Mar 03 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模板原理讲解
2013/11/13 PHP
PHP实现动态柱状图改进版
2015/03/30 PHP
PHP 爬取网页的主要方法
2018/07/13 PHP
php进程daemon化的正确实现方法
2018/09/06 PHP
laravel框架 api自定义全局异常处理方法
2019/10/11 PHP
Laravel 修改验证异常的响应格式实例代码详解
2020/05/25 PHP
Prototype1.6 JS 官方下载地址
2007/11/30 Javascript
最简单的jQuery程序 入门者学习
2009/07/09 Javascript
js隐藏与显示回到顶部按钮及window.onscroll事件应用
2013/01/25 Javascript
jQuery中[attribute^=value]选择器用法实例
2014/12/31 Javascript
JS模仿腾讯图片站的图片翻页按钮效果完整实例
2016/06/21 Javascript
Node.js设置CORS跨域请求中多域名白名单的方法
2017/03/28 Javascript
微信小程序中的swiper组件详解
2017/04/14 Javascript
详解如何在vue中使用sass
2017/06/21 Javascript
基于JavaScript实现表格滚动分页
2017/11/22 Javascript
vue.js系列中的vue-fontawesome使用
2018/02/10 Javascript
关于vue表单提交防双/多击的例子
2019/10/31 Javascript
Vue页面刷新记住页面状态的实现
2019/12/27 Javascript
微信小程序自定义纯净模态框(弹出框)的实例代码
2020/03/09 Javascript
jQuery HTML css()方法与css类实例详解
2020/05/20 jQuery
ES2020系列之空值合并运算符 '??'
2020/07/22 Javascript
Vant 在vue-cli 4.x中按需加载操作
2020/11/05 Javascript
[01:14:31]Secret vs VG 2018国际邀请赛淘汰赛BO3 第一场 8.23
2018/08/24 DOTA
python 打印对象的所有属性值的方法
2016/09/11 Python
Python实现文件信息进行合并实例代码
2018/01/17 Python
css3实现wifi信号逐渐增强效果实例
2017/08/09 HTML / CSS
迪士尼法国在线商店:shopDisney FR
2020/12/03 全球购物
Unix如何添加新的用户
2014/08/20 面试题
大学生求职简历的自我评价
2013/10/14 职场文书
餐厅采购员岗位职责
2014/03/06 职场文书
三分钟英语演讲稿
2014/04/24 职场文书
保护环境建议书100字
2014/05/13 职场文书
全陪导游词
2015/02/04 职场文书
校车安全管理责任书
2015/05/11 职场文书
会计试用期工作总结2015
2015/05/28 职场文书
在Oracle表中进行关键词搜索的过程
2022/06/10 Oracle