关于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 相关文章推荐
netbeans7安装python插件的方法图解
Dec 24 Python
Python中计算三角函数之cos()方法的使用简介
May 15 Python
Python实现控制台进度条功能
Jan 04 Python
Python 将RGB图像转换为Pytho灰度图像的实例
Nov 14 Python
python如何让类支持比较运算
Mar 20 Python
儿童python练习实例
May 27 Python
Python数据可视化教程之Matplotlib实现各种图表实例
Jan 13 Python
Python使用POP3和SMTP协议收发邮件的示例代码
Apr 16 Python
把vgg-face.mat权重迁移到pytorch模型示例
Dec 27 Python
python列表删除和多重循环退出原理详解
Mar 26 Python
keras做CNN的训练误差loss的下降操作
Jun 22 Python
python随机打印成绩排名表
Jun 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 set_magic_quotes_runtime() 函数过时解决方法
2010/07/08 PHP
php define的第二个参数使用方法
2013/11/04 PHP
php过滤敏感词的示例
2014/03/31 PHP
apache和PHP如何整合在一起
2015/10/12 PHP
PHP基于反射机制实现插件的可插拔设计详解
2016/11/10 PHP
php中__toString()方法用法示例
2016/12/07 PHP
Laravel接收前端ajax传来的数据的实例代码
2017/07/20 PHP
PHP使用栈解决约瑟夫环问题算法示例
2017/08/27 PHP
PHP+Ajax实现上传文件进度条动态显示进度功能
2018/06/04 PHP
javascript instanceof,typeof的区别
2010/03/24 Javascript
js 判断checkbox是否选中的操作方法
2012/11/09 Javascript
js单例模式详解实例
2013/11/21 Javascript
浅谈jQuery异步对象(XMLHttpRequest)
2014/11/17 Javascript
微信小程序图表插件(wx-charts)实例代码
2017/01/17 Javascript
在Vue中使用highCharts绘制3d饼图的方法
2018/02/08 Javascript
详解Node.js中的Async和Await函数
2018/02/22 Javascript
Vue cli构建及项目打包以及出现的问题解决
2018/08/27 Javascript
小程序跳转到的H5页面再跳转回跳小程序的方法
2020/03/06 Javascript
vue iview实现动态新增和删除
2020/06/17 Javascript
python实现批量监控网站
2016/09/09 Python
浅谈Python生成器generator之next和send的运行流程(详解)
2017/05/08 Python
Python使用Scrapy保存控制台信息到文本解析
2017/12/27 Python
解决Django migrate No changes detected 不能创建表的问题
2018/05/27 Python
python 反向输出字符串的方法
2018/07/16 Python
python 多线程重启方法
2019/02/18 Python
深入浅析css3 中display box使用方法
2015/11/25 HTML / CSS
html5 input属性使用示例
2013/06/28 HTML / CSS
html5中audio支持音频格式的解决方法
2018/08/24 HTML / CSS
加拿大休闲和工业服装和鞋类零售商:L’Équipeur
2018/01/12 全球购物
美国球鞋寄卖网站:Stadium Goods
2018/05/09 全球购物
手工制作的意大利礼服鞋:Ace Marks
2018/12/15 全球购物
大学生求职中的自我评价
2013/10/01 职场文书
财务会计实训报告
2014/11/05 职场文书
2015年爱牙日活动总结
2015/03/23 职场文书
趣味运动会口号
2015/12/24 职场文书
Redis实现订单自动过期功能的示例代码
2021/05/08 Redis