feat(categories): Hierarchiczna struktura kategorii
- Dodanie parent_id do tabeli categories - Model Category z relacją parent/subcategories - 4 główne grupy: Usługi, Budownictwo, Handel, Produkcja - Skrypt assign_category_parents.py do przypisania podkategorii - Migracja 030_add_category_hierarchy.sql Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
parent
1fb938feb3
commit
4b38f8953c
13
database.py
13
database.py
@ -233,7 +233,7 @@ class User(Base, UserMixin):
|
||||
# ============================================================
|
||||
|
||||
class Category(Base):
|
||||
"""Company categories"""
|
||||
"""Company categories with hierarchical structure"""
|
||||
__tablename__ = 'categories'
|
||||
|
||||
id = Column(Integer, primary_key=True)
|
||||
@ -244,7 +244,18 @@ class Category(Base):
|
||||
sort_order = Column(Integer, default=0)
|
||||
created_at = Column(DateTime, default=datetime.now)
|
||||
|
||||
# Hierarchical structure
|
||||
parent_id = Column(Integer, ForeignKey('categories.id'), nullable=True)
|
||||
display_order = Column(Integer, default=0)
|
||||
|
||||
# Relationships
|
||||
companies = relationship('Company', back_populates='category')
|
||||
parent = relationship('Category', remote_side=[id], backref='subcategories')
|
||||
|
||||
@property
|
||||
def is_main_category(self):
|
||||
"""Check if this is a main (parent) category"""
|
||||
return self.parent_id is None
|
||||
|
||||
|
||||
class Company(Base):
|
||||
|
||||
30
database/migrations/030_add_category_hierarchy.sql
Normal file
30
database/migrations/030_add_category_hierarchy.sql
Normal file
@ -0,0 +1,30 @@
|
||||
-- Migration: Add category hierarchy (parent-child structure)
|
||||
-- Date: 2026-01-28
|
||||
-- Description: Adds parent_id to categories for 4 main groups + subcategories
|
||||
|
||||
-- Add parent_id column
|
||||
ALTER TABLE categories ADD COLUMN IF NOT EXISTS parent_id INTEGER REFERENCES categories(id);
|
||||
ALTER TABLE categories ADD COLUMN IF NOT EXISTS display_order INTEGER DEFAULT 0;
|
||||
|
||||
-- Create index for parent lookup
|
||||
CREATE INDEX IF NOT EXISTS idx_categories_parent_id ON categories(parent_id);
|
||||
|
||||
-- Insert 4 main categories (parents)
|
||||
INSERT INTO categories (name, slug, description, parent_id, display_order)
|
||||
VALUES
|
||||
('Usługi', 'uslugi', 'Firmy usługowe - IT, doradztwo, marketing, prawo, finanse', NULL, 1),
|
||||
('Budownictwo', 'budownictwo-grupa', 'Budownictwo, instalacje, architektura, nieruchomości', NULL, 2),
|
||||
('Handel', 'handel', 'Handel, hurtownie, motoryzacja, hotelarstwo', NULL, 3),
|
||||
('Produkcja', 'produkcja-grupa', 'Produkcja, wytwarzanie, rolnictwo', NULL, 4)
|
||||
ON CONFLICT (slug) DO NOTHING;
|
||||
|
||||
-- Get IDs of main categories (will be used in next migration step)
|
||||
-- Note: The actual parent assignment will be done via Python script
|
||||
-- because we need to know the exact IDs
|
||||
|
||||
-- Comments
|
||||
COMMENT ON COLUMN categories.parent_id IS 'Parent category ID for hierarchical structure (NULL = main category)';
|
||||
COMMENT ON COLUMN categories.display_order IS 'Order for display in UI';
|
||||
|
||||
-- Grant permissions
|
||||
GRANT ALL ON TABLE categories TO nordabiz_app;
|
||||
112
scripts/assign_category_parents.py
Normal file
112
scripts/assign_category_parents.py
Normal file
@ -0,0 +1,112 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Skrypt do przypisania istniejących kategorii do głównych grup.
|
||||
Uruchom po migracji 030_add_category_hierarchy.sql
|
||||
"""
|
||||
|
||||
import os
|
||||
import sys
|
||||
|
||||
# Add parent directory to path
|
||||
sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
|
||||
|
||||
from database import SessionLocal, Category
|
||||
|
||||
# Mapowanie kategorii do głównych grup
|
||||
# Klucz: slug głównej grupy, wartość: lista slugów podkategorii
|
||||
CATEGORY_MAPPING = {
|
||||
'uslugi': [
|
||||
'it-technologie',
|
||||
'it-telekomunikacja',
|
||||
'marketing',
|
||||
'uslugi-prawne',
|
||||
'ksiegowosc-finanse',
|
||||
'uslugi-biznesowe',
|
||||
'bezpieczenstwo-ochrona',
|
||||
'media',
|
||||
],
|
||||
'budownictwo-grupa': [
|
||||
'budownictwo',
|
||||
'hvac-instalacje',
|
||||
'architektura-projektowanie',
|
||||
'energia-oze',
|
||||
'nieruchomosci',
|
||||
],
|
||||
'handel': [
|
||||
'handel-hurtownie',
|
||||
'motoryzacja',
|
||||
'hotelarstwo',
|
||||
],
|
||||
'produkcja-grupa': [
|
||||
'produkcja',
|
||||
'rolnictwo',
|
||||
'inne',
|
||||
],
|
||||
}
|
||||
|
||||
|
||||
def main():
|
||||
db = SessionLocal()
|
||||
try:
|
||||
# Znajdź lub utwórz główne kategorie
|
||||
main_categories = {}
|
||||
|
||||
for main_slug, subcategory_slugs in CATEGORY_MAPPING.items():
|
||||
main_cat = db.query(Category).filter(Category.slug == main_slug).first()
|
||||
|
||||
if not main_cat:
|
||||
print(f"[!] Główna kategoria '{main_slug}' nie istnieje - tworzę...")
|
||||
# Utwórz główną kategorię
|
||||
name_map = {
|
||||
'uslugi': 'Usługi',
|
||||
'budownictwo-grupa': 'Budownictwo',
|
||||
'handel': 'Handel',
|
||||
'produkcja-grupa': 'Produkcja',
|
||||
}
|
||||
main_cat = Category(
|
||||
name=name_map.get(main_slug, main_slug),
|
||||
slug=main_slug,
|
||||
description=f'Główna kategoria: {name_map.get(main_slug, main_slug)}',
|
||||
parent_id=None,
|
||||
display_order=list(CATEGORY_MAPPING.keys()).index(main_slug) + 1
|
||||
)
|
||||
db.add(main_cat)
|
||||
db.flush() # Get ID
|
||||
|
||||
main_categories[main_slug] = main_cat
|
||||
print(f"[✓] Główna kategoria: {main_cat.name} (ID: {main_cat.id})")
|
||||
|
||||
# Przypisz podkategorie
|
||||
for sub_slug in subcategory_slugs:
|
||||
sub_cat = db.query(Category).filter(Category.slug == sub_slug).first()
|
||||
if sub_cat:
|
||||
if sub_cat.parent_id != main_cat.id:
|
||||
sub_cat.parent_id = main_cat.id
|
||||
print(f" → {sub_cat.name} przypisana do {main_cat.name}")
|
||||
else:
|
||||
print(f" ✓ {sub_cat.name} już przypisana")
|
||||
else:
|
||||
print(f" [!] Kategoria '{sub_slug}' nie istnieje - pomijam")
|
||||
|
||||
db.commit()
|
||||
print("\n[✓] Przypisanie kategorii zakończone!")
|
||||
|
||||
# Pokaż podsumowanie
|
||||
print("\n=== PODSUMOWANIE ===")
|
||||
for main_slug, main_cat in main_categories.items():
|
||||
subcats = db.query(Category).filter(Category.parent_id == main_cat.id).all()
|
||||
print(f"\n{main_cat.name} ({len(subcats)} podkategorii):")
|
||||
for sub in subcats:
|
||||
company_count = len(sub.companies) if sub.companies else 0
|
||||
print(f" - {sub.name}: {company_count} firm")
|
||||
|
||||
except Exception as e:
|
||||
print(f"[!] Błąd: {e}")
|
||||
db.rollback()
|
||||
raise
|
||||
finally:
|
||||
db.close()
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
Loading…
Reference in New Issue
Block a user