플러터.py | 양쪽 끝의 왕

13726 단어 pythonflutter


오늘 우리는 Python 확장 기능인 Flask-RESTful 백엔드를 Flutter를 프런트엔드로 통합하여 매우 간단한 API를 활용할 것입니다.

요컨대, 우리는 FRONTEND의 왕과 BACKEND의 왕을 통합하고 있습니다.

🎨 Flutter 및 Flask-RESTful



Flutter은 크로스 플랫폼 및 고성능 앱을 개발하기 위한 UI 툴킷입니다. 매우 유연하며 Google에서 개발했습니다.

Flask-RESTful은 REST API를 신속하게 구축하기 위한 지원을 추가하는 Flask의 확장입니다. Python으로 구동됩니다.

🕸 REST API



REST API는 REST 아키텍처 스타일을 기반으로 하는 애플리케이션 프로그래밍 인터페이스(API)입니다. 여기에는 데이터를 보내고 가져오기 위한 GET, POST, DELETE 등과 같은 메서드가 포함됩니다. 모든 HTTP 메서드는 REST API와 함께 사용할 수 있습니다.

🧑🏻‍💻 첫 번째 REST API 작성



따라서 우리는 Python으로 구동되는 flask-restful 라이브러리를 사용할 것입니다. 따라서 첫 번째 단계는 라이브러리를 설치하는 것입니다. 우리 모두는 pip가 Python에서 다양한 패키지를 설치할 수 있는 관리자라는 것을 알고 있습니다.

pip install flask-restful


Mac OS: pip가 작동하지 않고 최신 Python 버전을 설치한 경우 pip3를 선택하십시오. python ~ python3 키워드와 동일합니다.

파일app.py을 생성하고 매우 간단한hello world API 응답을 작성하여 매우 간단하게 시작할 것입니다.

import flask
from flask_restful import Resource, Api

app = flask.Flask(__name__)
api = Api(app)


class HelloWorld(Resource):
 def get(self):
 return {
 'hello': 'world',
        }


api.add_resource(HelloWorld, '/')

if __name__ == '__main__':
    app.run(debug=True, host='0.0.0.0', port=8080)


Save this code

다음 명령을 실행합니다.

python app.py


오픈http://localhost:8080

이 모양을 위해 확장 JSON 뷰어를 사용하고 있습니다.

조금 더 깊게

이제 Flutter 프런트엔드에서 보여줄 수 있도록 이 API 응답을 좀 더 복잡하게 만들어 보겠습니다.

import flask
from flask_restful import Resource, Api

app = flask.Flask(__name__)
api = Api(app)


class HelloWorld(Resource):
 def get(self):

        data = [
 'first',
 'API',
 'Response',
 'with',
 'random List',
 'python',
        ]

 return {
 'data': data,
        }


api.add_resource(HelloWorld, '/')

if __name__ == '__main__':
    app.run(debug=True, host='0.0.0.0', port=8080)


Save this code

이제 localhost를 열면 다음과 같이 표시됩니다.



💻 Flutter에 통합



flutter_bloc을 사용하여 REST API를 처리하고 이어서 큐빗과 상태를 처리하겠습니다. 따라서 프로젝트 구조는 다음과 같습니다.

.



모델

aList<String>만 포함하는 매우 간단한 모델 클래스부터 시작하겠습니다.

import 'dart:convert';

class Data {
 final List<String> words;
 Data({
    required this.words,
  });

 Data copyWith({
    List<String>? words,
  }) {
 return Data(
      words: words ?? this.words,
    );
  }

 Map<String, dynamic> toMap() {
 return <String, dynamic>{
      'words': words,
    };
  }

  factory Data.fromMap(Map<String, dynamic> map) {
 return Data(
      words: List<String>.from((map['words'] as List)),
    );
  }

  String toJson() => json.encode(toMap());

  factory Data.fromJson(String source) =>
      Data.fromMap(json.decode(source) as Map<String, dynamic>);

  @override
  String toString() => 'Data(words: $words)';

  @override
  int get hashCode => words.hashCode;
}


Save this code

data_provider.dart

그런 다음 data_provider 계층의 API에서 데이터를 요청합니다.

여기에서도 dio을 사용할 수 있습니다. 이것이 제가 선호하는 것입니다.

part of 'cubit.dart';

class DataDataProvider {
 static Future<Data> fetch() async {
 try {
 final request = await http.get(Uri.parse('http://localhost:8080'));

 return Data.fromJson(request.body);
    } catch (e) {
 throw Exception("Internal Server Error");
    }
  }
}


Save this code

저장소.다트

다음으로 API에서 cubits로 데이터를 전달합니다.

part of 'cubit.dart';

class DataRepository {
 Future<Data> fetch() => DataDataProvider.fetch();
}


Save this code

state.dart

여기에서 몇 가지 다른 상태를 처리하고 있습니다.
  • 로드 상태
  • 성공 상태
  • 장애 상태

  • part of 'cubit.dart';
    
    @immutable
    class DataState extends Equatable {
     final Data? data;
     final String? message;
    
     const DataState({
        this.data,
        this.message,
      });
    
      @override
     List<Object?> get props => [
     data,
     message,
          ];
    }
    
    @immutable
    class DataDefault extends DataState {}
    
    @immutable
    class DataFetchLoading extends DataState {
     const DataFetchLoading() : super();
    }
    
    @immutable
    class DataFetchSuccess extends DataState {
     const DataFetchSuccess({Data? data}) : super(data: data);
    }
    
    @immutable
    class DataFetchFailed extends DataState {
     const DataFetchFailed({String? message}) : super(message: message);
    }
    


    Save this code

    큐빗 다트

    마지막으로 데이터가 있는지 여부에 따라 상태를 생략합니다.

    import 'dart:async';
    
    import 'package:flutter/material.dart';
    import 'package:flutter_bloc/flutter_bloc.dart';
    import 'package:equatable/equatable.dart';
    import 'package:http/http.dart' as http;
    
    import 'package:jugaad/models/data.dart';
    
    part 'data_provider.dart';
    part 'repository.dart';
    part 'state.dart';
    
    class DataCubit extends Cubit<DataState> {
     static DataCubit cubit(BuildContext context, [bool listen = false]) =>
     BlocProvider.of<DataCubit>(context, listen: listen);
    
     DataCubit() : super(DataDefault());
    
      final repo = DataRepository();
    
      Future<void> fetch() async {
        emit(const DataFetchLoading());
     try {
          final data = await repo.fetch();
    
          emit(DataFetchSuccess(data: data));
        } catch (e) {
          emit(DataFetchFailed(message: e.toString()));
        }
      }
    }
    


    Save this code

    이제 BlocBuilder 를 사용하여 프런트엔드를 처리해 보겠습니다. 최종 제품은 다음과 같습니다.

    import 'package:flutter/material.dart';
    import 'package:flutter_bloc/flutter_bloc.dart';
    import 'package:jugaad/cubits/data/cubit.dart';
    
    void main() {
      runApp(const MyApp());
    }
    
    class MyApp extends StatelessWidget {
     const MyApp({Key? key}) : super(key: key);
    
      @override
      Widget build(BuildContext context) {
     return MultiBlocProvider(
          providers: [
            BlocProvider(create: (_) => DataCubit()),
          ],
          child: const MaterialApp(
            debugShowCheckedModeBanner: false,
            title: 'flutter.py',
            home: DataScreen(),
          ),
        );
      }
    }
    
    class DataScreen extends StatefulWidget {
     const DataScreen({Key? key}) : super(key: key);
    
      @override
      State<DataScreen> createState() => _DataScreenState();
    }
    
    class _DataScreenState extends State<DataScreen> {
      @override
     void initState() {
     super.initState();
    
     DataCubit.cubit(context).fetch();
      }
    
      @override
     Widget build(BuildContext context) {
     return Scaffold(
          body: BlocBuilder<DataCubit, DataState>(
            builder: (context, state) {
              // loading
              if (state is DataFetchLoading) {
                return const Center(
                  child: CircularProgressIndicator(),
                );
              }
    
              // success
              else if (state is DataFetchSuccess) {
                return ListView(
                  children: state.data!.words
                      .map(
                        (word) => ListTile(
                          title: Text(word),
                        ),
                      )
                      .toList(),
                );
              }
    
              // failure
              else if (state is DataFetchFailed) {
                return Center(
                  child: Text(state.message!),
                );
              }
    
              // something unexpected
              return const Center(
                child: Text('Something went wrong'),
              );
            },
          ),
        );
      }
    }
    


    Save this code

    그리고…… 🥁🥁🥁

    Flask API의 데이터

    🔥 복잡성++



    더 많은 이해를 위해 API 응답을 좀 더 복잡하게 만든 다음 그에 따라 data.dart 모델 클래스를 변경하여 UI를 채울 것입니다.

    API 응답

    import flask
    from flask_restful import Resource, Api
    
    app = flask.Flask(__name__)
    api = Api(app)
    
    
    class HelloWorld(Resource):
     def get(self):
    
            data = [
                {
     'word': 'cat',
     'type': 'animal',
                },
                {
     'word': 'football',
     'type': 'sports',
                },
                {
     'word': 'rice',
     'type': 'food',
                },
            ]
    
     return {
     'data': data,
            }
    
    
    api.add_resource(HelloWorld, '/')
    
    if __name__ == '__main__':
        app.run(debug=True, host='0.0.0.0', port=8080)
    


    Save this code

    Data.dart

    import 'dart:convert';
    
    class Data {
     final String word;
     final String type;
     Data({
        required this.word,
        required this.type,
      });
    
     Data copyWith({
        String? word,
        String? type,
      }) {
     return Data(
          word: word ?? this.word,
          type: type ?? this.type,
        );
      }
    
     Map<String, dynamic> toMap() {
     return <String, dynamic>{
          'word': word,
     'type': type,
        };
      }
    
      factory Data.fromMap(Map<String, dynamic> map) {
     return Data(
          word: map['word'] as String,
          type: map['type'] as String,
        );
      }
    
      String toJson() => json.encode(toMap());
    
      factory Data.fromJson(String source) =>
          Data.fromMap(json.decode(source) as Map<String, dynamic>);
    
      @override
      String toString() => 'Data(word: $word, type: $type)';
    
      @override
      int get hashCode => word.hashCode ^ type.hashCode;
    
      @override
      bool operator ==(covariant Data other) {
     if (identical(this, other)) return true;
    
     return other.word == word && other.type == type;
      }
    }
    


    Save this code

    UI의 최종 모습은 다음과 같습니다.



    그게 다야! 나는 당신이 오늘 무언가를 배웠기를 바랍니다. 그리고 어떤 천재가 이 기사를 읽고 모든 소란을 쉽게 처리하는 flutter.py라는 이름의 실제 다트 패키지를 생각해 내길 바랍니다!

    사람들은 항상 "Flutter와 함께 어떤 종류의 백엔드를 사용할 수 있나요?"와 같은 질문을 합니다. "Python을 백엔드로 사용할 수 있습니까?""Node.js를 사용할 수 있나요?"등등.

    Flutter는 백엔드에 무엇이든 연결할 수 있는 UI 툴킷일 뿐입니다. 이를 위해 Flask-RESTful을 사용했지만 Django, Node.js 또는 선호하는 백엔드를 사용할 수 있습니다.

    그러니 계속 탐색하고 계속 멋진 작품을 만드세요!

    고마워요 여러분 #행복 설레개 💙

    좋은 웹페이지 즐겨찾기