关于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中map、any、all函数用法分析
Apr 21 Python
Python实现MySQL操作的方法小结【安装,连接,增删改查等】
Jul 12 Python
Python探索之创建二叉树
Oct 25 Python
对pandas的算术运算和数据对齐实例详解
Dec 22 Python
Python语言进阶知识点总结
May 28 Python
python打包exe开机自动启动的实例(windows)
Jun 28 Python
python实现对列表中的元素进行倒序打印
Nov 23 Python
Python内置方法实现字符串的秘钥加解密(推荐)
Dec 09 Python
15行Python代码实现免费发送手机短信推送消息功能
Feb 27 Python
python 三种方法提取pdf中的图片
Feb 07 Python
Python上下文管理器Content Manager
Jun 26 Python
Python基础 括号()[]{}的详解
Nov 07 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 CURL 多线程操作代码实例
2015/05/13 PHP
php中实现用数组妩媚地生成要执行的sql语句
2015/07/10 PHP
PHP crc32()函数讲解
2019/02/14 PHP
使用composer安装使用thinkphp6.0框架问题【视频教程】
2019/10/01 PHP
PHP使用gearman进行异步的邮件或短信发送操作详解
2020/02/27 PHP
asp 的 分词实现代码
2007/05/24 Javascript
Javascript 圆角div的实现代码
2009/10/15 Javascript
De facto standard 世界上不可思议的事实标准
2010/08/29 Javascript
基于jQuery的一个扩展form序列化到json对象
2010/12/09 Javascript
Javascript 面向对象编程(coolshell)
2012/03/18 Javascript
JQuery伸缩导航练习示例
2013/11/13 Javascript
Javascript基础教程之数据类型 (字符串 String)
2015/01/18 Javascript
JavaScript中的包装对象介绍
2015/01/27 Javascript
详解Vue生命周期的示例
2017/03/10 Javascript
使用React手写一个对话框或模态框的方法示例
2019/04/25 Javascript
JQuery常见节点操作实例分析
2019/05/15 jQuery
layui实现数据分页功能(ajax异步)
2019/07/27 Javascript
[03:49]DOTA2英雄基础教程 光之守卫
2014/01/14 DOTA
[01:58]DOTA2上海特级锦标赛现场采访:RTZ这个ID到底好不好
2016/03/25 DOTA
Python原始字符串(raw strings)用法实例
2014/10/13 Python
python杀死一个线程的方法
2015/09/06 Python
Python实现自动添加脚本头信息的示例代码
2016/09/02 Python
浅谈pandas中DataFrame关于显示值省略的解决方法
2018/04/08 Python
python操作excel的包(openpyxl、xlsxwriter)
2018/06/11 Python
Python中函数参数匹配模型详解
2019/06/09 Python
python爬虫分布式获取数据的实例方法
2020/11/26 Python
快速解决pymongo操作mongodb的时区问题
2020/12/05 Python
详解HTML5新增标签
2017/11/27 HTML / CSS
主题酒店策划书
2014/01/28 职场文书
学雷锋志愿者活动方案
2014/08/21 职场文书
2014年妇幼保健工作总结
2014/12/08 职场文书
学校捐书倡议书
2015/04/27 职场文书
学校财务管理制度
2015/08/04 职场文书
奖学金申请个人主要事迹材料
2015/11/04 职场文书
人身损害赔偿协议书
2016/03/22 职场文书
关于感恩的歌曲整理(8首)
2019/08/14 职场文书