123 lines
		
	
	
		
			5.6 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
			
		
		
	
	
			123 lines
		
	
	
		
			5.6 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
| from sqlalchemy import Column, Integer, String, Float, Boolean, DateTime, ForeignKey, Table
 | |
| from sqlalchemy.ext.declarative import declarative_base
 | |
| from sqlalchemy.orm import relationship
 | |
| from sqlalchemy.sql import func
 | |
| from datetime import datetime
 | |
| 
 | |
| Base = declarative_base()
 | |
| 
 | |
| # Association table for many-to-many relationship between shopping events and products
 | |
| shopping_event_products = Table(
 | |
|     'shopping_event_products',
 | |
|     Base.metadata,
 | |
|     Column('id', Integer, primary_key=True, autoincrement=True),  # Artificial primary key
 | |
|     Column('shopping_event_id', Integer, ForeignKey('shopping_events.id'), nullable=False),
 | |
|     Column('product_id', Integer, ForeignKey('products.id'), nullable=False),
 | |
|     Column('amount', Float, nullable=False),  # Amount of this product bought in this event
 | |
|     Column('price', Float, nullable=False),  # Price of this product at the time of this shopping event
 | |
|     Column('discount', Boolean, default=False, nullable=False)  # Whether this product was purchased with a discount
 | |
| )
 | |
| 
 | |
| # Association table for many-to-many self-referential relationship between related products
 | |
| related_products = Table(
 | |
|     'related_products',
 | |
|     Base.metadata,
 | |
|     Column('id', Integer, primary_key=True, autoincrement=True),  # Artificial primary key
 | |
|     Column('product_id', Integer, ForeignKey('products.id'), nullable=False),
 | |
|     Column('related_product_id', Integer, ForeignKey('products.id'), nullable=False),
 | |
|     Column('relationship_type', String, nullable=True),  # Optional: e.g., "size_variant", "brand_variant", "similar"
 | |
|     Column('created_at', DateTime(timezone=True), server_default=func.now())
 | |
| )
 | |
| 
 | |
| class BrandInShop(Base):
 | |
|     __tablename__ = "brands_in_shops"
 | |
|     
 | |
|     id = Column(Integer, primary_key=True, index=True)
 | |
|     shop_id = Column(Integer, ForeignKey("shops.id"), nullable=False)
 | |
|     brand_id = Column(Integer, ForeignKey("brands.id"), nullable=False)
 | |
|     created_at = Column(DateTime(timezone=True), server_default=func.now())
 | |
|     updated_at = Column(DateTime(timezone=True), onupdate=func.now())
 | |
|     
 | |
|     # Relationships
 | |
|     shop = relationship("Shop", back_populates="brands_in_shop")
 | |
|     brand = relationship("Brand", back_populates="shops_with_brand")
 | |
| 
 | |
| class Brand(Base):
 | |
|     __tablename__ = "brands"
 | |
|     
 | |
|     id = Column(Integer, primary_key=True, index=True)
 | |
|     name = Column(String, nullable=False, index=True)
 | |
|     created_at = Column(DateTime(timezone=True), server_default=func.now())
 | |
|     updated_at = Column(DateTime(timezone=True), onupdate=func.now())
 | |
|     
 | |
|     # Relationships
 | |
|     products = relationship("Product", back_populates="brand")
 | |
|     shops_with_brand = relationship("BrandInShop", back_populates="brand")
 | |
| 
 | |
| class GroceryCategory(Base):
 | |
|     __tablename__ = "grocery_categories"
 | |
|     
 | |
|     id = Column(Integer, primary_key=True, index=True)
 | |
|     name = Column(String, nullable=False, index=True)
 | |
|     created_at = Column(DateTime(timezone=True), server_default=func.now())
 | |
|     updated_at = Column(DateTime(timezone=True), onupdate=func.now())
 | |
|     
 | |
|     # Relationships
 | |
|     products = relationship("Product", back_populates="category")
 | |
| 
 | |
| class Product(Base):
 | |
|     __tablename__ = "products"
 | |
|     
 | |
|     id = Column(Integer, primary_key=True, index=True)
 | |
|     name = Column(String, nullable=False, index=True)
 | |
|     category_id = Column(Integer, ForeignKey("grocery_categories.id"), nullable=False)
 | |
|     brand_id = Column(Integer, ForeignKey("brands.id"), nullable=True)
 | |
|     organic = Column(Boolean, default=False)
 | |
|     weight = Column(Float, nullable=True)  # in grams or kg
 | |
|     weight_unit = Column(String, default="piece")  # "g", "kg", "ml", "l", "piece"
 | |
|     created_at = Column(DateTime(timezone=True), server_default=func.now())
 | |
|     updated_at = Column(DateTime(timezone=True), onupdate=func.now())
 | |
|     
 | |
|     # Relationships
 | |
|     category = relationship("GroceryCategory", back_populates="products")
 | |
|     brand = relationship("Brand", back_populates="products")
 | |
|     shopping_events = relationship("ShoppingEvent", secondary=shopping_event_products, back_populates="products")
 | |
|     
 | |
|     # Self-referential many-to-many relationship for related products
 | |
|     # We'll use a simpler approach without back_populates to avoid circular references
 | |
|     related_products = relationship(
 | |
|         "Product",
 | |
|         secondary=related_products,
 | |
|         primaryjoin="Product.id == related_products.c.product_id",
 | |
|         secondaryjoin="Product.id == related_products.c.related_product_id",
 | |
|         viewonly=True
 | |
|     )
 | |
| 
 | |
| class Shop(Base):
 | |
|     __tablename__ = "shops"
 | |
|     
 | |
|     id = Column(Integer, primary_key=True, index=True)
 | |
|     name = Column(String, nullable=False, index=True)
 | |
|     city = Column(String, nullable=False)
 | |
|     address = Column(String, nullable=True)
 | |
|     created_at = Column(DateTime(timezone=True), server_default=func.now())
 | |
|     updated_at = Column(DateTime(timezone=True), onupdate=func.now())
 | |
|     
 | |
|     # Relationships
 | |
|     shopping_events = relationship("ShoppingEvent", back_populates="shop")
 | |
|     brands_in_shop = relationship("BrandInShop", back_populates="shop")
 | |
| 
 | |
| class ShoppingEvent(Base):
 | |
|     __tablename__ = "shopping_events"
 | |
|     
 | |
|     id = Column(Integer, primary_key=True, index=True)
 | |
|     shop_id = Column(Integer, ForeignKey("shops.id"), nullable=False)
 | |
|     date = Column(DateTime(timezone=True), nullable=False, default=datetime.utcnow)
 | |
|     total_amount = Column(Float, nullable=True)  # Total cost of the shopping event
 | |
|     notes = Column(String, nullable=True)
 | |
|     created_at = Column(DateTime(timezone=True), server_default=func.now())
 | |
|     updated_at = Column(DateTime(timezone=True), onupdate=func.now())
 | |
|     
 | |
|     # Relationships
 | |
|     shop = relationship("Shop", back_populates="shopping_events")
 | |
|     products = relationship("Product", secondary=shopping_event_products, back_populates="shopping_events")  |