关于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使用MySQLdb访问mysql数据库的方法
Aug 03 Python
Python基本语法经典教程
Mar 11 Python
Python查询IP地址归属完整代码
Jun 21 Python
python 中的int()函数怎么用
Oct 17 Python
Python探索之ModelForm代码详解
Oct 26 Python
Python 内置函数进制转换的用法(十进制转二进制、八进制、十六进制)
Apr 30 Python
深入理解Django自定义信号(signals)
Oct 15 Python
python3爬虫获取html内容及各属性值的方法
Dec 17 Python
pandas DataFrame 删除重复的行的实现方法
Jan 29 Python
Django保护敏感信息的方法示例
May 09 Python
使用python实现滑动验证码功能
Aug 05 Python
PyQt 图解Qt Designer工具的使用方法
Aug 06 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 mysql索引问题
2008/06/07 PHP
PHP逐行输出(ob_flush与flush的组合)
2012/02/04 PHP
php中json_encode不兼容JSON_UNESCAPED_UNICODE的解决方案
2016/05/31 PHP
PHP使用preg_split()分割特殊字符(元字符等)的方法分析
2017/02/04 PHP
javascript分页代码(当前页码居中)
2012/09/20 Javascript
jquery获取radio值实例
2014/10/16 Javascript
在Node.js中使用HTTP上传文件的方法
2015/06/23 Javascript
JavaScript判断DIV内容是否为空的方法
2016/01/29 Javascript
js实现省份下拉菜单效果
2017/02/15 Javascript
JS去掉字符串前后空格或去掉所有空格的用法
2017/03/25 Javascript
jQuery实现简单漂亮的Nav导航菜单效果
2017/03/29 jQuery
vue表单绑定实现多选框和下拉列表的实例
2017/08/12 Javascript
使用jQuery实现两个div中按钮互换位置的实例代码
2017/09/21 jQuery
js实时监控文本框输入字数的实例代码
2018/01/18 Javascript
vuex 项目结构目录及一些简单配置介绍
2018/04/08 Javascript
简单的vuex 的使用案例笔记
2018/04/13 Javascript
Electron 如何调用本地模块的方法
2019/02/01 Javascript
通过实例解析JavaScript for in及for of区别
2020/06/15 Javascript
vue项目开启Gzip压缩和性能优化操作
2020/10/26 Javascript
微信小程序实现页面监听自定义组件的触发事件
2020/11/01 Javascript
[06:42]DOTA2每周TOP10 精彩击杀集锦vol.1
2014/06/25 DOTA
使用Python对IP进行转换的一些操作技巧小结
2015/11/09 Python
windows及linux环境下永久修改pip镜像源的方法
2016/11/28 Python
celery4+django2定时任务的实现代码
2018/12/23 Python
由面试题加深对Django的认识理解
2019/07/19 Python
pyinstaller将含有多个py文件的python程序做成exe
2020/04/29 Python
浅谈python3打包与拆包在函数的应用详解
2020/05/02 Python
python利用platform模块获取系统信息
2020/10/09 Python
Spartoo芬兰:欧洲最大的网上鞋店
2016/08/28 全球购物
网络艺术零售业的先驱者:artrepublic
2017/09/26 全球购物
MADE法国:提供原创设计师家具
2018/09/18 全球购物
党员年终民主评议的自我评价
2013/11/05 职场文书
母亲追悼会答谢词
2014/01/27 职场文书
企业法人代表证明书
2014/09/27 职场文书
2015年电话销售工作总结范文
2015/04/20 职场文书
郭明义电影观后感
2015/06/08 职场文书