关于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列表list保留顺序去重的实例
Dec 14 Python
Python实现二维曲线拟合的方法
Dec 29 Python
快速排序的四种python实现(推荐)
Apr 03 Python
基于Python打造账号共享浏览器功能
May 30 Python
python实现发送form-data数据的方法详解
Sep 27 Python
Python Gluon参数和模块命名操作教程
Dec 18 Python
Python 序列化和反序列化库 MarshMallow 的用法实例代码
Feb 25 Python
python列表删除和多重循环退出原理详解
Mar 26 Python
解决reload(sys)后print失效的问题
Apr 25 Python
python实现mean-shift聚类算法
Jun 10 Python
Python提取视频中图片的示例(按帧、按秒)
Oct 22 Python
教你使用Python获取QQ音乐某个歌手的歌单
Apr 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 函数中使用static的说明
2012/06/01 PHP
CodeIgniter框架提示Disallowed Key Characters的解决办法
2014/04/21 PHP
ThinkPHP3.1新特性之查询条件预处理简介
2014/06/19 PHP
PHP字符串比较函数strcmp()和strcasecmp()使用总结
2014/11/19 PHP
PHP判断IP并转跳到相应城市分站的方法
2015/03/25 PHP
php编写的一个E-mail验证类
2015/03/25 PHP
php正则表达式学习笔记
2015/11/13 PHP
PHP加密解密类实例代码
2016/07/20 PHP
PHP用函数嵌入网站访问量计数器
2017/10/27 PHP
js右键菜单效果代码
2007/07/21 Javascript
javascript 验证日期的函数
2010/03/18 Javascript
script标签的 charset 属性使用说明
2010/12/04 Javascript
收集的10个免费的jQuery相册
2011/02/26 Javascript
放弃用你的InnerHTML来输出HTML吧 jQuery Tmpl不详细讲解
2013/04/20 Javascript
js 获取屏幕各种宽高的方法(浏览器兼容)
2013/05/15 Javascript
jQuery中hide()方法用法实例
2014/12/24 Javascript
JavaScript中的原始值和复杂值
2016/01/07 Javascript
jQuery基础知识点总结(DOM操作)
2016/06/01 Javascript
AngularJS动态绑定HTML的方法分析
2016/11/07 Javascript
分分钟玩转Vue.js组件(二)
2017/03/01 Javascript
JavaScript实现的文本框placeholder提示文字功能示例
2018/07/25 Javascript
js实现延迟加载的几种方法详解
2019/01/19 Javascript
VUEX-action可以修改state吗
2019/11/19 Javascript
Vue性能优化的方法
2020/07/30 Javascript
python Shapely使用指南详解
2020/02/18 Python
python实现批量命名照片
2020/06/18 Python
女性时尚网购:Chic Me
2019/07/30 全球购物
俄罗斯电子产品、计算机和家用电器购物网站:OLDI
2019/10/27 全球购物
优纳科技软件测试面试题
2012/05/15 面试题
护士见习期自我鉴定
2014/02/08 职场文书
创先争优标语
2014/06/27 职场文书
工作表扬信
2015/01/17 职场文书
幼儿教师小班个人总结
2015/02/05 职场文书
2016大学生求职自荐信范文
2016/01/28 职场文书
索尼ICF-5900W收音机测评
2022/04/24 无线电
Web应用开发TypeScript使用详解
2022/05/25 Javascript