from flask import Flask, render_template, request, redirect, url_for, flash, session from flask_sqlalchemy import SQLAlchemy from flask_migrate import Migrate from datetime import datetime from werkzeug.security import generate_password_hash, check_password_hash from werkzeug.utils import secure_filename import os from config import Config app = Flask(__name__) app.config.from_object(Config) os.makedirs(app.config['UPLOAD_FOLDER'], exist_ok=True) db = SQLAlchemy(app) migrate = Migrate(app, db) # Database Models class User(db.Model): id = db.Column(db.Integer, primary_key=True) username = db.Column(db.String(80), unique=True, nullable=False) password_hash = db.Column(db.String(256), nullable=False) def set_password(self, password): self.password_hash = generate_password_hash(password) def check_password(self, password): return check_password_hash(self.password_hash, password) class Environment(db.Model): id = db.Column(db.Integer, primary_key=True) name = db.Column(db.String(100), unique=True, nullable=False) description = db.Column(db.Text, nullable=True) icon = db.Column(db.String(200), nullable=True) def __repr__(self): return f"Environment('{self.name}')" class Climate(db.Model): id = db.Column(db.Integer, primary_key=True) name = db.Column(db.String(100), unique=True, nullable=False) description = db.Column(db.Text, nullable=True) icon = db.Column(db.String(200), nullable=True) def __repr__(self): return f"Climate('{self.name}')" class Product(db.Model): id = db.Column(db.Integer, primary_key=True) name = db.Column(db.String(100), unique=True, nullable=False) description = db.Column(db.Text, nullable=True) def __repr__(self): return f"Product('{self.name}')" class Section(db.Model): id = db.Column(db.Integer, primary_key=True) name = db.Column(db.String(50), nullable=False, unique=True) description = db.Column(db.Text, nullable=True) icon = db.Column(db.String(200), nullable=True) def __repr__(self): return f"Section('{self.name}')" class Plant(db.Model): id = db.Column(db.Integer, primary_key=True) name = db.Column(db.String(100), nullable=False) picture = db.Column(db.String(200), nullable=True) climate_id = db.Column(db.Integer, db.ForeignKey('climate.id'), nullable=True) environment_id = db.Column(db.Integer, db.ForeignKey('environment.id'), nullable=True) light_id = db.Column(db.Integer, db.ForeignKey('light.id'), nullable=True) toxicity_id = db.Column(db.Integer, db.ForeignKey('toxicity.id'), nullable=True) size_id = db.Column(db.Integer, db.ForeignKey('size.id'), nullable=True) care_difficulty_id = db.Column(db.Integer, db.ForeignKey('care_difficulty.id'), nullable=True) growth_rate_id = db.Column(db.Integer, db.ForeignKey('growth_rate.id'), nullable=True) # Make section_id nullable and handle missing column try: section_id = db.Column(db.Integer, db.ForeignKey('section.id'), nullable=True) except Exception: section_id = None products = db.Column(db.Text, nullable=True) # Will store product IDs as comma-separated values description = db.Column(db.Text, nullable=True) date_added = db.Column(db.DateTime, nullable=False, default=datetime.utcnow) care_guide = db.Column(db.Text, nullable=True) # New rich text care guide climate = db.relationship('Climate', backref='plants') environment = db.relationship('Environment', backref='plants') light = db.relationship('Light', backref='plant_light') toxicity = db.relationship('Toxicity', backref='plant_toxicity') size = db.relationship('Size', backref='plant_size') care_difficulty = db.relationship('CareDifficulty', backref='plant_care_difficulty') growth_rate = db.relationship('GrowthRate', backref='plant_growth_rate') # Make section relationship optional try: section = db.relationship('Section', backref='plants') except Exception: section = None def __repr__(self): return f"Plant('{self.name}', '{self.date_added}')" class Light(db.Model): id = db.Column(db.Integer, primary_key=True) name = db.Column(db.String(50), nullable=False, unique=True) description = db.Column(db.Text, nullable=True) icon = db.Column(db.String(200), nullable=True) def __repr__(self): return f"Light('{self.name}')" class Toxicity(db.Model): id = db.Column(db.Integer, primary_key=True) name = db.Column(db.String(50), nullable=False, unique=True) description = db.Column(db.Text, nullable=True) icon = db.Column(db.String(200), nullable=True) def __repr__(self): return f"Toxicity('{self.name}')" class Size(db.Model): id = db.Column(db.Integer, primary_key=True) name = db.Column(db.String(50), nullable=False, unique=True) description = db.Column(db.Text, nullable=True) icon = db.Column(db.String(200), nullable=True) def __repr__(self): return f"Size('{self.name}')" class CareDifficulty(db.Model): id = db.Column(db.Integer, primary_key=True) name = db.Column(db.String(50), nullable=False, unique=True) description = db.Column(db.Text, nullable=True) icon = db.Column(db.String(200), nullable=True) def __repr__(self): return f"CareDifficulty('{self.name}')" class GrowthRate(db.Model): id = db.Column(db.Integer, primary_key=True) name = db.Column(db.String(50), nullable=False, unique=True) description = db.Column(db.Text, nullable=True) icon = db.Column(db.String(200), nullable=True) def __repr__(self): return f"GrowthRate('{self.name}')" # Helper function def is_logged_in(): return session.get('user_id') is not None @app.context_processor def inject_is_logged_in(): return dict(is_logged_in=is_logged_in()) @app.context_processor def inject_admin_counts(): try: environment_count = Environment.query.count() climate_count = Climate.query.count() product_count = Product.query.count() plant_count = Plant.query.count() section_count = Section.query.count() except Exception: environment_count = climate_count = product_count = plant_count = section_count = 0 return dict( environment_count=environment_count, climate_count=climate_count, product_count=product_count, plant_count=plant_count, section_count=section_count ) def none_if_empty(val): return val if val not in (None, '', 'None') else None # Routes @app.route('/') def home(): search = request.args.get('search', '').strip() climate_id = request.args.get('climate') environment_id = request.args.get('environment') light_id = request.args.get('light') toxicity_id = request.args.get('toxicity') size_id = request.args.get('size') care_difficulty_id = request.args.get('care_difficulty') growth_rate_id = request.args.get('growth_rate') section_id = request.args.get('section') query = Plant.query if search: query = query.filter(Plant.name.ilike(f'%{search}%')) if climate_id: query = query.filter(Plant.climate_id == climate_id) if environment_id: query = query.filter(Plant.environment_id == environment_id) if light_id: query = query.filter(Plant.light_id == light_id) if toxicity_id: query = query.filter(Plant.toxicity_id == toxicity_id) if size_id: query = query.filter(Plant.size_id == size_id) if care_difficulty_id: query = query.filter(Plant.care_difficulty_id == care_difficulty_id) if growth_rate_id: query = query.filter(Plant.growth_rate_id == growth_rate_id) if section_id: query = query.filter(Plant.section_id == section_id) plants = query.order_by(Plant.date_added.desc()).all() climates_dict = {c.id: {'name': c.name, 'icon': c.icon, 'description': c.description} for c in Climate.query.all()} environments_dict = {e.id: {'name': e.name, 'icon': e.icon, 'description': e.description} for e in Environment.query.all()} products_dict = {p.id: p.name for p in Product.query.all()} display_plants = [] for plant in plants: product_names = [] if plant.products: for pid in plant.products.split(','): pid = pid.strip() if pid.isdigit() and int(pid) in products_dict: product_names.append(products_dict[int(pid)]) climate_info = climates_dict.get(plant.climate_id, {'name': '', 'icon': None, 'description': ''}) environment_info = environments_dict.get(plant.environment_id, {'name': '', 'icon': None, 'description': ''}) display_plants.append({ 'id': plant.id, 'name': plant.name, 'picture': plant.picture, 'climate': climate_info['name'], 'climate_icon': climate_info['icon'], 'climate_description': climate_info['description'], 'environment': environment_info['name'], 'environment_icon': environment_info['icon'], 'environment_description': environment_info['description'], 'products': ', '.join(product_names), 'description': plant.description, 'date_added': plant.date_added, 'light': plant.light.name if plant.light else '', 'light_icon': plant.light.icon if plant.light and plant.light.icon else None, 'light_description': plant.light.description if plant.light else '', 'toxicity': plant.toxicity.name if plant.toxicity else '', 'toxicity_icon': plant.toxicity.icon if plant.toxicity and plant.toxicity.icon else None, 'toxicity_description': plant.toxicity.description if plant.toxicity else '', 'size': plant.size.name if plant.size else '', 'size_icon': plant.size.icon if plant.size and plant.size.icon else None, 'size_description': plant.size.description if plant.size else '', 'care_difficulty': plant.care_difficulty.name if plant.care_difficulty else '', 'care_difficulty_icon': plant.care_difficulty.icon if plant.care_difficulty and plant.care_difficulty.icon else None, 'care_difficulty_description': plant.care_difficulty.description if plant.care_difficulty else '', 'growth_rate': plant.growth_rate.name if plant.growth_rate else '', 'growth_rate_icon': plant.growth_rate.icon if plant.growth_rate and plant.growth_rate.icon else None, 'growth_rate_description': plant.growth_rate.description if plant.growth_rate else '', 'section': plant.section }) return render_template('home.html', plants=display_plants, climates=Climate.query.all(), environments=Environment.query.all(), lights=Light.query.all(), toxicities=Toxicity.query.all(), sizes=Size.query.all(), difficulties=CareDifficulty.query.all(), growth_rates=GrowthRate.query.all(), sections=Section.query.all(), search=search, selected_climate=climate_id, selected_environment=environment_id, selected_light=light_id, selected_toxicity=toxicity_id, selected_size=size_id, selected_care_difficulty=care_difficulty_id, selected_growth_rate=growth_rate_id, selected_section=section_id) @app.route('/login', methods=['GET', 'POST']) def login(): if request.method == 'POST': username = request.form['username'] password = request.form['password'] user = User.query.filter_by(username=username).first() if user and user.check_password(password): session['user_id'] = user.id flash('Logged in successfully!', 'success') return redirect(url_for('manage_environments')) else: flash('Invalid username or password', 'danger') return render_template('login.html') @app.route('/logout') def logout(): session.pop('user_id', None) flash('Logged out successfully.', 'success') return redirect(url_for('home')) # Environment management routes @app.route('/admin/environments', methods=['GET', 'POST']) def manage_environments(): if not is_logged_in(): return redirect(url_for('login')) if request.method == 'POST': name = request.form['name'] description = request.form['description'] icon_file = request.files.get('icon') icon_filename = None if not name: flash('Name is required!', 'danger') print('No name provided') return redirect(url_for('manage_environments')) if Environment.query.filter_by(name=name).first(): flash('Environment with this name already exists!', 'danger') print('Duplicate environment name') return redirect(url_for('manage_environments')) if icon_file and icon_file.filename: icon_filename = secure_filename(icon_file.filename) icon_path = os.path.join('static/icons', icon_filename) os.makedirs('static/icons', exist_ok=True) try: icon_file.save(icon_path) except Exception as e: print('Error saving icon:', e) flash(f'Error saving icon: {e}', 'danger') try: environment = Environment(name=name, description=description, icon=icon_filename) db.session.add(environment) db.session.commit() flash('Environment added successfully!', 'success') print('Environment added:', name) except Exception as e: db.session.rollback() print('Error adding environment:', e) flash(f'Error adding environment: {e}', 'danger') return redirect(url_for('manage_environments')) environments = Environment.query.all() return render_template('manage_environments.html', environments=environments, plant_count=len(Plant.query.all()), climate_count=len(Climate.query.all()), environment_count=len(environments), product_count=len(Product.query.all()), light_count=len(Light.query.all()), toxicity_count=len(Toxicity.query.all()), size_count=len(Size.query.all()), difficulty_count=len(CareDifficulty.query.all()), rate_count=len(GrowthRate.query.all())) @app.route('/admin/environments/edit/', methods=['GET', 'POST']) def edit_environment(environment_id): if not is_logged_in(): return redirect(url_for('login')) environment = Environment.query.get_or_404(environment_id) if request.method == 'POST': environment.name = request.form['name'] environment.description = request.form['description'] icon_file = request.files.get('icon') if icon_file and icon_file.filename: icon_filename = secure_filename(icon_file.filename) icon_path = os.path.join('static/icons', icon_filename) os.makedirs('static/icons', exist_ok=True) try: icon_file.save(icon_path) except Exception as e: print('Error saving icon:', e) environment.icon = icon_filename db.session.commit() flash('Environment updated successfully!', 'success') return redirect(url_for('manage_environments')) return render_template('edit_environment.html', environment=environment) @app.route('/admin/environments/delete/', methods=['POST']) def delete_environment(environment_id): if not is_logged_in(): return redirect(url_for('login')) environment = Environment.query.get_or_404(environment_id) db.session.delete(environment) db.session.commit() flash('Environment deleted successfully!', 'success') return redirect(url_for('manage_environments')) # Climate management routes @app.route('/admin/climates', methods=['GET', 'POST']) def manage_climates(): if not is_logged_in(): return redirect(url_for('login')) if request.method == 'POST': name = request.form['name'] description = request.form['description'] icon_file = request.files.get('icon') icon_filename = None if not name: flash('Name is required!', 'danger') print('No name provided') return redirect(url_for('manage_climates')) if Climate.query.filter_by(name=name).first(): flash('Climate with this name already exists!', 'danger') print('Duplicate climate name') return redirect(url_for('manage_climates')) if icon_file and icon_file.filename: icon_filename = secure_filename(icon_file.filename) icon_path = os.path.join('static/icons', icon_filename) os.makedirs('static/icons', exist_ok=True) try: icon_file.save(icon_path) except Exception as e: print('Error saving icon:', e) flash(f'Error saving icon: {e}', 'danger') try: climate = Climate(name=name, description=description, icon=icon_filename) db.session.add(climate) db.session.commit() flash('Climate added successfully!', 'success') print('Climate added:', name) except Exception as e: db.session.rollback() print('Error adding climate:', e) flash(f'Error adding climate: {e}', 'danger') return redirect(url_for('manage_climates')) climates = Climate.query.all() return render_template('manage_climates.html', climates=climates, plant_count=len(Plant.query.all()), climate_count=len(climates), environment_count=len(Environment.query.all()), product_count=len(Product.query.all()), light_count=len(Light.query.all()), toxicity_count=len(Toxicity.query.all()), size_count=len(Size.query.all()), difficulty_count=len(CareDifficulty.query.all()), rate_count=len(GrowthRate.query.all())) @app.route('/admin/climates/edit/', methods=['GET', 'POST']) def edit_climate(climate_id): if not is_logged_in(): return redirect(url_for('login')) climate = Climate.query.get_or_404(climate_id) if request.method == 'POST': climate.name = request.form['name'] climate.description = request.form['description'] icon_file = request.files.get('icon') if icon_file and icon_file.filename: icon_filename = secure_filename(icon_file.filename) icon_path = os.path.join('static/icons', icon_filename) os.makedirs('static/icons', exist_ok=True) try: icon_file.save(icon_path) except Exception as e: print('Error saving icon:', e) climate.icon = icon_filename db.session.commit() flash('Climate updated successfully!', 'success') return redirect(url_for('manage_climates')) return render_template('edit_climate.html', climate=climate) @app.route('/admin/climates/delete/', methods=['POST']) def delete_climate(climate_id): if not is_logged_in(): return redirect(url_for('login')) climate = Climate.query.get_or_404(climate_id) db.session.delete(climate) db.session.commit() flash('Climate deleted successfully!', 'success') return redirect(url_for('manage_climates')) # Product management routes @app.route('/admin/products', methods=['GET', 'POST']) def manage_products(): if not is_logged_in(): return redirect(url_for('login')) if request.method == 'POST': name = request.form['name'] description = request.form['description'] product = Product(name=name, description=description) db.session.add(product) db.session.commit() flash('Product added successfully!', 'success') return redirect(url_for('manage_products')) products = Product.query.all() return render_template('manage_products.html', products=products, plant_count=len(Plant.query.all()), climate_count=len(Climate.query.all()), environment_count=len(Environment.query.all()), product_count=len(products), light_count=len(Light.query.all()), toxicity_count=len(Toxicity.query.all()), size_count=len(Size.query.all()), difficulty_count=len(CareDifficulty.query.all()), rate_count=len(GrowthRate.query.all())) @app.route('/admin/products/edit/', methods=['GET', 'POST']) def edit_product(product_id): if not is_logged_in(): return redirect(url_for('login')) product = Product.query.get_or_404(product_id) if request.method == 'POST': product.name = request.form['name'] product.description = request.form['description'] db.session.commit() flash('Product updated successfully!', 'success') return redirect(url_for('manage_products')) return render_template('edit_product.html', product=product) @app.route('/admin/products/delete/', methods=['POST']) def delete_product(product_id): if not is_logged_in(): return redirect(url_for('login')) product = Product.query.get_or_404(product_id) db.session.delete(product) db.session.commit() flash('Product deleted successfully!', 'success') return redirect(url_for('manage_products')) @app.route('/plant/new', methods=['GET', 'POST']) def new_plant(): if not is_logged_in(): flash('You must be logged in as admin to add a plant.', 'danger') return redirect(url_for('login')) if request.method == 'POST': name = request.form['name'] climate_id = request.form['climate_id'] environment_id = request.form['environment_id'] light_id = request.form.get('light_id') toxicity_id = request.form.get('toxicity_id') size_id = request.form.get('size_id') care_difficulty_id = request.form.get('care_difficulty_id') growth_rate_id = request.form.get('growth_rate_id') product_ids = request.form.getlist('product_ids') description = request.form['description'] care_guide = request.form.get('care_guide') picture_file = request.files.get('picture') picture_filename = None # Required field checks if not name: flash('Name is required!', 'danger') print('No name provided') return redirect(url_for('new_plant')) if not climate_id: flash('Climate is required!', 'danger') print('No climate provided') return redirect(url_for('new_plant')) if not environment_id: flash('Environment is required!', 'danger') print('No environment provided') return redirect(url_for('new_plant')) if Plant.query.filter_by(name=name).first(): flash('A plant with this name already exists!', 'danger') print('Duplicate plant name') return redirect(url_for('new_plant')) if picture_file and picture_file.filename: filename = secure_filename(picture_file.filename) picture_path = os.path.join(app.config['UPLOAD_FOLDER'], filename) try: picture_file.save(picture_path) picture_filename = filename except Exception as e: print('Error saving plant picture:', e) flash(f'Error saving plant picture: {e}', 'danger') try: plant = Plant( name=name, picture=picture_filename, climate_id=none_if_empty(climate_id), environment_id=none_if_empty(environment_id), light_id=none_if_empty(light_id), toxicity_id=none_if_empty(toxicity_id), size_id=none_if_empty(size_id), care_difficulty_id=none_if_empty(care_difficulty_id), growth_rate_id=none_if_empty(growth_rate_id), products=','.join(product_ids), description=description, care_guide=care_guide ) db.session.add(plant) db.session.commit() flash('Your plant has been added!', 'success') print('Plant added:', name) return redirect(url_for('manage_plants', add=1)) except Exception as e: db.session.rollback() print('Error adding plant:', e) flash(f'Error adding plant: {e}', 'danger') return redirect(url_for('new_plant')) climates = Climate.query.all() environments = Environment.query.all() products = Product.query.all() lights = Light.query.order_by(Light.name).all() toxicities = Toxicity.query.order_by(Toxicity.name).all() sizes = Size.query.order_by(Size.name).all() difficulties = CareDifficulty.query.order_by(CareDifficulty.name).all() growth_rates = GrowthRate.query.order_by(GrowthRate.name).all() return render_template('create_plant.html', climates=climates, environments=environments, products=products, lights=lights, toxicities=toxicities, sizes=sizes, difficulties=difficulties, growth_rates=growth_rates) @app.route('/plant/') def plant(plant_id): plant = Plant.query.get_or_404(plant_id) product_ids = plant.products.split(',') if plant.products else [] products = Product.query.filter(Product.id.in_(product_ids)).all() if product_ids else [] return render_template('post.html', plant=plant, products=products) @app.route('/plant/edit/', methods=['GET', 'POST']) def edit_plant(plant_id): if not is_logged_in(): flash('You must be logged in as admin to edit a plant.', 'danger') return redirect(url_for('login')) plant = Plant.query.get_or_404(plant_id) climates = Climate.query.all() environments = Environment.query.all() products = Product.query.all() lights = Light.query.order_by(Light.name).all() toxicities = Toxicity.query.order_by(Toxicity.name).all() sizes = Size.query.order_by(Size.name).all() difficulties = CareDifficulty.query.order_by(CareDifficulty.name).all() growth_rates = GrowthRate.query.order_by(GrowthRate.name).all() sections = Section.query.order_by(Section.name).all() if request.method == 'POST': plant.name = request.form['name'] plant.climate_id = request.form['climate_id'] plant.environment_id = request.form['environment_id'] plant.light_id = request.form.get('light_id') plant.toxicity_id = request.form.get('toxicity_id') plant.size_id = request.form.get('size_id') plant.care_difficulty_id = request.form.get('care_difficulty_id') plant.growth_rate_id = request.form.get('growth_rate_id') plant.section_id = request.form.get('section_id') plant.products = ','.join(request.form.getlist('product_ids')) plant.description = request.form['description'] plant.care_guide = request.form.get('care_guide') picture_file = request.files.get('picture') if picture_file and picture_file.filename: filename = secure_filename(picture_file.filename) picture_path = os.path.join(app.config['UPLOAD_FOLDER'], filename) os.makedirs('static/icons', exist_ok=True) try: picture_file.save(picture_path) except Exception as e: print('Error saving icon:', e) plant.picture = filename db.session.commit() flash('Plant updated successfully!', 'success') return redirect(url_for('plant', plant_id=plant.id)) selected_products = plant.products.split(',') if plant.products else [] return render_template('edit_plant.html', plant=plant, climates=climates, environments=environments, products=products, selected_products=selected_products, lights=lights, toxicities=toxicities, sizes=sizes, difficulties=difficulties, growth_rates=growth_rates, sections=sections) @app.route('/plant/delete/', methods=['POST']) def delete_plant(plant_id): if not is_logged_in(): flash('You must be logged in as admin to delete a plant.', 'danger') return redirect(url_for('login')) plant = Plant.query.get_or_404(plant_id) db.session.delete(plant) db.session.commit() flash('Plant deleted successfully!', 'success') return redirect(url_for('manage_plants')) @app.route('/admin/plants') def manage_plants(): plants = Plant.query.all() climates = Climate.query.all() environments = Environment.query.all() products = Product.query.all() lights = Light.query.order_by(Light.name).all() toxicities = Toxicity.query.order_by(Toxicity.name).all() sizes = Size.query.order_by(Size.name).all() difficulties = CareDifficulty.query.order_by(CareDifficulty.name).all() growth_rates = GrowthRate.query.order_by(GrowthRate.name).all() # Create dictionaries for easy lookup climates_dict = {climate.id: climate.name for climate in climates} environments_dict = {env.id: env.name for env in environments} return render_template('manage_plants.html', plants=plants, climates=climates, # list for form environments=environments, # list for form climates_dict=climates_dict, # dict for table environments_dict=environments_dict, # dict for table products=products, lights=lights, toxicities=toxicities, sizes=sizes, difficulties=difficulties, growth_rates=growth_rates, plant_count=len(plants), climate_count=len(climates), environment_count=len(environments), product_count=len(products), light_count=len(lights), toxicity_count=len(toxicities), size_count=len(sizes), difficulty_count=len(difficulties), rate_count=len(growth_rates)) @app.route('/admin/attributes') def manage_attributes(): if not is_logged_in(): return redirect(url_for('login')) lights = Light.query.order_by(Light.name).all() toxicities = Toxicity.query.order_by(Toxicity.name).all() sizes = Size.query.order_by(Size.name).all() difficulties = CareDifficulty.query.order_by(CareDifficulty.name).all() growth_rates = GrowthRate.query.order_by(GrowthRate.name).all() return render_template('manage_attributes.html', lights=lights, toxicities=toxicities, sizes=sizes, difficulties=difficulties, growth_rates=growth_rates) # Light management routes @app.route('/admin/lights', methods=['GET', 'POST']) def manage_lights(): if not is_logged_in(): return redirect(url_for('login')) if request.method == 'POST': name = request.form['name'] description = request.form['description'] icon_file = request.files.get('icon') icon_filename = None if not name: flash('Name is required!', 'danger') print('No name provided') return redirect(url_for('manage_lights')) if Light.query.filter_by(name=name).first(): flash('Light requirement with this name already exists!', 'danger') print('Duplicate light name') return redirect(url_for('manage_lights')) if icon_file and icon_file.filename: icon_filename = secure_filename(icon_file.filename) icon_path = os.path.join('static/icons', icon_filename) os.makedirs('static/icons', exist_ok=True) try: icon_file.save(icon_path) except Exception as e: print('Error saving icon:', e) flash(f'Error saving icon: {e}', 'danger') try: light = Light(name=name, description=description, icon=icon_filename) db.session.add(light) db.session.commit() flash('Light requirement added successfully!', 'success') print('Light added:', name) except Exception as e: db.session.rollback() print('Error adding light:', e) flash(f'Error adding light: {e}', 'danger') return redirect(url_for('manage_lights')) lights = Light.query.all() return render_template('manage_lights.html', lights=lights, plant_count=len(Plant.query.all()), climate_count=len(Climate.query.all()), environment_count=len(Environment.query.all()), product_count=len(Product.query.all()), light_count=len(lights), toxicity_count=len(Toxicity.query.all()), size_count=len(Size.query.all()), difficulty_count=len(CareDifficulty.query.all()), rate_count=len(GrowthRate.query.all())) @app.route('/admin/lights/edit/', methods=['GET', 'POST']) def edit_light(light_id): if not is_logged_in(): return redirect(url_for('login')) light = Light.query.get_or_404(light_id) if request.method == 'POST': light.name = request.form['name'] light.description = request.form['description'] icon_file = request.files.get('icon') if icon_file and icon_file.filename: icon_filename = secure_filename(icon_file.filename) icon_path = os.path.join('static/icons', icon_filename) os.makedirs('static/icons', exist_ok=True) try: icon_file.save(icon_path) except Exception as e: print('Error saving icon:', e) light.icon = icon_filename db.session.commit() flash('Light requirement updated successfully!', 'success') return redirect(url_for('manage_lights')) return render_template('edit_light.html', light=light) @app.route('/admin/lights/delete/', methods=['POST']) def delete_light(light_id): if not is_logged_in(): return redirect(url_for('login')) light = Light.query.get_or_404(light_id) db.session.delete(light) db.session.commit() flash('Light requirement deleted successfully!', 'success') return redirect(url_for('manage_lights')) # Toxicity management routes @app.route('/admin/toxicities', methods=['GET', 'POST']) def manage_toxicities(): if not is_logged_in(): return redirect(url_for('login')) if request.method == 'POST': name = request.form['name'] description = request.form['description'] icon_file = request.files.get('icon') icon_filename = None if not name: flash('Name is required!', 'danger') print('No name provided') return redirect(url_for('manage_toxicities')) if Toxicity.query.filter_by(name=name).first(): flash('Toxicity with this name already exists!', 'danger') print('Duplicate toxicity name') return redirect(url_for('manage_toxicities')) if icon_file and icon_file.filename: icon_filename = secure_filename(icon_file.filename) icon_path = os.path.join('static/icons', icon_filename) os.makedirs('static/icons', exist_ok=True) try: icon_file.save(icon_path) except Exception as e: print('Error saving icon:', e) flash(f'Error saving icon: {e}', 'danger') try: toxicity = Toxicity(name=name, description=description, icon=icon_filename) db.session.add(toxicity) db.session.commit() flash('Toxicity level added successfully!', 'success') print('Toxicity added:', name) except Exception as e: db.session.rollback() print('Error adding toxicity:', e) flash(f'Error adding toxicity: {e}', 'danger') return redirect(url_for('manage_toxicities')) toxicities = Toxicity.query.all() return render_template('manage_toxicities.html', toxicities=toxicities, plant_count=len(Plant.query.all()), climate_count=len(Climate.query.all()), environment_count=len(Environment.query.all()), product_count=len(Product.query.all()), light_count=len(Light.query.all()), toxicity_count=len(toxicities), size_count=len(Size.query.all()), difficulty_count=len(CareDifficulty.query.all()), rate_count=len(GrowthRate.query.all())) @app.route('/admin/toxicities/edit/', methods=['GET', 'POST']) def edit_toxicity(toxicity_id): if not is_logged_in(): return redirect(url_for('login')) toxicity = Toxicity.query.get_or_404(toxicity_id) if request.method == 'POST': toxicity.name = request.form['name'] toxicity.description = request.form['description'] icon_file = request.files.get('icon') if icon_file and icon_file.filename: icon_filename = secure_filename(icon_file.filename) icon_path = os.path.join('static/icons', icon_filename) os.makedirs('static/icons', exist_ok=True) try: icon_file.save(icon_path) except Exception as e: print('Error saving icon:', e) toxicity.icon = icon_filename db.session.commit() flash('Toxicity level updated successfully!', 'success') return redirect(url_for('manage_toxicities')) return render_template('edit_toxicity.html', toxicity=toxicity) @app.route('/admin/toxicities/delete/', methods=['POST']) def delete_toxicity(toxicity_id): if not is_logged_in(): return redirect(url_for('login')) toxicity = Toxicity.query.get_or_404(toxicity_id) db.session.delete(toxicity) db.session.commit() flash('Toxicity level deleted successfully!', 'success') return redirect(url_for('manage_toxicities')) # Size management routes @app.route('/admin/sizes', methods=['GET', 'POST']) def manage_sizes(): if not is_logged_in(): return redirect(url_for('login')) if request.method == 'POST': name = request.form['name'] description = request.form['description'] icon_file = request.files.get('icon') icon_filename = None if not name: flash('Name is required!', 'danger') print('No name provided') return redirect(url_for('manage_sizes')) if Size.query.filter_by(name=name).first(): flash('Size with this name already exists!', 'danger') print('Duplicate size name') return redirect(url_for('manage_sizes')) if icon_file and icon_file.filename: icon_filename = secure_filename(icon_file.filename) icon_path = os.path.join('static/icons', icon_filename) os.makedirs('static/icons', exist_ok=True) try: icon_file.save(icon_path) except Exception as e: print('Error saving icon:', e) flash(f'Error saving icon: {e}', 'danger') try: size = Size(name=name, description=description, icon=icon_filename) db.session.add(size) db.session.commit() flash('Size category added successfully!', 'success') print('Size added:', name) except Exception as e: db.session.rollback() print('Error adding size:', e) flash(f'Error adding size: {e}', 'danger') return redirect(url_for('manage_sizes')) sizes = Size.query.all() return render_template('manage_sizes.html', sizes=sizes, plant_count=len(Plant.query.all()), climate_count=len(Climate.query.all()), environment_count=len(Environment.query.all()), product_count=len(Product.query.all()), light_count=len(Light.query.all()), toxicity_count=len(Toxicity.query.all()), size_count=len(sizes), difficulty_count=len(CareDifficulty.query.all()), rate_count=len(GrowthRate.query.all())) @app.route('/admin/sizes/edit/', methods=['GET', 'POST']) def edit_size(size_id): if not is_logged_in(): return redirect(url_for('login')) size = Size.query.get_or_404(size_id) if request.method == 'POST': size.name = request.form['name'] size.description = request.form['description'] icon_file = request.files.get('icon') if icon_file and icon_file.filename: icon_filename = secure_filename(icon_file.filename) icon_path = os.path.join('static/icons', icon_filename) os.makedirs('static/icons', exist_ok=True) try: icon_file.save(icon_path) except Exception as e: print('Error saving icon:', e) size.icon = icon_filename db.session.commit() flash('Size category updated successfully!', 'success') return redirect(url_for('manage_sizes')) return render_template('edit_size.html', size=size) @app.route('/admin/sizes/delete/', methods=['POST']) def delete_size(size_id): if not is_logged_in(): return redirect(url_for('login')) size = Size.query.get_or_404(size_id) db.session.delete(size) db.session.commit() flash('Size category deleted successfully!', 'success') return redirect(url_for('manage_sizes')) # Care Difficulty management routes @app.route('/admin/care-difficulties', methods=['GET', 'POST']) def manage_care_difficulties(): if not is_logged_in(): return redirect(url_for('login')) if request.method == 'POST': name = request.form['name'] description = request.form['description'] icon_file = request.files.get('icon') icon_filename = None if not name: flash('Name is required!', 'danger') print('No name provided') return redirect(url_for('manage_care_difficulties')) if CareDifficulty.query.filter_by(name=name).first(): flash('Care difficulty with this name already exists!', 'danger') print('Duplicate care difficulty name') return redirect(url_for('manage_care_difficulties')) if icon_file and icon_file.filename: icon_filename = secure_filename(icon_file.filename) icon_path = os.path.join('static/icons', icon_filename) os.makedirs('static/icons', exist_ok=True) try: icon_file.save(icon_path) except Exception as e: print('Error saving icon:', e) flash(f'Error saving icon: {e}', 'danger') try: difficulty = CareDifficulty(name=name, description=description, icon=icon_filename) db.session.add(difficulty) db.session.commit() flash('Care difficulty level added successfully!', 'success') print('Care difficulty added:', name) except Exception as e: db.session.rollback() print('Error adding care difficulty:', e) flash(f'Error adding care difficulty: {e}', 'danger') return redirect(url_for('manage_care_difficulties')) difficulties = CareDifficulty.query.all() return render_template('manage_care_difficulties.html', difficulties=difficulties, plant_count=len(Plant.query.all()), climate_count=len(Climate.query.all()), environment_count=len(Environment.query.all()), product_count=len(Product.query.all()), light_count=len(Light.query.all()), toxicity_count=len(Toxicity.query.all()), size_count=len(Size.query.all()), difficulty_count=len(difficulties), rate_count=len(GrowthRate.query.all())) @app.route('/admin/care-difficulties/edit/', methods=['GET', 'POST']) def edit_care_difficulty(difficulty_id): if not is_logged_in(): return redirect(url_for('login')) difficulty = CareDifficulty.query.get_or_404(difficulty_id) if request.method == 'POST': difficulty.name = request.form['name'] difficulty.description = request.form['description'] icon_file = request.files.get('icon') if icon_file and icon_file.filename: icon_filename = secure_filename(icon_file.filename) icon_path = os.path.join('static/icons', icon_filename) os.makedirs('static/icons', exist_ok=True) try: icon_file.save(icon_path) except Exception as e: print('Error saving icon:', e) difficulty.icon = icon_filename db.session.commit() flash('Care difficulty level updated successfully!', 'success') return redirect(url_for('manage_care_difficulties')) return render_template('edit_care_difficulty.html', difficulty=difficulty) @app.route('/admin/care-difficulties/delete/', methods=['POST']) def delete_care_difficulty(difficulty_id): if not is_logged_in(): return redirect(url_for('login')) difficulty = CareDifficulty.query.get_or_404(difficulty_id) db.session.delete(difficulty) db.session.commit() flash('Care difficulty level deleted successfully!', 'success') return redirect(url_for('manage_care_difficulties')) # Growth Rate management routes @app.route('/admin/growth-rates', methods=['GET', 'POST']) def manage_growth_rates(): if not is_logged_in(): return redirect(url_for('login')) if request.method == 'POST': name = request.form['name'] description = request.form['description'] icon_file = request.files.get('icon') icon_filename = None if not name: flash('Name is required!', 'danger') print('No name provided') return redirect(url_for('manage_growth_rates')) if GrowthRate.query.filter_by(name=name).first(): flash('Growth rate with this name already exists!', 'danger') print('Duplicate growth rate name') return redirect(url_for('manage_growth_rates')) if icon_file and icon_file.filename: icon_filename = secure_filename(icon_file.filename) icon_path = os.path.join('static/icons', icon_filename) os.makedirs('static/icons', exist_ok=True) try: icon_file.save(icon_path) except Exception as e: print('Error saving icon:', e) flash(f'Error saving icon: {e}', 'danger') try: rate = GrowthRate(name=name, description=description, icon=icon_filename) db.session.add(rate) db.session.commit() flash('Growth rate category added successfully!', 'success') print('Growth rate added:', name) except Exception as e: db.session.rollback() print('Error adding growth rate:', e) flash(f'Error adding growth rate: {e}', 'danger') return redirect(url_for('manage_growth_rates')) rates = GrowthRate.query.all() return render_template('manage_growth_rates.html', rates=rates, plant_count=len(Plant.query.all()), climate_count=len(Climate.query.all()), environment_count=len(Environment.query.all()), product_count=len(Product.query.all()), light_count=len(Light.query.all()), toxicity_count=len(Toxicity.query.all()), size_count=len(Size.query.all()), difficulty_count=len(CareDifficulty.query.all()), rate_count=len(rates)) @app.route('/admin/growth-rates/edit/', methods=['GET', 'POST']) def edit_growth_rate(rate_id): if not is_logged_in(): return redirect(url_for('login')) rate = GrowthRate.query.get_or_404(rate_id) if request.method == 'POST': rate.name = request.form['name'] rate.description = request.form['description'] icon_file = request.files.get('icon') if icon_file and icon_file.filename: icon_filename = secure_filename(icon_file.filename) icon_path = os.path.join('static/icons', icon_filename) os.makedirs('static/icons', exist_ok=True) try: icon_file.save(icon_path) except Exception as e: print('Error saving icon:', e) rate.icon = icon_filename db.session.commit() flash('Growth rate category updated successfully!', 'success') return redirect(url_for('manage_growth_rates')) return render_template('edit_growth_rate.html', rate=rate) @app.route('/admin/growth-rates/delete/', methods=['POST']) def delete_growth_rate(rate_id): if not is_logged_in(): return redirect(url_for('login')) rate = GrowthRate.query.get_or_404(rate_id) db.session.delete(rate) db.session.commit() flash('Growth rate category deleted successfully!', 'success') return redirect(url_for('manage_growth_rates')) # Section management routes @app.route('/admin/sections', methods=['GET', 'POST']) def manage_sections(): if not is_logged_in(): return redirect(url_for('login')) if request.method == 'POST': name = request.form['name'] description = request.form['description'] icon_file = request.files.get('icon') icon_filename = None if not name: flash('Name is required!', 'danger') print('No name provided') return redirect(url_for('manage_sections')) if Section.query.filter_by(name=name).first(): flash('Section with this name already exists!', 'danger') print('Duplicate section name') return redirect(url_for('manage_sections')) if icon_file and icon_file.filename: icon_filename = secure_filename(icon_file.filename) icon_path = os.path.join('static/icons', icon_filename) os.makedirs('static/icons', exist_ok=True) try: icon_file.save(icon_path) except Exception as e: print('Error saving icon:', e) flash(f'Error saving icon: {e}', 'danger') try: section = Section(name=name, description=description, icon=icon_filename) db.session.add(section) db.session.commit() flash('Section added successfully!', 'success') print('Section added:', name) except Exception as e: db.session.rollback() print('Error adding section:', e) flash(f'Error adding section: {e}', 'danger') return redirect(url_for('manage_sections')) sections = Section.query.all() return render_template('manage_sections.html', sections=sections, plant_count=len(Plant.query.all()), climate_count=len(Climate.query.all()), environment_count=len(Environment.query.all()), product_count=len(Product.query.all()), light_count=len(Light.query.all()), toxicity_count=len(Toxicity.query.all()), size_count=len(Size.query.all()), difficulty_count=len(CareDifficulty.query.all()), rate_count=len(GrowthRate.query.all()), section_count=len(sections)) @app.route('/admin/sections/edit/', methods=['GET', 'POST']) def edit_section(section_id): if not is_logged_in(): return redirect(url_for('login')) section = Section.query.get_or_404(section_id) if request.method == 'POST': section.name = request.form['name'] section.description = request.form['description'] icon_file = request.files.get('icon') if icon_file and icon_file.filename: icon_filename = secure_filename(icon_file.filename) icon_path = os.path.join('static/icons', icon_filename) os.makedirs('static/icons', exist_ok=True) try: icon_file.save(icon_path) except Exception as e: print('Error saving icon:', e) section.icon = icon_filename db.session.commit() flash('Section updated successfully!', 'success') return redirect(url_for('manage_sections')) return render_template('edit_section.html', section=section) @app.route('/admin/sections/delete/', methods=['POST']) def delete_section(section_id): if not is_logged_in(): return redirect(url_for('login')) section = Section.query.get_or_404(section_id) db.session.delete(section) db.session.commit() flash('Section deleted successfully!', 'success') return redirect(url_for('manage_sections')) def seed_db(): # Environments environments = [ {'name': 'Indoor', 'description': 'Inside the house or building.'}, {'name': 'Outdoor', 'description': 'Outside, exposed to natural elements.'}, {'name': 'Greenhouse', 'description': 'Controlled environment for plants.'} ] for env in environments: if not Environment.query.filter_by(name=env['name']).first(): db.session.add(Environment(name=env['name'], description=env['description'])) # Sections sections = [ {'name': 'Succulents', 'description': 'Plants that store water in their leaves, stems, or roots.'}, {'name': 'Tropical', 'description': 'Plants native to tropical regions.'}, {'name': 'Herbs', 'description': 'Plants used for culinary, medicinal, or aromatic purposes.'}, {'name': 'Flowering', 'description': 'Plants grown primarily for their flowers.'}, {'name': 'Foliage', 'description': 'Plants grown primarily for their attractive leaves.'} ] for sec in sections: if not Section.query.filter_by(name=sec['name']).first(): db.session.add(Section(name=sec['name'], description=sec['description'])) # Climates climates = [ {'name': 'Tropical', 'description': 'Warm and humid year-round.'}, {'name': 'Temperate', 'description': 'Moderate temperatures, distinct seasons.'}, {'name': 'Arid', 'description': 'Dry, little rainfall.'}, {'name': 'Mediterranean', 'description': 'Mild, wet winters and hot, dry summers.'} ] for clim in climates: if not Climate.query.filter_by(name=clim['name']).first(): db.session.add(Climate(name=clim['name'], description=clim['description'])) # Products products = [ {'name': 'Potting Soil', 'description': 'Soil mix for potted plants.'}, {'name': 'Fertilizer', 'description': 'Nutrient supplement for plants.'}, {'name': 'Watering Can', 'description': 'Tool for watering plants.'}, {'name': 'Grow Light', 'description': 'Artificial light for plant growth.'} ] for prod in products: if not Product.query.filter_by(name=prod['name']).first(): db.session.add(Product(name=prod['name'], description=prod['description'])) # Light Requirements lights = [ {'name': 'Bright Direct'}, {'name': 'Bright Indirect'}, {'name': 'Medium Light'}, {'name': 'Low Light'} ] for light in lights: if not Light.query.filter_by(name=light['name']).first(): db.session.add(Light(name=light['name'])) # Toxicity Levels toxicities = [ {'name': 'Non-toxic'}, {'name': 'Mildly Toxic'}, {'name': 'Toxic'}, {'name': 'Highly Toxic'} ] for toxicity in toxicities: if not Toxicity.query.filter_by(name=toxicity['name']).first(): db.session.add(Toxicity(name=toxicity['name'])) # Size Categories sizes = [ {'name': 'Small'}, {'name': 'Medium'}, {'name': 'Large'} ] for size in sizes: if not Size.query.filter_by(name=size['name']).first(): db.session.add(Size(name=size['name'])) # Care Difficulty Levels difficulties = [ {'name': 'Easy'}, {'name': 'Moderate'}, {'name': 'Difficult'} ] for difficulty in difficulties: if not CareDifficulty.query.filter_by(name=difficulty['name']).first(): db.session.add(CareDifficulty(name=difficulty['name'])) # Growth Rate Categories growth_rates = [ {'name': 'Slow'}, {'name': 'Moderate'}, {'name': 'Fast'} ] for rate in growth_rates: if not GrowthRate.query.filter_by(name=rate['name']).first(): db.session.add(GrowthRate(name=rate['name'])) db.session.commit() # Plants (add only if no plants exist) if Plant.query.count() == 0: indoor = Environment.query.filter_by(name='Indoor').first() outdoor = Environment.query.filter_by(name='Outdoor').first() greenhouse = Environment.query.filter_by(name='Greenhouse').first() tropical = Climate.query.filter_by(name='Tropical').first() temperate = Climate.query.filter_by(name='Temperate').first() arid = Climate.query.filter_by(name='Arid').first() mediterranean = Climate.query.filter_by(name='Mediterranean').first() soil = Product.query.filter_by(name='Potting Soil').first() fert = Product.query.filter_by(name='Fertilizer').first() can = Product.query.filter_by(name='Watering Can').first() light = Product.query.filter_by(name='Grow Light').first() # Get attribute instances bright_indirect = Light.query.filter_by(name='Bright Indirect').first() non_toxic = Toxicity.query.filter_by(name='Non-toxic').first() medium = Size.query.filter_by(name='Medium').first() easy = CareDifficulty.query.filter_by(name='Easy').first() moderate = GrowthRate.query.filter_by(name='Moderate').first() # Get section instances succulents = Section.query.filter_by(name='Succulents').first() tropical_section = Section.query.filter_by(name='Tropical').first() herbs = Section.query.filter_by(name='Herbs').first() flowering = Section.query.filter_by(name='Flowering').first() foliage = Section.query.filter_by(name='Foliage').first() # 10 example plants seed_plants = [ dict(name='Monstera Deliciosa', climate=tropical, environment=indoor, light=bright_indirect, toxicity=non_toxic, size=medium, care_difficulty=easy, growth_rate=moderate, section=tropical_section, products=[soil, fert], description='A popular tropical houseplant with large, split leaves.', care_guide='
  • Water when the top 2 inches of soil are dry.
  • Provide bright, indirect light.
  • Fertilize monthly during growing season.
'), dict(name='Aloe Vera', climate=arid, environment=indoor, light=bright_indirect, toxicity=non_toxic, size=medium, care_difficulty=easy, growth_rate=moderate, section=succulents, products=[soil], description='A succulent known for its medicinal properties.', care_guide='
  • Allow soil to dry completely between waterings.
  • Place in bright, indirect sunlight.
  • Use well-draining soil.
'), dict(name='Fiddle Leaf Fig', climate=tropical, environment=indoor, light=bright_indirect, toxicity=non_toxic, size=medium, care_difficulty=moderate, growth_rate=moderate, section=foliage, products=[soil, fert, can], description='A trendy houseplant with large, violin-shaped leaves.', care_guide='
  • Keep soil consistently moist but not soggy.
  • Needs bright, filtered light.
  • Rotate plant for even growth.
'), dict(name='Snake Plant', climate=arid, environment=indoor, light=bright_indirect, toxicity=non_toxic, size=medium, care_difficulty=easy, growth_rate=moderate, section=foliage, products=[soil, can], description='A hardy plant that tolerates low light and irregular watering.', care_guide='
  • Water sparingly; let soil dry out between waterings.
  • Tolerates low to bright light.
  • Wipe leaves to remove dust.
'), dict(name='Spider Plant', climate=temperate, environment=indoor, light=bright_indirect, toxicity=non_toxic, size=medium, care_difficulty=easy, growth_rate=moderate, section=foliage, products=[soil, can], description='An easy-care plant with arching leaves and baby plantlets.', care_guide='
  • Keep soil slightly moist.
  • Thrives in bright, indirect light.
  • Trim brown tips as needed.
'), dict(name='Peace Lily', climate=tropical, environment=indoor, light=bright_indirect, toxicity=non_toxic, size=medium, care_difficulty=easy, growth_rate=moderate, section=flowering, products=[soil, fert, can], description='A flowering plant that thrives in shade and purifies air.', care_guide='
  • Water when leaves droop slightly.
  • Prefers low to medium light.
  • Remove spent flowers to encourage new blooms.
'), dict(name='Jade Plant', climate=arid, environment=indoor, light=bright_indirect, toxicity=non_toxic, size=medium, care_difficulty=easy, growth_rate=moderate, section=succulents, products=[soil], description='A succulent with thick, shiny leaves and a tree-like form.', care_guide='
  • Let soil dry between waterings.
  • Needs several hours of direct sunlight.
  • Prune to maintain shape.
'), dict(name='Tomato', climate=temperate, environment=outdoor, light=bright_indirect, toxicity=non_toxic, size=medium, care_difficulty=moderate, growth_rate=moderate, section=herbs, products=[soil, fert, can], description='A classic edible plant for outdoor gardens.', care_guide='
  • Water regularly, keeping soil consistently moist.
  • Provide full sun.
  • Support with stakes or cages.
'), dict(name='Basil', climate=mediterranean, environment=greenhouse, light=bright_indirect, toxicity=non_toxic, size=medium, care_difficulty=easy, growth_rate=moderate, section=herbs, products=[soil, fert, light], description='A fragrant herb often grown in greenhouses or sunny windows.', care_guide='
  • Water when soil surface is dry.
  • Needs at least 6 hours of sunlight daily.
  • Pinch off flowers to encourage leaf growth.
'), dict(name='Cactus', climate=arid, environment=indoor, light=bright_indirect, toxicity=non_toxic, size=medium, care_difficulty=easy, growth_rate=moderate, section=succulents, products=[soil, light], description='A spiny plant adapted to dry, sunny conditions.', care_guide='
  • Water sparingly, especially in winter.
  • Place in bright, direct sunlight.
  • Use cactus-specific soil mix.
'), ] for plant in seed_plants: db.session.add(Plant( name=plant['name'], climate_id=plant['climate'].id if plant['climate'] else None, environment_id=plant['environment'].id if plant['environment'] else None, light_id=plant['light'].id if plant['light'] else None, toxicity_id=plant['toxicity'].id if plant['toxicity'] else None, size_id=plant['size'].id if plant['size'] else None, care_difficulty_id=plant['care_difficulty'].id if plant['care_difficulty'] else None, growth_rate_id=plant['growth_rate'].id if plant['growth_rate'] else None, section_id=plant['section'].id if plant['section'] else None, products=','.join(str(p.id) for p in plant['products'] if p), description=plant['description'], care_guide=plant['care_guide'] )) db.session.commit() if __name__ == "__main__": with app.app_context(): db.create_all() # Create all tables # Create admin user if it doesn't exist admin = User.query.filter_by(username='admin').first() if not admin: admin = User(username='admin') admin.set_password('admin123') # Set a default password db.session.add(admin) db.session.commit() print("Admin user created with username: admin and password: admin123") seed_db() # Seed initial data app.run(debug=True)