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)
 ...
코드 를 쓸 때 이상 한 현상 을 발 견 했 습 니 다.인 스 턴 스 의 외 키 를 주 었 을 때(로)id 끝)할당(숫자)을 할 때 이 외부 키 에 대응 하 는 intance 의 값 은 변 하지 않 습 니 다.

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(여기 서 4567914)를 검사 합 니 다.관심 이 있 으 면_article_cache의 생 성 규칙 을 볼 수 있 습 니 다.바로 외 키 이름 앞 에 밑줄 을 치고 뒤에 cache 를 추가 하 는 것 입 니 다.존재 하지 않 으 면 데이터 베 이 스 를 요청 하고 요청 이 끝 난 후에 cache 에 저장 합 니 다.
다시 보 자cache_name.코드 가 너무 길 면 붙 이지 않 는 다__set__방법 아래 에 있다).외부 키 필드__get__에 값 을 부여 하 는 것 외 에 도 pk 필드article,article_id의 값 을 None 로 설정 하여 다음 요청 시 정확 한 값 을 얻 을 수 있 습 니 다.
이상 은 모두 ForeignKey 의 Magic 입 니 다.우리 가lh_field.attname에 값 을 부 여 했 을 때 일반적인 attribute 에 값 을 부 여 했 을 뿐,어떠한 magic 도 없 었 습 니 다.외부 키 에 대응 하 는 cache 를 청소 하지 않 았 습 니 다.이때 받 은 intance 는 여전히 cache 에 있 는 원래 의 인 스 턴 스 입 니 다.
총결산
이상 은 이 글 의 전체 내용 입 니 다.본 논문 의 내용 이 여러분 의 학습 이나 업무 에 어느 정도 도움 이 되 기 를 바 랍 니 다.궁금 한 점 이 있 으 시 면 댓 글 을 남 겨 주 셔 서 저희 에 대한 지지 에 감 사 드 립 니 다.

좋은 웹페이지 즐겨찾기