[Django] GenericForeignKey Generic Relation 및 ContentType(zz)

6136 단어 generic
Generic Relation은 새로 나온 것이 아니지만, 이전에 나는 줄곧 사용한 적이 없다.이제 SharePlat의 일부 기능을 독립시키기 위해 사용하기 시작했습니다.django 원본에 있는 문서에Generic Relation에 대한 설명이 없으며,django의 사이트에서 이것문서을 찾을 수 있습니다.
문서에서 매우 명확하게 묘사하다.GenericForeignKey와 GenericRelation은 기본적으로 두 가지 용도로 사용됩니다.예를 들어, 토론 주제를 저장하는 데 사용되는 Topic 테이블이 있습니다.그 다음에 답장을 저장하는 Comment 테이블이 있습니다.Comment 일반 사용을 위해 Comment 는 Topic 관계에 직접 저장하지 않습니다.이 두 테이블의 모델은 다음과 같습니다.
from django.contrib.contenttypes.models import ContentTypeclass Topic(models.Model):    title = models.CharField(maxlength=200)    content = models.TextField()    comments = models.GenericRelation(Comment)class Comment(models.Model):    content = models.TextField(default='')    content_type = models.ForeignKey(ContentType)    object_id = models.IntegerField()    content_object = models.GenericForeignKey()
두 가지 단순화된 모델입니다.여기에 두 가지 용법을 구현하였다.
먼저 보기Comment.Comment에서 GenericForeignKey()를 사용하여 다른 모델 인스턴스를 가리킵니다.그것을 사용하기 위해서는 Model에서 콘텐츠를 정의해야 합니다type 및 object아이디만 가능합니다.여기서 contenttype은 ContentType Model을 가리킵니다.예시의 맨 위에서 볼 수 있듯이django에 정의되어 있다.contrib.contenttypes.모델의 모델입니다.귀찮으신지 어쩔 수 없어요.처음에 저는 Woodlog에서 비슷한 기능을 실현하고 싶었습니다. 그때 저는 모델 이름과 기록된 id 값을 포함하여'/'를 통해 구분하는 문자열을 사용했습니다.그래서 처리할 때 매번 분할해야 한다.이것보다 더 귀찮아요.사실 곰곰이 생각해 보면 어쩔 수 없는 일이다.django에서 당신은 어떻게 기록을 포지셔닝합니까?일반적으로 세 가지 값이 필요합니다: appname, modelname,objectid.ContentType에서는 appname과 modelname이 저장됩니다.그래서 GenericForeignKey를 사용하면 두 개의 값만 얻을 수 있습니다.GenericForeignKey 자체는 정의해야 합니다.결과는 역시 세 종목이다.사용은 사실 매우 간단하다.문서를 보면 분명히 알 수 있다.
토픽도 보고.GenericRelation을 정의합니다.이렇게 하면 너는 instance를 통과할 수 있다.comments.all () 는 instance에 대응하는 모든 Comment 실례에 접근합니다.물론 이 정의는 필수적인 것이 아닙니다. 만약 정의하지 않는다면, 수동으로 Comment에서 찾아야 합니다. 예를 들어 이미 topic의 실례가 있는데, 지금 그 답장을 찾아야 합니다.
ctype = ContentType.objects.get_for_model(topic)Comment.objects.filter(content_type__pk=ctype.id, object_id=topic.id)
동시에 하나의 모델에서GenericForeignKey를 여러 개 정의할 수 있습니다.GenericForeignKey는 정의할 때 콘텐츠를 지정할 수 있기 때문입니다type 및 objectid 필드의 이름, 기본값은 이 두 개입니다. 새 이름을 지정하면 새로운GenericForeignKey를 정의할 수 있습니다.예:
    content_type = models.ForeignKey(ContentType, related_name='content_type')    object_id = models.IntegerField()    content_object = models.GenericForeignKey()    own_type = models.ForeignKey(ContentType, related_name='own_type')    own_id = models.IntegerField()    own_object = models.GenericForeignKey(ct_field='own_type', fk_field='own_id')
Generic Relation을 사용하면 Django의 메일 리스트에서 언급된 기능이 충분하지 않을 수도 있습니다.제가 발견한 게 크레이트 입니다.or_get () 은 안 될 것 같습니다.
어쨌든 만약에 당신의 앱이 다른 모델을 처리할 수 있도록 하려면 예를 들어 당신의 앱이 태그,Comment 등이면GenericForeignKey와GenericRelation을 고려하여 처리할 수 있고 당신의 처리를 간소화할 수 있습니다.
 
간단하게 말하면ContentType은 모델, 즉 데이터 테이블이다. 그 중에서 현재 프로젝트에 있는 모든 모델의 메타데이터가 저장되어 있다. 구체적으로name, applabel과 모델 세 필드 중 applabel과 모델 두 문자열을 조합하면 모델을 유일하게 표시할 수 있습니다.호출을 통해django.db.models.get_모델(app label, 모델)에서 모델 클래스를 얻을 수 있습니다.이런 이상한 모델이 무슨 소용이 있을까요?임의의 모델과 관계가 있는 모델이 필요할 때 어떻게 할 것인지 생각해 보세요.사용자 평론!만약에 프로젝트에 영화, 문장, 음악 등 내용이 있다고 가정하면 각각 다른 모델에 대응하고 사용자가 각각의 내용에 대해 평론을 할 수 있다. 그러면 가장 간단한 방법은 각각의 내용에 해당하는 평론표를 작성하는 것이다. 예를 들어 무비comments, article_comments 등.그러나 이런 방법의 폐단은 매우 뚜렷하다. 먼저 모델의 수량을 증가시켰고 코드의 복잡도를 증가시켰다.또한 확장성이 없고 다른 내용을 추가하려면 해당하는comments표를 추가해야 한다.그리고 사용자의 모든 평론을 통계할 때 비교적 번거롭기 때문에 여러 테이블에서 조회를 해야 한다.프로젝트에 있는 모든 모델의 메타데이터를 기록한 테이블이 있다면, 테이블의 메타데이터는 하나의 모델에 대응한다. 그러면 우리는 하나의 메타데이터 테이블의 id와 구체적인 데이터 테이블의 id를 통해 모든 모델의 메타데이터를 찾을 수 있다.콘텐츠Type이 바로 이 표입니다. (단 하나의 전제는 관련 모델의 키 형식이 같아야 하며,django의 기본 키를 사용하면 ok입니다.)ContentType이 있으면 저희 사용자 평론은 모델 하나만 있으면 됩니다!다음은 구체적인 방법을 소개하겠습니다. 우선 아래 명령을 실행하여>django-admin.py startproject ContentType에서 프로젝트를 만듭니다.그리고 settings를 수정합니다.py, 적합한 데이터베이스 백엔드를 설정합니다.그리고 >cd ContentType>manage를 통해py startapp contents에서 app를 만들고 contents/models를 수정합니다.py는 다음과 같습니다.
from django.db import models
from django.contrib.contenttypes.models import ContentType

class Movie(models.Model):
title = models.CharField(maxlength=100)

class Article(models.Model):
title = models.CharField(maxlength=100)

class Music(models.Model):
title = models.CharField(maxlength=100)

class Comment(models.Model):
content_type = models.ForeignKey(ContentType)
object_id = models.IntegerField()
content_object = models.GenericForeignKey()
title = models.CharField(maxlength=100)

그리고 settings에서.py의 INSTALLEDAPPS에 "ContentType.contents", 명령 실행: >manage.py syncdb 다음 실행: >manage.pyshell은 이제 노동의 열매를 즐겨볼 수 있습니다.
>>> from ContentType.contents.models import *
>>> a = Article()
>>> a.title = 'article1'
>>> a.save()
>>> m = Movie()
>>> m.title = 'movie1'
>>> m.save()
>>> mu = Music()
>>> mu.title = 'music1'
>>> mu.save()
>>> c = Comment()
>>> c.content_object = a
>>> c.title = 'comment1'
>>> c.save()
>>> c = Comment()
>>> c.content_object = m
>>> c.title = 'comment2'
>>> c.save()
>>> c = Comment()
>>> c.content_object = mu
>>> c.title = 'comment3'
>>> c.save()
>>> for c in Comment.objects.all():
... print c.content_type,c.object_id
...
article 1
movie 1
music 1
>>> c.content_object.title
'music1'

또 하나 언급할 점은 Comment 콘텐츠object 필드.사실 위에서 설명한 대로 콘텐츠만 있으면type 및 objectid 두 필드면 충분하지만, 두 필드의 값을 직접 지정해야 합니다.GenericForeignKey가 나타난 목적은 이 과정을 자동화하는 것이다. 콘텐츠만object에 대상을 부여하면 자동으로 이 대상의 메타데이터에 따라 콘텐츠에type 및 objectid가 부여되었습니다.GenericForeignKey의 구조 함수는 두 개의 선택적 인자를 수락합니다: definit__(self,ct field="content type", fk field="object id"): GenericForeignKey를 구성할 때 다른 필드 이름을 지정할 수 있습니다.또 주의해야 할 점은 콘텐츠 type의 표는syncdb에서 만들어졌지만 처음에는 메타데이터가 없었고 그 중의 데이터는 필요할 때 추가되었다. 네가 생각한 바와 같이 get 를 사용했다.or_create 방법.

좋은 웹페이지 즐겨찾기