關(guān)于Django外鍵賦值問題詳解
本文主要給大家介紹關(guān)于Django外鍵賦值的相關(guān)內(nèi)容,分享出來供大家參考學(xué)習(xí),在開始之前,我們先來看一段代碼:
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) ...
寫代碼的的時(shí)候,發(fā)現(xiàn)了一個(gè)很奇怪的現(xiàn)象,當(dāng)我給一個(gè)instance的外鍵(以_id結(jié)尾)賦值(數(shù)字)的時(shí)候 ,這個(gè)外鍵對應(yīng)的instance的值并不會(huì)改變。
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
注釋得非常到位,當(dāng)我們請求ac.article的時(shí)候,會(huì)先去檢查對應(yīng)的cache(在這里是_article_cache,感興趣可以去看cache_name的生成規(guī)則,就是外鍵名前面加下劃線,后面加cache)存不存在,如果不存在那么就進(jìn)行數(shù)據(jù)庫請求,請求完之后會(huì)保存到cache中。
我們再看看__set__ ,代碼太長就不貼了(就在__get__方法下面)。除了給外鍵字段(article)賦值外,還會(huì)將pk字段(article_id,是lh_field.attname的值)設(shè)置為None,這樣下次請求的時(shí)候就能拿到正確的值。
以上都是ForeignKey的Magic,而當(dāng)我們給article_id賦值的時(shí)候,只是在給一個(gè)普通的attribute賦值而已,沒有任何magic,不會(huì)清理對應(yīng)外鍵的cache,這時(shí)候拿到的instance仍然是cache中原來的那個(gè)instance。
總結(jié)
以上就是這篇文章的全部內(nèi)容了,希望本文的內(nèi)容對大家的學(xué)習(xí)或者工作能帶來一定的幫助,如果有疑問大家可以留言交流,謝謝大家對腳本之家的支持。
相關(guān)文章
Python如何實(shí)現(xiàn)macOS系統(tǒng)代理的設(shè)置
這篇文章主要為大家詳細(xì)介紹了Python如何實(shí)現(xiàn)macOS系統(tǒng)代理的設(shè)置,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下2025-01-01
Python異常信息的不同展現(xiàn)方法總結(jié)
在日常開發(fā)的過程中,當(dāng)代碼報(bào)錯(cuò)時(shí),我們通常要不斷打印、閱讀traceback提示信息,來調(diào)試代碼,這篇文章介紹了如何實(shí)現(xiàn)一個(gè)Exception?Hooks,使得traceback模塊的提示信息更加精確;同時(shí)還介紹了一些第三方庫,這些庫也提供了Exception?Hooks的功能2022-11-11
Python用5行代碼實(shí)現(xiàn)批量摳圖的示例代碼
這篇文章主要介紹了Python用5行代碼實(shí)現(xiàn)批量摳圖的示例代碼,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-04-04
Python實(shí)現(xiàn)Word表格轉(zhuǎn)成Excel表格的示例代碼
這篇文章主要介紹了Python實(shí)現(xiàn)Word表格轉(zhuǎn)成Excel表格的示例代碼,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-04-04

