본문 바로가기
IT/파이썬

파이썬 two way referencing in mongoengine - ReferenceField 팁과 문제 해결

아직 선언안된 테이블, 컬렉션 (머라 부르던) 객체를 레퍼런스 하는 필드를 추가하고 싶을때

 

NameError: name 'XXXX' is not defined

 

에러가 발생한다.

쉽게 해결하기 위해서는 레퍼런스 할 모델 클래스를 사용하기 전에 선언하면 좋긴한데

두 클랙스 사이에 각자가 각각 레퍼런스 하는 경우도 있기 때문에 순서로 해결하기 어려운 경우가 더 많다.


이중 참조 문제 해결

그런데, 아주 쉽게 해결이 되었다. 

 

github.com/MongoEngine/mongoengine/issues/1697

 

two way referencing in mongoengine · Issue #1697 · MongoEngine/mongoengine

Hey i read here about two way referencing in mongoengine https://www.mongodb.com/blog/post/6-rules-of-thumb-for-mongodb-schema-design-part-2 how can it be done in mongoengine? since if i do class A...

github.com

요지를 정리하면, 선언이 되기 전의 클래스(컬렉션) 이름을 그냥 문자열 처럼 인터프리터가 이해하도록 해 놓고 넘어가면 된다는 것, 기능은 나중에 실행시에 late binding 이 되도록 구현되어 있으므로 걱정할 필요가 없다.

ReferenceField(클래스명) 을 ReferenceField('클래스명') 으로 써 두면 된다. 문자열 처럼 보이게

 

문법은 안 맞아도 예제로 아래 코드의 ReferenceField 부분을 보자.

    class Course(me.Document):
        id = me.IntField(primary_key=True)
        name = me.StringField()
        students = me.ListField(me.ReferenceField('Student'))

    class School(me.Document):
        name = me.StringField()
        students = me.ListField(me.ReferenceField('Student'))
        headteacher = me.EmbeddedDocumentField(HeadTeacher)

    class Student(me.Document):
        full_name = me.StringField(max_length=255, unique=True, default='noname')
        age = me.IntField(min_value=10, max_value=99)
        current_school = me.ReferenceField('School')
        courses = me.ListField(me.ReferenceField('Course'))
        
        
       ...

전체코드는 여기를 참고하세요.

www.programcreek.com/python/example/72906/mongoengine.ReferenceField

 

Python Examples of mongoengine.ReferenceField

The following are 5 code examples for showing how to use mongoengine.ReferenceField(). These examples are extracted from open source projects. You can vote up the ones you like or vote down the ones you don't like, and go to the original project or source

www.programcreek.com


기타 팁 

하나더, 아래 예제 처럼 사용자 정의해 보스라는 사용자를 referencefield로 즉, 정의하고 있는 class를 자체를 참조 객체로 넣고 싶을 때는 'self' 를 사용하세요.

이 때 User 객체는 자동적으로 참조가 되고, Page 객체를 검색했을 때는 역참조된다. 정의 중인 document를 참조하는 ReferenceField를 추가하기 위해서는 'self'를 사용한다.
class Employee(Document):
    name = StringField()
    boss = ReferenceField('self')
    profile_page = ReferenceField('ProfilePage')

class ProfilePage(Document):
    content = StringField()

 

그리고, GenericReferenceField 라고 불리는 것은 그냥 Document 형태를 정의하지 않고 아무 거나 넣을 수 있도록 유연하게 되어 있는 ReferenceField 이다. 가끔 이런 설계를 벗어난 용례의 프로젝트가 있을 수도...알아두자.

class Bookmark(Document):
    bookmark_object = GenericReferenceField()

link = Link(url='http://hmarr.com/mongoengine/')
link.save()

Bookmark(bookmark_object=link).save()

기타 팁에 관련된 내용은 아래 원본 글을 참고하면 자세한 설명을 볼 수 있다. 완전 잘 정리되어 있는 글이다.

velog.io/@matisse/Flask-setup-with-MongoEngine

 

🌱 Flask setup with MongoEngine

flask를 기반으로 Mongodb를 사용할 때, mongoengine을 사용하면 NoSQL DB임에도 모델링을 하고(데이터 타입이나 관계를 정의), view를 작성할 때 Django ORM 같이 쿼리를 객체처럼 접근할 수 있다.

velog.io

BJ.

두명 여인 자동차

Elijah O'Donnell 님의 사진, 출처: Pexels