Django 모델 레이어의 필드 관계(일대일, 다대일, 다대다)

필드 관계
  • 필드 관계는 django 유지보수표 관계의 방식이다.그 중에서 주로 일대일, 다대일 및 다대다
  • 가 있다.
  • 현재의 일대일 및 다대일 관계에 설정on_delete 속성은 관련 데이터가 삭제되었을 때의 조작을 설명하는데 다음과 같다
  • models.CASCADE: 연관된 데이터 삭제 및 연관된 데이터 삭제
    models.PROTECT: 연결된 데이터를 삭제하여 ProtectedError 오류 발생
    models.SET_NULL: 연관된 값이 null로 설정됩니다. 사전 요구 사항은 FK 필드가 비어 있어야 합니다.
    models.SET_DEFAULT: 연관된 데이터를 삭제하고 연관된 값을 기본값으로 설정합니다. FK 필드는 기본값을 설정해야 합니다.
    models.DO_NOTHING: 연결된 데이터를 삭제하고 아무것도 하지 않음
    일대일 관계
    모델류는 OneToOneField를 사용하여 일대일 관계를 정의한다.
    예를 들어 선생님표를 가지고 있을 때 바로 교수표가 필요하다. 그러면 교수표는 선생님표의 일련의 속성을 가지고 있을 수 있다. 그러면 선생님표의 필드를 교수표로 직접 복제하고 싶지 않다. 그러면 OnToOneField를 통해 교수표를 계승할 수 있다.
    사실 모델 클래스 상속을 사용할 때도 일대일 관계가 포함되어 있다
  • OneToOneField(to, on_delete, parent_link=False, options)
  • class Teacher(models.Model):
        name = models.CharField(max_length=50)
        age = models.CharField(max_length=50)
        def __str__(self):
            return self.name
    class Professor(models.Model):
        teacher = models.OneToOneField(Teacher,primary_key=True,on_delete=models.CASCADE)
        big_project = models.CharField(max_length=50)
        def __str__(self):
            return self.teacher.name
    
    manage.py shell에서 데이터베이스 작업 수행
    >>> t1 = Teacher.objects.create(name='Jack',age='22')
    >>> t2 = Teacher.objects.create(name='Bob',age='17')
    >>> p1 = Professor.objects.create(teacher=t1,big_project='     ')
    >>> p1.teacher
    <Teacher: Jack>
    >>> p1.teacher = t2
    >>> p1.save()
    >>> p1.teacher
    <Teacher: Bob>
    

    위의 테스트에서 p1에 대응하는 교수를 Bob로 변신시킨 것 같다.
    그러나 데이터베이스에 이전에 t1선생님이 대응한 교수 정보가 존재했다. 이때의 값 부여 조작은 교수님을 가르치기 전의 교수 데이터를 덮어쓰지 않고 값은 다시 만들어졌다.
    올바른 방법은 데이터의 일대일 관계를 delete 관계를 통해 삭제한 다음에 다시 부여하는 것이다
    다대일 관계Django 사용django.db.models.ForeignKey으로 다대일 관계를 정의한다.ForeignKey 위치 매개 변수가 필요합니다: 이 모델과 관련된 클래스
    생활 속의 다대일 관계: 담임선생님, 반 관계.담임 선생님은 많은 반을 이끌 수 있지만, 각 반에는 담임 선생님이 한 분만 있을 수 있다
    class Headmaster(models.Model):
        name = models.CharField(max_length=50)
        def __str__(self):
            return self.name
    class Class(models.Model):
        class_name = models.CharField(max_length=50)
        teacher = models.ForeignKey(Headmaster,null=True,on_delete=models.SET_NULL)
        def __str__(self):
            return self.class_name
    
    >>> H1 = Headmaster(name='  ')
    >>> H1.save()
    >>> H1
    <Headmaster:   >
    >>> H2 = Headmaster(name='  ')
    >>> H2.save()
    >>> Headmaster.objects.all()
    [<Headmaster:   >, <Headmaster:   >]
    

    이상에서 두 개의 선생님 데이터를 만들었습니다.
    저희가 외부 키 연결을 비워둘 수 있기 때문에 null=True 학급표를 만들 때 직접 저장할 수 있고 선생님 데이터를 제공할 필요가 없습니다.
    >>>C1 = Class(class_name='  ')
    >>>C2 = Class(class_name='  ')
    #          ,         
    # IntegrityError: NOT NULL constraint failed: bbs_class.teacher_id
    >>>C1.teacher = H1
    >>>C2.teacher = H2
    >>>C1.save()
    >>>C2.save()
    

    선생님을 한 학급으로 분배한 후, 학급표에 선생님 필드가 연결되어 있기 때문에, 우리는 학급을 통해 대응하는 선생님을 찾을 수 있다
    선생님 표에는 관련 학급 필드가 없지만 선생님을 통해 그가 가지고 있는 학급을 찾을 수 있다. 이런 조회 방식을 관련 조회라고도 부른다.
    모델 클래스 이름을 통해 '' 추가set, 역방향 검색을 실현합니다
    >>> H1.class_set.all()
    <QuerySet [<Class:   >]>
    

    우리 는 다대일 의 관계 이기 때문 에, 우리 선생님 이 여러 반 에 대응할 수 있다는 것 을 설명한다
    우리는 계속해서 H1 선생님께 새로운 반을 배정할 수 있다
    >>> C3 = Class(class_name='  ')
    >>> C3.teacher = H1
    >>> C3.save()
    >>> H1.class_set.all()
    [<Class:   >, <Class:   >]
    

    한 반은 한 선생님만 대응할 수 있습니다. 외부 키는 유일합니다. 그러면 C1반에 새로운 선생님을 계속 배정할 때 이전의 선생님 정보를 덮어쓰고 새로운 선생님을 저장하지 않습니다.
    >>> H3 = Headmaster(name='  ')
    >>> H3.save()
    >>> C1.teacher
    <Headmaster:   >
    >>> C1.teacher=H3
    >>> C1.save()
    >>> C1.teacher
    <Headmaster:   >
    

    이 반의 선생님을 삭제합니다. 키 필드가 설정되어 있기 때문에null입니다. 이 반의 선생님 옵션은null입니다.
    >>> t1 = Headmaster.objects.all().first()
    >>> t1
    >>> c1 = Class.objects.all().first()
    <Headmaster:   >
    >>> c1
    <Class:   >
    >>> c1.teacher
    <Headmaster:   >
    >>> t1.delete()
    (1, {
         'modelsapp.Headmaster': 1})
    >>> c1 = Class.objects.all().first()
    >>> c1
    <Class:   >
    >>> c1.teacher
    >>> #       ,    C1       None 
    

    삭제한 후에 데이터를 다시 한 번 얻는 것을 기억해야 한다. 그렇지 않으면 본 결과에서 선생님의 반 데이터를 얻었는지 아니면 이전에 얻었는지 기억해야 한다
    다대다관계
    모델에 ManyToManyField 필드를 사용하여 다중 관계식 정의
    여러 쌍의 다중 관계는 관련이 있을 수도 있고 없을 수도 있기 때문에 명확하게 지정할 필요가 없다on_delete 속성
    생활 속 에서 다대다 관계: 한 음악가 는 여러 밴드 에 예속될 수 있고, 한 밴드 는 여러 음악가 가 가 있을 수 있다
    class Artist(models.Model):
        artist_name = models.CharField(max_length=50)
        def __str__(self):
            return self.artist_name
    class Band(models.Model):
        band_name = models.CharField(max_length=50)
        artist = models.ManyToManyField(Artist)
        def __str__(self):
            return self.band_name
    

    음악가와 밴드를 만들다
    >>> from bbs.models import Artist,Band
    >>> A1 = Artist.objects.create(artist_name='Jack')
    >>> A2 = Artist.objects.create(artist_name='Bob')
    >>> B1 = Band.objects.create(band_name='FiveMonthDay')
    >>> B2 = Band.objects.create(band_name='SHE')
    

    두 밴드를 만들어서 뮤지션의 추가를 하도록 하겠습니다.
    다중 필드를 추가할 때 add 함수를 사용하여 다중 값을 증가할 수 있습니다
    >>> B1.artist.add(A1,A2)
    >>> B2.artist.add(A2)
    
    B1 밴드 포함A1, A2 두 멤버B2 밴드 멤버 포함 A1
    >>> B1.artist.all()
    [<Artist: Bob>, <Artist: Jack>]
    >>> B2.artist.all()	
    [<Artist: Jack>]
    

    음악가 표에서 어떤 악가가 어떤 밴드에 속하는지 찾을 수 있다
    >>> Band.objects.filter(artist=A1) #                 。
    [<Band: SHE>, <Band: FiveMonthDay>] # A1    ,SHE  FiveMonthDay
    >>> Band.objects.filter(artist=A2)
    [<Band: SHE>]
    

    이 뮤지션이 어떤 밴드에 있는지 찾아보셔도 돼요.
    >>> A1.band_set.all() #               
    [<Band: SHE>, <Band: FiveMonthDay>]
    >>> A2.band_set.all()
    [<Band: SHE>]
    

    다중 연관 필드 삭제remove를 사용하여 관계 끊기
    직접 사용 delete 대신 remove 데이터 간의 연결은 끊어지지만 삭제되지는 않음
    지금 B1 밴드에서 A1 악가를 삭제합니다.
    >>> B1.artist.remove(A1)
    >>> B1.artist.all()
    <QuerySet [<Artist: Bob>]>
    

    연관 테이블에 대한 질의
    조회하고자 하는 필드가 관련 테이블에 있으면 __ 를 사용하여 테이블 간의 조회 작업을 진행합니다
    다대일 관계의 부자표를 만들면, 한 아버지에게는 여러 아들이 있을 수 있다.
    class Father(models.Model):
    	name = models.CharField(max_length=30)
    	age = models.CharField(max_length=30)
        def __str__(self):
            return self.name
    class Son(models.Model):
        father = models.ForeignKey(Father,on_delete=models.CASCADE)
        name = models.CharField(max_length=30)
        def __str__(self):
            return self.name
    

    데이터 생성
    >>> f1 = Father.objects.create(name='Jack',age='30')
    >>> s1 = Son.objects.create(name='Json',father=f1)
    >>> s2 = Son.objects.create(name='Json2',father=f1)
    
    >>> f2 = Father.objects.create(name='Bob',age='40')
    >>> s3 = Son.objects.create(name='Json3',father=f2)
    

    모든 아버지 이름이 jack인 아이 조회
    >>> Son.objects.filter(father__name__exact='Jack')
    [<Son: Json>, <Son: Json2>]
    

    모든 아들의 이름이 J로 시작하는 아버지를 조회하다
    >>> Father.objects.filter(son__name__startswith='J')
    [<Father: Jack>, <Father: Jack>, <Father: Bob>]
    

    어떤 아버지의 모든 아이를 얻고 어떤 데이터를 통해 _set 역방향 조회
    >>> f1.son_set.all()
    >>> [<Son: Json>, <Son: Json2>]
    

    데이터의 역방향 조회
    기본적으로 어떤 데이터를 얻은 후에 우리는 모델 클래스 이름_set을 붙여서 역방향 조회를 실현할 수 있다.
    현재 두 개의 표를 군대와 병사표로 설계하였으며, 병사는 다대일 관련 군대이다
    class Aramy(models.Model):
    	name = models.CharField(max_length=30)
        def __str__(self):
            return self.name
    class Soldier(models.Model):
        aramy = models.ForeignKey(Aramy,on_delete=models.CASCADE)
        name = models.CharField(max_length=30)
        def __str__(self):
    		return self.name
    

    일부 데이터 생성
    >>> a1 = Aramy(name='  ')
    >>> a1.save()
    >>> s1 = Soldier(name='  ',aramy=a1)
    >>> s1.save()
    >>> s2 = Soldier(name='  ',aramy=a1)
    >>> s2.save()
    
    soldier_set를 통해 우리는 대응하는 병사표에 연결할 수 있다
    또한 반환 결과에 대응하여 우리가 자주 사용하는 filter,exclude 등 조회 조작을 실행할 수 있다
    >>> a1.soldier_set.all()
    [<Soldier:   >, <Soldier:   >]
    >>> a1.soldier_set.filter(name='  ')
    [<Soldier:   >]
    

    관련 필드의 related_name 값을 정의하여 사용자 정의 역방향 검색 이름을 실현할 수 있습니다
    또한 related_name 값은 고유해야 합니다.
    class Aramy(models.Model):
        name = models.CharField(max_length=30)
        def __str__(self):
            return self.name
    class Soldier(models.Model):
        aramy = models.ForeignKey(Aramy,on_delete=models.CASCADE,related_name='soldier')
        name = models.CharField(max_length=30)
        def __str__(self):
            return self.name
    

    다음에 어떤 데이터를 통해 역방향 조회를 한다
    >>> a1 = Aramy.objects.all()[0]
    >>> s1 = Soldier.objects.get(name='  ')
    >>> a1.soldier.all()
    [<Soldier:   >, <Soldier:   >]
    

    참고: relatedname은 반드시 유일한 값입니다. 그렇지 않으면 반대로 찾을 때 이성 오류가 발생합니다.related_name+로 초기화하여 역방향 조회를 취소할 수도 있습니다.

    좋은 웹페이지 즐겨찾기