# plugins/plant/models.py from datetime import datetime import uuid as uuid_lib from app import db from plugins.media.models import Media # import Media so we can refer to Media.plant_id # Association table for Plant ↔ Tag (unchanged) plant_tags = db.Table( 'plant_tags', db.metadata, db.Column('plant_id', db.Integer, db.ForeignKey('plant.id'), primary_key=True), db.Column('tag_id', db.Integer, db.ForeignKey('tag.id'), primary_key=True), extend_existing=True ) class Tag(db.Model): __tablename__ = 'tag' __table_args__ = {'extend_existing': True} id = db.Column(db.Integer, primary_key=True) name = db.Column(db.String(128), unique=True, nullable=False) class PlantCommonName(db.Model): __tablename__ = 'plant_common_name' __table_args__ = {'extend_existing': True} id = db.Column(db.Integer, primary_key=True) name = db.Column(db.String(128), unique=True, nullable=False) created_at = db.Column(db.DateTime, default=datetime.utcnow) scientific_names = db.relationship( 'plugins.plant.models.PlantScientificName', backref=db.backref('common', lazy='joined'), lazy=True, cascade='all, delete-orphan' ) class PlantScientificName(db.Model): __tablename__ = 'plant_scientific_name' __table_args__ = {'extend_existing': True} id = db.Column(db.Integer, primary_key=True) name = db.Column(db.String(256), unique=True, nullable=False) common_id = db.Column(db.Integer, db.ForeignKey('plant_common_name.id'), nullable=False) created_at = db.Column(db.DateTime, default=datetime.utcnow) class PlantOwnershipLog(db.Model): __tablename__ = 'plant_ownership_log' __table_args__ = {'extend_existing': True} id = db.Column(db.Integer, primary_key=True) plant_id = db.Column(db.Integer, db.ForeignKey('plant.id'), nullable=False) user_id = db.Column(db.Integer, db.ForeignKey('users.id'), nullable=False) date_acquired = db.Column(db.DateTime, default=datetime.utcnow) transferred = db.Column(db.Boolean, default=False, nullable=False) is_verified = db.Column(db.Boolean, default=False, nullable=False) user = db.relationship( 'plugins.auth.models.User', backref='ownership_logs', lazy=True ) class Plant(db.Model): __tablename__ = 'plant' __table_args__ = {'extend_existing': True} id = db.Column(db.Integer, primary_key=True) uuid = db.Column(db.String(36), default=lambda: str(uuid_lib.uuid4()), unique=True, nullable=False) custom_slug = db.Column(db.String(255), unique=True, nullable=True) owner_id = db.Column(db.Integer, db.ForeignKey('users.id'), nullable=False) common_id = db.Column(db.Integer, db.ForeignKey('plant_common_name.id'), nullable=False) scientific_id = db.Column(db.Integer, db.ForeignKey('plant_scientific_name.id'), nullable=False) mother_uuid = db.Column(db.String(36), db.ForeignKey('plant.uuid'), nullable=True) plant_type = db.Column(db.String(50), nullable=False) notes = db.Column(db.Text, nullable=True) is_active = db.Column(db.Boolean, default=True, nullable=False) featured_media_id = db.Column(db.Integer, db.ForeignKey('media.id'), nullable=True) created_at = db.Column(db.DateTime, default=datetime.utcnow) updated_at = db.Column(db.DateTime, onupdate=datetime.utcnow) data_verified = db.Column(db.Boolean, default=False, nullable=False) # ─── FIXED: explicitly join on Media.plant_id ────────────────────────────── media = db.relationship( Media, backref='plant', lazy=True, cascade='all, delete-orphan', foreign_keys=[Media.plant_id] ) featured_media = db.relationship( Media, foreign_keys=[featured_media_id], uselist=False ) updates = db.relationship( 'plugins.growlog.models.PlantUpdate', backref='plant', lazy=True, cascade='all, delete-orphan' ) tags = db.relationship( Tag, secondary=plant_tags, backref='plants', lazy='dynamic' ) common_name = db.relationship( PlantCommonName, backref=db.backref('plants', lazy='dynamic'), lazy=True ) scientific_name = db.relationship( PlantScientificName, backref=db.backref('plants', lazy='dynamic'), lazy=True ) ownership_logs = db.relationship( PlantOwnershipLog, backref='plant', lazy=True, cascade='all, delete-orphan' ) def __repr__(self): return f""