关于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实现统计单词出现的个数
May 28 Python
python实现下载整个ftp目录的方法
Jan 17 Python
Python使用PIL模块生成随机验证码
Nov 21 Python
详解python3中tkinter知识点
Jun 21 Python
详解django的serializer序列化model几种方法
Oct 16 Python
关于python下cv.waitKey无响应的原因及解决方法
Jan 10 Python
基于python if 判断选择结构的实例详解
May 06 Python
Python实现微信小程序支付功能
Jul 25 Python
解析pip安装第三方库但PyCharm中却无法识别的问题及PyCharm安装第三方库的方法教程
Mar 10 Python
python处理写入数据代码讲解
Oct 22 Python
Django 实现图片上传和下载功能
Dec 31 Python
解决Jupyter-notebook不弹出默认浏览器的问题
Mar 30 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记录和读取JSON格式日志文件
2016/07/07 PHP
phpinfo()中Loaded Configuration File(none)的解决方法
2017/01/16 PHP
js右键菜单效果代码
2007/07/21 Javascript
用js实现随机返回数组的一个元素
2007/08/13 Javascript
JQuery 技巧和窍门整理(8个)
2010/04/22 Javascript
js querySelector和getElementById通过id获取元素的区别
2012/04/20 Javascript
Extjs4中Form的使用之本地hiddenfield
2013/11/26 Javascript
通过js为元素添加多项样式,浏览器全兼容写法
2014/08/30 Javascript
JavaScript实现拖拽网页内元素的方法
2015/04/15 Javascript
javascript中传统事件与现代事件
2015/06/23 Javascript
12个非常实用的JavaScript小技巧【推荐】
2016/05/18 Javascript
javascript运算符——逻辑运算符全面解析
2016/06/27 Javascript
每个程序员都需要学习 JavaScript 的7个理由小结
2016/09/03 Javascript
Validform表单验证总结篇
2016/10/31 Javascript
EasyUI为Numberbox添加blur事件的方法
2017/03/05 Javascript
详解mpvue小程序中怎么引入iconfont字体图标
2018/10/01 Javascript
bootstrap中的导航条实例代码详解
2019/05/20 Javascript
vue scroll滚动判断的实现(是否滚动到底部、滚动方向、滚动节流、获取滚动区域dom元素)
2020/06/11 Javascript
vue动态加载SVG文件并修改节点数据的操作代码
2020/08/17 Javascript
Vue实现购物车基本功能
2020/11/08 Javascript
Vue 实现拨打电话操作
2020/11/16 Javascript
[32:56]完美世界DOTA2联赛PWL S3 Rebirth vs CPG 第二场 12.11
2020/12/16 DOTA
python 正则式使用心得
2009/05/07 Python
Python实现拼接多张图片的方法
2014/12/01 Python
python字符串编码识别模块chardet简单应用
2015/06/15 Python
Python 实现一行输入多个值的方法
2018/04/21 Python
Python实现正弦信号的时域波形和频谱图示例【基于matplotlib】
2018/05/04 Python
Django 开发调试工具 Django-debug-toolbar使用详解
2019/07/23 Python
python GUI库图形界面开发之PyQt5浏览器控件QWebEngineView详细使用方法
2020/02/26 Python
django 扩展user用户字段inlines方式
2020/03/30 Python
python实现启动一个外部程序,并且不阻塞当前进程
2020/12/05 Python
分享30个新鲜的CSS3打造的精美绚丽效果(附演示下载)
2012/12/28 HTML / CSS
基于第一个PhoneGap(cordova)的应用详解
2013/05/03 HTML / CSS
搞笑的爱情检讨书
2014/10/01 职场文书
党员对照检查剖析材料
2014/10/13 职场文书
css3实现的加载动画效果
2021/04/07 HTML / CSS