關(guān)于Django外鍵賦值問題詳解
本文主要給大家介紹關(guān)于Django外鍵賦值的相關(guān)內(nèi)容,分享出來供大家參考學習,在開始之前,我們先來看一段代碼:
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) ...
寫代碼的的時候,發(fā)現(xiàn)了一個很奇怪的現(xiàn)象,當我給一個instance的外鍵(以_id結(jié)尾)賦值(數(shù)字)的時候 ,這個外鍵對應的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
的生成規(guī)則,就是外鍵名前面加下劃線,后面加cache)存不存在,如果不存在那么就進行數(shù)據(jù)庫請求,請求完之后會保存到cache中。
我們再看看__set__
,代碼太長就不貼了(就在__get__
方法下面)。除了給外鍵字段(article
)賦值外,還會將pk字段(article_id
,是lh_field.attname
的值)設置為None,這樣下次請求的時候就能拿到正確的值。
以上都是ForeignKey的Magic,而當我們給article_id
賦值的時候,只是在給一個普通的attribute賦值而已,沒有任何magic,不會清理對應外鍵的cache,這時候拿到的instance仍然是cache中原來的那個instance。
總結(jié)
以上就是這篇文章的全部內(nèi)容了,希望本文的內(nèi)容對大家的學習或者工作能帶來一定的幫助,如果有疑問大家可以留言交流,謝謝大家對腳本之家的支持。
相關(guān)文章
快速實現(xiàn)基于Python的微信聊天機器人示例代碼
本篇文章主要介紹了快速實現(xiàn)基于Python的微信聊天機器人示例代碼,基于itchat開發(fā),可以用它做一個微信聊天機器人,有興趣的可以了解一下。2017-03-03一個基于flask的web應用誕生 記錄用戶賬戶登錄狀態(tài)(6)
一個基于flask的web應用誕生第六篇,這篇文章主要介紹了記錄用戶賬戶登錄狀態(tài)功能開發(fā),具有一定的參考價值,感興趣的小伙伴們可以參考一下2017-04-04python GUI庫圖形界面開發(fā)之PyQt5復選框控件QCheckBox詳細使用方法與實例
這篇文章主要介紹了python GUI庫圖形界面開發(fā)之PyQt5復選框控件QCheckBox詳細使用方法與實例,需要的朋友可以參考下2020-02-02python 使用pdfminer3k 讀取PDF文檔的例子
今天小編就為大家分享一篇python 使用pdfminer3k 讀取PDF文檔的例子,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2019-08-08