关于Django外键赋值问题详解

 更新时间:2017年08月13日 15:56:57   作者:Youmai  
这段时间用django 做程序用到了一对多的关系的操作,下面分享一些心得体会,这篇文章主要给大家介绍了关于Django外键赋值问题的相关资料,需要的朋友可以参考借鉴,下面来一起看看吧。

本文主要给大家介绍关于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中内置库os与sys模块的详细介绍

    python中内置库os与sys模块的详细介绍

    这篇文章主要介绍了python中内置库os与sys模块的详细介绍,文章围绕主题展开详细的内容介绍,具有一定的参考价值,需要的朋友可以参考一下
    2022-08-08
  • python 包 requests 实现请求操作

    python 包 requests 实现请求操作

    这篇文章主要介绍了python 包 requests 实现请求操作,文章介绍内容包括带参数请求、自定义headers,文章内容详细具有一定的参考价值,需要的小伙伴可以参考一下
    2022-04-04
  • pandas如何修改DataFrame行/列/字段值

    pandas如何修改DataFrame行/列/字段值

    这篇文章主要介绍了pandas如何修改DataFrame行/列/字段值问题,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教
    2023-08-08
  • 获取python文件扩展名和文件名方法

    获取python文件扩展名和文件名方法

    本篇文章通过python写一个获取python文件扩展名和文件名的功能,并分享了代码,有兴趣的参考下。
    2018-02-02
  • Python读取mat文件,并保存为pickle格式的方法

    Python读取mat文件,并保存为pickle格式的方法

    今天小编就为大家分享一篇Python读取mat文件,并保存为pickle格式的方法,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2018-10-10
  • 利用python实现对web服务器的目录探测的方法

    利用python实现对web服务器的目录探测的方法

    这篇文章主要介绍了利用python实现对web服务器的目录探测的方法,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2019-02-02
  • 在django中查询获取数据,get, filter,all(),values()操作

    在django中查询获取数据,get, filter,all(),values()操作

    这篇文章主要介绍了在django中查询获取数据,get, filter,all(),values()操作,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2020-08-08
  • Python图片处理之图片裁剪教程

    Python图片处理之图片裁剪教程

    这篇博文的目的是从图片中提取一定的矩形区域作为新的图片 简单来说:我的全家福丢了,所以我想从以前的房间照片里,提取出其中的全家福并重新打印一张(忽视画质问题)现在我就是这么个目的,需要的朋友可以参考下
    2021-05-05
  • Python实现自动填写脚本流程详解

    Python实现自动填写脚本流程详解

    这篇文章主要介绍了Python实现自动填写脚本,100%准确率,文中的示例代码讲解详细,感兴趣的小伙伴可以了解一下
    2022-10-10
  • Python实现把utf-8格式的文件转换成gbk格式的文件

    Python实现把utf-8格式的文件转换成gbk格式的文件

    这篇文章主要介绍了Python实现把utf-8格式的文件转换成gbk格式的文件,本文给出了实现代码并同时剖析了代码的作用,需要的朋友可以参考下
    2015-01-01

最新评论