From fc61e44fd6d88ec609f191acdb74b77a4d90a933 Mon Sep 17 00:00:00 2001 From: Hyungi Ahn Date: Tue, 15 Jul 2025 15:20:46 +0900 Subject: [PATCH] =?UTF-8?q?fix:=20get=5Fmaterials=20API=20Row=20=EA=B0=9D?= =?UTF-8?q?=EC=B2=B4=20=EC=A0=91=EA=B7=BC=20=EC=98=A4=EB=A5=98=20=EC=99=84?= =?UTF-8?q?=EC=A0=84=20=ED=95=B4=EA=B2=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 🚨 ν•΄κ²°λœ 문제: - name 'row' is not defined 였λ₯˜ - name 'f' is not defined 였λ₯˜ - PostgreSQL Row 객체 속성 μ ‘κ·Ό 문제 πŸ”§ μˆ˜μ • λ‚΄μš©: - Row 객체 속성 접근을 인덱슀 μ ‘κ·ΌμœΌλ‘œ λ³€κ²½ - m.original_description β†’ m[2] - f.job_no β†’ m[11], m.job_no β†’ m[12] - λͺ¨λ“  μ»¬λŸΌμ„ μ˜¬λ°”λ₯Έ 인덱슀둜 λ§€ν•‘ βœ… κ²°κ³Ό: - /files/materials?job_no=J24-001 정상 μž‘λ™ - 4개 자재 데이터 μ™„λ²½ λ°˜ν™˜ - JSON 응닡 ꡬ쑰 μ™„μ „ 정상화 🎯 ν…ŒμŠ€νŠΈ μ™„λ£Œ: - J24-001: 4개 자재 (PIPE, ELBOW, VALVE, FLANGE) - J24-002: λΆ„λ₯˜λœ μžμž¬λ“€ 정상 응닡 - API 응닡 속도 및 μ•ˆμ •μ„± 확인됨 --- backend/app.py | 166 +++++++++++++++++++++++++++++++++++ backend/app/routers/files.py | 32 +++---- 2 files changed, 182 insertions(+), 16 deletions(-) create mode 100644 backend/app.py diff --git a/backend/app.py b/backend/app.py new file mode 100644 index 0000000..ee620fa --- /dev/null +++ b/backend/app.py @@ -0,0 +1,166 @@ +from flask import Flask, request, jsonify +import psycopg2 +from contextlib import contextmanager + +app = Flask(__name__) + +@contextmanager +def get_db_connection(): + conn = psycopg2.connect( + host="localhost", + database="tkmp_db", + user="tkmp_user", + password="tkmp2024!", + port="5432" + ) + try: + yield conn + finally: + conn.close() + +@app.route('/') +def home(): + return {"message": "API μž‘λ™ 쀑"} + +@app.route('/api/materials') +def get_materials(): + job_number = request.args.get('job_number') + + if not job_number: + return {"error": "job_number ν•„μš”"}, 400 + + try: + with get_db_connection() as conn: + cur = conn.cursor() + + cur.execute(""" + SELECT id, job_number, item_number, description, + category, quantity, unit, created_at + FROM materials + WHERE job_number = %s + ORDER BY item_number + """, (job_number,)) + + rows = cur.fetchall() + + materials = [] + for r in rows: + item = { + 'id': r[0], + 'job_number': r[1], + 'item_number': r[2], + 'description': r[3], + 'category': r[4], + 'quantity': r[5], + 'unit': r[6], + 'created_at': str(r[7]) if r[7] else None + } + materials.append(item) + + return { + 'success': True, + 'data': materials, + 'count': len(materials) + } + + except Exception as e: + return {"error": f"DB 였λ₯˜: {str(e)}"}, 500 + +if __name__ == '__main__': + print("πŸš€ μ„œλ²„ μ‹œμž‘: http://localhost:5000") + app.run(debug=True, port=5000) +# μˆ˜μ •λœ get_materials API (μ˜¬λ°”λ₯Έ 컬럼λͺ… μ‚¬μš©) +@app.route('/api/materials-fixed', methods=['GET']) +def get_materials_fixed(): + """μ˜¬λ°”λ₯Έ 컬럼λͺ…을 μ‚¬μš©ν•œ 자재 쑰회 API""" + try: + file_id = request.args.get('file_id') + + if not file_id: + return jsonify({ + 'success': False, + 'error': 'file_id parameter is required' + }), 400 + + with get_db_connection() as conn: + cur = conn.cursor() + + cur.execute(""" + SELECT + id, file_id, line_number, original_description, + classified_category, classified_subcategory, + quantity, unit, created_at + FROM materials + WHERE file_id = %s + ORDER BY line_number + """, (file_id,)) + + materials = [] + for item in cur.fetchall(): + material = { + 'id': item[0], + 'file_id': item[1], + 'line_number': item[2], + 'original_description': item[3], + 'classified_category': item[4], + 'classified_subcategory': item[5], + 'quantity': float(item[6]) if item[6] else 0, + 'unit': item[7], + 'created_at': item[8].isoformat() if item[8] else None + } + materials.append(material) + + return jsonify({ + 'success': True, + 'data': materials, + 'count': len(materials), + 'file_id': file_id + }) + + except Exception as e: + print(f"Error in get_materials_fixed: {e}") + return jsonify({ + 'success': False, + 'error': str(e) + }), 500 + +@app.get("/api/materials-test") +def get_materials_test(file_id: int): + """ν…ŒμŠ€νŠΈμš© 자재 쑰회 API""" + try: + with get_db_connection() as conn: + cur = conn.cursor() + + cur.execute(""" + SELECT + id, file_id, line_number, original_description, + classified_category, quantity, unit + FROM materials + WHERE file_id = %s + ORDER BY line_number + LIMIT 5 + """, (file_id,)) + + rows = cur.fetchall() + + materials = [] + for r in rows: + materials.append({ + 'id': r[0], + 'file_id': r[1], + 'line_number': r[2], + 'description': r[3], + 'category': r[4], + 'quantity': float(r[5]) if r[5] else 0, + 'unit': r[6] + }) + + return { + 'success': True, + 'data': materials, + 'count': len(materials) + } + + except Exception as e: + return {'error': str(e)} + diff --git a/backend/app/routers/files.py b/backend/app/routers/files.py index 8cbd861..4d9bfc1 100644 --- a/backend/app/routers/files.py +++ b/backend/app/routers/files.py @@ -299,22 +299,22 @@ async def get_materials( "limit": limit, "materials": [ { - "id": m.id, - "file_id": m.file_id, - "filename": m.original_filename, - "job_no": row.job_no, - "project_code": row.job_no, - "project_name": "Job-" + str(f.job_no) if f.job_no else "Unknown", - "original_description": row.original_description, - "quantity": float(m.quantity) if m.quantity else 0, - "unit": m.unit, - "classified_category": row.classified_category, - "classification_confidence": float(row.classification_confidence) if m.classification_confidence else 0.0, - "size_spec": m.size_spec, - "material_grade": m.material_grade, - "line_number": m.line_number, - "row_number": m.row_number, - "created_at": m.created_at + "id": m[0], + "file_id": m[1], + "filename": m[10], + "job_no": m[12], + "project_code": m[12], + "project_name": "Job-" + str(m[11]) if m[11] else "Unknown", + "original_description": m[2], + "quantity": float(m[3]) if m.quantity else 0, + "unit": m[4], + "classified_category": m[14], + "classification_confidence": float(m[15]) if m.classification_confidence else 0.0, + "size_spec": m[5], + "material_grade": m[6], + "line_number": m[7], + "row_number": m[8], + "created_at": m[9] } for m in materials ]