关于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批量制作雷达图的实现方法
Jul 26 Python
JSONLINT:python的json数据验证库实例解析
Nov 28 Python
Python使用matplotlib实现的图像读取、切割裁剪功能示例
Apr 28 Python
对Python Class之间函数的调用关系详解
Jan 23 Python
Python3.5实现的罗马数字转换成整数功能示例
Feb 25 Python
Python3批量生成带logo的二维码方法
Jun 24 Python
Python 解析pymysql模块操作数据库的方法
Feb 18 Python
python GUI库图形界面开发之PyQt5中QMainWindow, QWidget以及QDialog的区别和选择
Feb 26 Python
Python GUI编程学习笔记之tkinter控件的介绍及基本使用方法详解
Mar 30 Python
python接入支付宝的实例操作
Jul 20 Python
python基于opencv实现人脸识别
Jan 04 Python
Python爬虫之用Xpath获取关键标签实现自动评论盖楼抽奖(二)
Jun 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
编写漂亮的代码 - 将后台程序与前端程序分开
2008/04/23 PHP
PHP 使用 Imagick 裁切/生成缩略图/添加水印自动检测和处理 GIF
2016/02/19 PHP
PHP线程的内存回收问题
2016/07/08 PHP
laravel创建类似ThinPHP中functions.php的全局函数
2016/11/26 PHP
Javascript公共脚本库系列(一): 弹出层脚本
2011/02/24 Javascript
判定是否原生方法的JS代码
2013/11/12 Javascript
jQuery实现数字加减效果汇总
2014/12/16 Javascript
JavaScript在浏览器标题栏上显示当前日期和时间的方法
2015/03/19 Javascript
JavaScript中对DOM节点的访问、创建、修改、删除
2015/11/16 Javascript
javascript实现拖动元素交换位置
2015/11/29 Javascript
js给table赋值的实例代码
2016/10/13 Javascript
jQuery实现的仿百度,仿谷歌搜索下拉框效果示例
2016/12/30 Javascript
AngularJS $http post 传递参数数据的方法
2018/10/09 Javascript
vue路由 遍历生成复数router-link的例子
2019/10/30 Javascript
vue引用外部JS的两种种方法
2020/01/28 Javascript
react基本安装与测试示例
2020/04/27 Javascript
vue3.0封装轮播图组件的步骤
2021/03/04 Vue.js
Python程序员开发中常犯的10个错误
2014/07/07 Python
Python简单实现enum功能的方法
2016/04/25 Python
简介Python的collections模块中defaultdict类型的用法
2016/07/07 Python
python实现桌面气泡提示功能
2019/07/29 Python
python turtle 绘制太极图的实例
2019/12/18 Python
深入了解如何基于Python读写Kafka
2019/12/31 Python
python使用openCV遍历文件夹里所有视频文件并保存成图片
2020/01/14 Python
python实现文法左递归的消除方法
2020/05/22 Python
购买瑞典当代设计的腕表和太阳眼镜:TRIWA
2016/10/30 全球购物
澳大利亚拥有最好的家具和家居用品在线目的地:Nestz
2019/02/23 全球购物
汽车驾驶求职信
2013/10/25 职场文书
计算机售后服务承诺书
2014/05/30 职场文书
敬老院标语
2014/06/27 职场文书
机械操作工岗位职责
2014/08/08 职场文书
酒店管理专业毕业生自我鉴定
2014/09/29 职场文书
党员剖析材料范文
2014/09/30 职场文书
大一新生军训新闻稿
2015/07/17 职场文书
Python中npy和mat文件的保存与读取
2022/04/24 Python
Linux中文件的基本属性介绍
2022/06/01 Servers