1

SQLAlchemy 1.0.13에서 Flask-SQLAlchemy 2.1을 사용하고 있는데, 다음과 같이 AddressCustomer, 서로 여러 관계를 가질 수 :Flask-SQLAlchemy : CircularDependencyError 여기서 다 대일 관계의 같은 행은 동일한 테이블과 일대 다 관계가 될 수 있습니다.

class Address(db.Model): 
    id = db.Column(db.Integer, primary_key=True) 
    ... # Other rows including first_name, last_name, etc. 
    customer_id = db.Column(
     db.Integer, 
     db.ForeignKey('customers.id') 
    ) 
    customer = db.relationship(
     'Customer', 
     foreign_keys=customer_id, 
     back_populates='addresses' 
    ) 

class Customer(db.Model): 
    id = db.Column(db.Integer, primary_key=True) 
    billing_address_id = db.Column(db.Integer, db.ForeignKey('addresses.id')) 
    billing_address = db.relationship(
     'Address', 
     foreign_keys=billing_address_id 
    ) 
    shipping_address_id = db.Column(
     db.Integer, 
     db.ForeignKey('addresses.id') 
    ) 
    shipping_address = db.relationship(
     'Address', 
     foreign_keys=shipping_address_id 
    ) 
    addresses = db.relationship(
     'Address', 
     foreign_keys='Address.customer_id', 
     back_populates='customer' 
    ) 

자동으로 Customer 인스턴스에 대한 어떤 addressesbilling_address 또는 shipping_address을 설정 추가 두 개의 이벤트 리스너도 있습니다

@event.listens_for(Customer.billing_address, 'set') 
def add_billing_address_event(target, value, oldvalue, initiator): 
    """If a billing address is added to a `Customer`, add it to addresses.""" 
    if value is not None and value not in target.addresses: 
     target.addresses.append(value) 


@event.listens_for(Customer.shipping_address, 'set') 
def add_shipping_address_event(target, value, oldvalue, initiator): 
    """If a shipping address is added to `Customer`, add to addresses.""" 
    if value is not None and value not in target.addresses: 
     target.addresses.append(value) 
,536,913,632가 나는 이벤트 리스너를 주석 경우,이 내가 무엇을 기대 또한 인은 CircularDependencyError가 발생하지 않습니다

> c = Customer() 
> c.billing_address = Address(first_name='Bill') 
> c.shipping_address = Address(first_name='Ship') 
> db.session.add(c) 
> db.session.flush() 

CircularDependencyError: Circular dependency detected. (ProcessState(ManyToOneDP(Customer.shipping_address), <Customer at 0x7f53aa5c9fd0>, delete=False), ProcessState(ManyToOneDP(Address.customer), <Address at 0x7f53aa4e4128>, delete=False), ProcessState(ManyToOneDP(Address.customer), <Address at 0x7f53aa4e4080>, delete=False), SaveUpdateState(<Customer at 0x7f53aa5c9fd0>), ProcessState(ManyToOneDP(Customer.billing_address), <Customer at 0x7f53aa5c9fd0>, delete=False), ProcessState(OneToManyDP(Customer.addresses), <Customer at 0x7f53aa5c9fd0>, delete=False), SaveUpdateState(<Address at 0x7f53aa4e4080>), SaveUpdateState(<Address at 0x7f53aa4e4128>)) 

Customer.address로 : 나는 기대로 CircularDependencyErrorCustomer.billing_addressCustomer.shipping_address 결과를 설정하려고 10

액세스 할 수 없습니다. 그러나 이것은 동일한 Address 인스턴스가 billing_address 또는 shipping_addressaddresses에 존재하는 것으로 인해 순환 종속성이 발생하므로 addresses에 현재 청구서 수신 주소와 배송 주소가 포함되도록 허용하고 싶습니다. 그러나

class Address(db.Model): 
    ... 
    customer_id = db.Column(
     db.Integer, 
     db.ForeignKey('customers.id', name='fk_customer_id') 
    ) 
    customer = db.relationship(
     'Customer', 
     foreign_keys=customer_id, 
     back_populates='addresses', 
     post_update=True 
    ) 

이 여전히 CircularDependencyError 제기 :

relevant SQLAlchemy docs에 따르면,이 관계 post_update=True 인수 한쪽을 첨가하고, 그 외부 키 이름을 부여하여 정착되어야

CircularDependencyError: Circular dependency detected. (ProcessState(OneToManyDP(Customer.addresses), <Customer at 0x7f620af3ff60>, delete=False), SaveUpdateState(<Address at 0x7f620ae5a080>), SaveUpdateState(<Address at 0x7f620ae5a128>), ProcessState(ManyToOneDP(Customer.billing_address), <Customer at 0x7f620af3ff60>, delete=False), SaveUpdateState(<Customer at 0x7f620af3ff60>), ProcessState(ManyToOneDP(Customer.shipping_address), <Customer at 0x7f620af3ff60>, delete=False)) 

관련 StackOverflow 게시물에 언급 된 customer_id 외래 키에 use_alter=True을 전달하려고 시도했습니다.

customer_id = db.Column(
    db.Integer, 
    db.ForeignKey('customers.id', name='fk_customer_id', use_alter=True) 
) 

CircularDependencyError이 여전히 발생합니다. 나는 아래에 게시 할 것으로 보이는 해결책을 찾았지만 올바른 해결책이라고 확신하지 못합니다. 관계의 양쪽 post_update=True 설정

답변

1

문제 해결 표시하십시오 shipping_address을하고 billing_address 추가/있거나 지금

class Address(db.Model): 
    ... 
    customer_id = db.Column(db.Integer, db.ForeignKey('customers.id')) 
    customer = db.relationship(
     'Customer', 
     foreign_keys=customer_id, 
     back_populates='addresses', 
     post_update=True 
    ) 

class Customer(db.Model): 
    ... 
    addresses = db.relationship(
     'Address', 
     foreign_keys='Address.customer_id', 
     back_populates='customer', 
     post_update=True 
    ) 

를 자동 문제없이 addresses 첨가된다. 새로운 billing_address 또는 shipping_address을 추가하면 이전 주소가 addresses이고 새 주소가 추가 될 것으로 예상됩니다.

SQLAlchemy 문서에 명시 적으로 언급했듯이 post_update=True은 관계의 한쪽에 설정되어야하며 둘 다 설정되어서는 안되기 때문에 내 솔루션으로 인해 예기치 않은 동작이 발생하는지 궁금합니다.제안도 customer (또는 그 반대) 작업하지만, billing_addressshipping_address에 설정되지 않은 그것을 설정하지 않고 addressespost_update=True을 설정, 어떤 이유

: -

편집 여기에 적절한 솔루션입니다 작성자 : @univerio. 감사!

class Customer(db.Model): 
... 
    billing_address = db.relationship(
     'Address', 
     foreign_keys=billing_address_id, 
     post_update=True 
    ) 
    shipping_address = db.relationship(
     'Address', 
     foreign_keys=shipping_address_id, 
     post_update=True 
    ) 
+1

"이 플래그는 하나의 관계에 배치해야"이것은 'addresses' 관계, 또는 모두'shipping_address'과'billing_address' 관계 중 어느 하나에'post_update = TRUE '로 설정하는 의미 같은 '주소'/ '고객'관계의 양면이 아닙니다. – univerio

관련 문제