关于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转换摩斯密码示例
Feb 16 Python
利用python微信库itchat实现微信自动回复功能
May 18 Python
50行Python代码实现人脸检测功能
Jan 23 Python
Python3.5 创建文件的简单实例
Apr 26 Python
Python 读写文件的操作代码
Sep 20 Python
使用Scrapy爬取动态数据
Oct 21 Python
在mac下查找python包存放路径site-packages的实现方法
Nov 06 Python
python使用PIL实现多张图片垂直合并
Jan 15 Python
python 中的列表生成式、生成器表达式、模块导入
Jun 19 Python
python使用mitmproxy抓取浏览器请求的方法
Jul 02 Python
详解python中的生成器、迭代器、闭包、装饰器
Aug 22 Python
PyCharm设置Ipython交互环境和宏快捷键进行数据分析图文详解
Apr 23 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中文字符截取防乱码
2008/03/28 PHP
Sublime里直接运行PHP配置方法
2014/11/28 PHP
PHP的mysqli_stmt_init()函数讲解
2019/01/24 PHP
javascript 全选与全取消功能的实现代码
2012/12/23 Javascript
Chrome下ifame父窗口调用子窗口的问题示例探讨
2014/03/17 Javascript
jQuery中阻止冒泡事件的方法介绍
2014/04/12 Javascript
javascript获取dom的下一个节点方法
2014/09/05 Javascript
JavaScript中number转换成string介绍
2014/12/31 Javascript
JQuery包裹DOM节点的方法
2015/06/11 Javascript
jQuery操作复选框(CheckBox)的取值赋值实现代码
2017/01/10 Javascript
jQuery弹出窗口简单实现代码
2017/03/09 Javascript
Angularjs中ng-repeat的简单实例
2017/08/25 Javascript
使用Vue父子组件通信实现todolist的功能示例代码
2019/04/11 Javascript
详解解决小程序中webview页面多层history返回问题
2019/08/20 Javascript
vuex实现像调用模板方法一样调用Mutations方法
2019/11/06 Javascript
JS array数组检测方式解析
2020/05/19 Javascript
JavaScript实现图片合成下载的示例
2020/11/19 Javascript
[32:36]完美世界DOTA2联赛PWL S3 LBZS vs CPG 第二场 12.12
2020/12/16 DOTA
Python实现的数据结构与算法之快速排序详解
2015/04/22 Python
对numpy中轴与维度的理解
2018/04/18 Python
python3利用ctypes传入一个字符串类型的列表方法
2019/02/12 Python
在pytorch中为Module和Tensor指定GPU的例子
2019/08/19 Python
在win64上使用bypy进行百度网盘文件上传功能
2020/01/02 Python
打包PyQt5应用时的注意事项
2020/02/14 Python
利用pyecharts读取csv并进行数据统计可视化的实现
2020/04/17 Python
浅谈numpy中np.array()与np.asarray的区别以及.tolist
2020/06/03 Python
Python实现树莓派摄像头持续录像并传送到主机的步骤
2020/11/30 Python
优秀学生自我鉴定范例
2013/12/18 职场文书
房产公证书范本
2014/04/10 职场文书
《果园机器人》教学反思
2014/04/13 职场文书
电钳工人个人求职信
2014/05/10 职场文书
保洁公司服务承诺书
2014/05/28 职场文书
教师学习三严三实心得体会
2014/10/13 职场文书
个人整改措施落实情况汇报
2014/10/29 职场文书
Javascript中的解构赋值语法详解
2021/04/02 Javascript
MySQL 十大常用字符串函数详解
2021/06/30 MySQL