Я создаю базу данных User
модель, которая может принадлежать нескольким Trait
с. Приведенный ниже скрипт воспроизводит странное поведение, которого я не понимаю - после фиксации новых строк отношение прикрепляет Trait
s к User
s непредсказуемым образом.
Я хочу иметь возможность прикреплять 1+ черты к пользователю, и я хочу, чтобы пользователи могли обмениваться чертами.
Но в этом примере, когда признак является общим для пользователей, признак иногда присоединяется к пользователю 1, а в другое время пользователь 2. Как я могу сделать так, чтобы пользователи могут делиться чертами?
import enum
from sqlalchemy import Column, Integer, String
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy import Enum, UniqueConstraint, ForeignKey
from sqlalchemy.orm import backref, relationship, validates
Base = declarative_base()
class TraitName(enum.Enum):
happy = 0
mad = 1
full = 2
class User(Base):
__tablename__ = 'users'
id = Column(Integer, primary_key=True)
username = Column(String(80), unique=True, nullable=False)
traits = relationship("Trait")
def __repr__(self):
return self.username + str(traits)
class Trait(Base):
__tablename__ = 'traits'
id = Column(Integer, primary_key=True)
name = Column(Enum(TraitName), nullable=False)
user_id = Column(Integer, ForeignKey('users.id'))
__table_args__ = (UniqueConstraint('name', 'user_id', name='_user_trait'),)
def __repr__(self):
return str(self.name)
Когда я запускаю этот скрипт несколько раз,
from sqlalchemy import create_engine
from sqlalchemy.exc import IntegrityError
from sqlalchemy.orm import Session
engine = create_engine('postgresql://postgres@localhost:5420/test_db')
Base.metadata.drop_all(engine)
Base.metadata.create_all(engine)
session = Session(engine)
user1 = User(username="bob")
user2 = User(username="ann")
happy_trait = Trait(name=TraitName.happy)
full_trait = Trait(name=TraitName.full)
user1.traits.extend([full_trait, happy_trait])
user2.traits.append(happy_trait)
session.add_all([user1, user2])
session.commit()
print([t.traits for t in session.query(User).all()])
print(session.query(Trait.user_id).all())
print(session.query(Trait).filter(Trait.user_id.in_((1,))).all())
session.close()
разные результаты:
либо:
[[TraitName.full, TraitName.happy], []] # Users' traits
[(1,), (1,)] # Traits' user_ids
[TraitName.full, TraitName.happy] # Traits with uers_id 1
или
[[TraitName.full], [TraitName.happy]] # Users' traits
[(1,), (2,)] # Traits' user_ids
[TraitName.full] # Traits with uers_id 1
Поэтому я хотел бы понять, почему Trait
будет назначен непредсказуемо. И как я могу смоделировать своих пользователей и черты, чтобы избежать этого - может быть, это не подходящий шаблон для привязки черт к пользователям?
Кроме того, если это возможно (я полагаю, что все возможно), я хотел бы иметь два поля в полях User
: inactive_traits
и active_traits
. Но в любом случае мне сначала нужно выяснить, как заставить работать один список черт.