[flutter] flask 서버와 연동 + DB 내용 보여주기
이번엔 플라스크 서버와 플러터를 연동해서 서버 내용을 플러터 화면에 보여주는 걸 적어보도록 하겠다.
0,제품명,카테고리,전면사진,후면사진,알레르기성분
1,신라면(봉지),라면,신라면봉지-1.jpg,신라면봉지-2.jpg,밀 대두 돼지고기 계란 쇠고기
8801043015714,신라면 컵,라면,이미지2-1.jpg,이미지2-2.jpg,밀 대두 우유 계란 쇠고기
8801043015981,신라면 큰 사발면,라면,이미지3-1.jpg,이미지3-2.jpg,밀 대두 돼지고기 우유 계란 쇠고기
서버에 이런DB가 저장되 있을 때
이렇게 화면에 보여준 모습이다.
진행과정
1. 서버 및 DB 만들기 (플라스크)
2. DB에 데이터 넣기
3. 플러터 화면 구현 및 서버 연동
먼저 플라스크는 SQLAlchemy을 사용하고 CSV를 통해 DB를 관리하기로 했다.
1. 서버 및 DB 만들기 (플라스크)
먼저 서버 파일인 py
from flask import Flask, jsonify, request
from flask_sqlalchemy import SQLAlchemy
from flask_cors import CORS
import csv
# Flask 앱 초기화
app = Flask(__name__)
CORS(app)
# SQLite 데이터베이스 설정
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///products.db'
db = SQLAlchemy(app)
# 데이터 모델 정의
class Product(db.Model):
id = db.Column(db.Integer, primary_key=True)
barcode = db.Column(db.String(20), nullable=False)
name = db.Column(db.String(80), nullable=False)
kategorie = db.Column(db.String(255), nullable=True)
frontproduct = db.Column(db.String(255), nullable=True)
backproduct = db.Column(db.String(255), nullable=False)
allergens = db.Column(db.String(255), nullable=True)
def __repr__(self):
return f'<Product {self.name}>'
# 데이터베이스 생성 및 CSV 데이터 추가
if __name__ == '__main__':
with app.app_context():
db.create_all()
# CSV 파일에서 데이터를 읽어와 데이터베이스에 추가
with open('C:/Users/82109/Desktop/src/flutter_banergy/lib/DB/product.csv', 'r', encoding='utf-8') as csvfile:
csvreader = csv.DictReader(csvfile, fieldnames=['barcode', 'name', 'kategorie', 'frontproduct', 'backproduct', 'allergens'])
for idx, row in enumerate(csvreader):
if idx == 0: # 첫 번째 행은 헤더이므로 건너뜁니다.
continue
# 중복 체크
existing_product = Product.query.filter_by(barcode=row['barcode']).first()
if existing_product:
print(f"제품 '{row['name']}'(바코드: {row['barcode']})은 이미 데이터베이스에 존재합니다.")
continue
new_product = Product(
barcode=row['barcode'],
name=row['name'],
kategorie=row['kategorie'],
frontproduct=row['frontproduct'],
backproduct=row['backproduct'],
allergens=row['allergens']
)
db.session.add(new_product)
db.session.commit()
# 라우팅: 제품 추가
@app.route('/add', methods=['POST'])
def add_product():
if request.method == 'POST':
data = request.get_json()
# 중복 체크
existing_product = Product.query.filter_by(barcode=data['barcode']).first()
if existing_product:
return jsonify({'message': '이미 존재하는 제품입니다.'}), 400
new_product = Product(
barcode=data['barcode'],
name=data['name'],
kategorie=data['kategorie'],
frontproduct=data['frontproduct'],
backproduct=data['backproduct'],
allergens=data['allergens']
)
db.session.add(new_product)
db.session.commit()
return jsonify({'message': '제품이 성공적으로 추가되었습니다.'}), 201
if __name__ == '__main__':
app.run(host='0.0.0.0', port=8000, debug=True)
사실 파이썬 코드는 내가 안짜고 같이 하시는 분이 짜주셨기 때문에 딱 필요한 부분만 아는 수준이다.
코드를 짜주신 분이 DB 생성 및 CSV 연동을 다 해주셔서 실행만 하면 알아서 instance 폴더에 DB가 만들어졌다.
데이터베이스 생성 부분만 내 위치의 절대경로로 수정만 하면 됨
with open('여기에 나의 CSV 절대 경로 넣으면 됨', 'r', encoding='utf-8') as csvfile:
2. DB에 데이터 넣기
여기는 사실 정말 쉽다. CSV에 데이터를 적어서 저장하면 된다.
나 같은 경우엔 id, barcode , name ,kategorie ,frontproduct ,backproduct ,allergens 로 테이블이 구성되어 있는데
id는 자동으로 생성되기 때문에 생략해주고 순서에 맞게barcode부터 적어서 저장하면 된다.
그후 py을 실행하면 해당 데이터들이 삽입된다.
잘 저장되었나 확인하는 방법은 여러가지가 있지만 코드에 디버깅을 해놨기 때문에
터미널에 뜨는 주소에 들어가보면 된다.
참고로 host에0.0.0.0을 넣으면 외부 접속이 허용되고 post는 내 마음대로 수정해도 상관없음
코드 상 연동을 했다고 해도 파이썬 파일을 실행하지 않으면 화면에 뜨지 않는다
즉 파이썬 파일 , 플러터 파일 둘다 실행해야 함
3. 플러터 화면 구현 및 서버 연동
백쪽은 이제 끝나고 프론트를 할 시간이다.
화면 dart 부분
class ProductGrid extends StatefulWidget {
const ProductGrid({super.key});
@override
_ProductGridState createState() => _ProductGridState();
}
class _ProductGridState extends State<ProductGrid> {
late List<Product> products = [];
@override
void initState() {
super.initState();
fetchData(); // initState에서 데이터를 불러옵니다.
}
Future<void> fetchData() async {
final response = await http.get(
Uri.parse('http://127.0.0.1:8000/'),
);
if (response.statusCode == 200) {
setState(() {
final List<dynamic> productList = json.decode(response.body);
products = productList.map((item) => Product.fromJson(item)).toList();
});
} else {
throw Exception('Failed to load data');
}
}
@override
Widget build(BuildContext context) {
return GridView.builder(
gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 2,
),
itemCount: products.length,
itemBuilder: (context, index) {
return Card(
child: InkWell(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Expanded(
child: Image.network(
products[index].frontproduct,
fit: BoxFit.cover,
),
),
const SizedBox(height: 8.0),
Text(
products[index].name,
style: const TextStyle(fontWeight: FontWeight.bold),
),
const SizedBox(height: 4.0),
Text(products[index].allergens),
],
),
),
);
},
);
}
여기서는 gridview를 사용해서 한줄에 2개씩 배치한 후
화면엔 내 기준 이미지 , 이름 , 알레르기가 보여지게 하였다.
서버 연동 부분은 fetchData를 사용해서 서버에 데이터를 요청한 후 JSON 형식으 데이터를 받아오도록 하였다
여기서 서버에 요청을 위해 import 'package:http/http.dart' as http; 이걸 임포트 해줘야 한다.
Uri.parse('http://127.0.0.1:8000/') 여기 부분이 서버랑 다르면 연동이 안되기 때문에 주의!!
또 화면에 보여지는 products 리스트들을 클래스 선언해주면 된다.
// DB Product
class Product {
final int id;
final String barcode;
.....
Product({
required this.id,
required this.barcode,
....
});
factory Product.fromJson(Map<String, dynamic> json) {
return Product(
id: json['id'],
barcode: json['barcode'],
....
);
}
}
나는 코드가 길어지는 걸 방지하기 위해 따로 파일을 만들어서 화면페이지랑 연동했다.