关于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实现2014火车票查询代码分享
Jan 10 Python
使用rst2pdf实现将sphinx生成PDF
Jun 07 Python
python处理csv数据动态显示曲线实例代码
Jan 23 Python
Python 编码规范(Google Python Style Guide)
May 05 Python
Python解析并读取PDF文件内容的方法
May 08 Python
Python实现多线程的两种方式分析
Aug 29 Python
详解python解压压缩包的五种方法
Jul 05 Python
Django接收post前端返回的json格式数据代码实现
Jul 31 Python
win10环境下配置vscode python开发环境的教程详解
Oct 16 Python
python实现的批量分析xml标签中各个类别个数功能示例
Dec 30 Python
pytorch cuda上tensor的定义 以及减少cpu的操作详解
Jun 23 Python
python跨文件使用全局变量的实现
Nov 17 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
回首过去10年中最搞笑的10部动漫,哪一部让你节操尽碎?
2020/03/03 日漫
PHP通过COM使用ADODB的简单例子
2006/12/31 PHP
PHP常用的缓存技术汇总
2014/05/05 PHP
PHP生成图片验证码、点击切换实例
2014/06/25 PHP
自己写的兼容低于PHP 5.5版本的array_column()函数
2014/10/24 PHP
浅析iis7.5安装配置php环境
2015/05/10 PHP
php插件Xajax使用方法详解
2017/08/31 PHP
PHP实现断点续传乱序合并文件的方法
2018/09/06 PHP
对laravel的session获取与存取方法详解
2019/10/08 PHP
深入理解JavaScript系列(6) 强大的原型和原型链
2012/01/15 Javascript
防止登录页面出现在frame中js代码
2014/07/22 Javascript
Javascript中作用域的详细介绍
2016/10/06 Javascript
移动端web滚动分页的实现方法
2017/05/05 Javascript
判断jQuery是否加载完成,没完成继续判断的解决方法
2017/12/06 jQuery
基于webpack-hot-middleware热加载相关错误的解决方法
2018/02/22 Javascript
vue 设置proxyTable参数进行代理跨域
2018/04/09 Javascript
layui动态绑定事件的方法
2019/09/20 Javascript
html-webpack-plugin修改页面的title的方法
2020/06/18 Javascript
原生JavaScript写出Tabs标签页的实例代码
2020/07/20 Javascript
Vue 同步异步存值取值实现案例
2020/08/05 Javascript
Python编码类型转换方法详解
2016/07/01 Python
关于Python面向对象编程的知识点总结
2017/02/14 Python
详解python并发获取snmp信息及性能测试
2017/03/27 Python
基于Python os模块常用命令介绍
2017/11/03 Python
浅谈Python_Openpyxl使用(最全总结)
2019/09/05 Python
Python 写了个新型冠状病毒疫情传播模拟程序
2020/02/14 Python
如何转换一个字符串到enum值
2014/04/12 面试题
九年级体育教学反思
2014/01/23 职场文书
幼儿园英语教学反思
2014/01/30 职场文书
连带责任保证书
2014/04/29 职场文书
机械机修工岗位职责
2014/08/03 职场文书
保密工作整改报告
2014/11/06 职场文书
2014年勤工助学工作总结
2014/11/24 职场文书
2019广播稿怎么写
2019/04/17 职场文书
Java 超详细讲解设计模式之中的抽象工厂模式
2022/03/25 Java/Android
apache ftpserver搭建ftp服务器
2022/05/20 Servers