TIL Python Basics Day 39 - Capstone Part 1: Flight Deal Finder

이다연·2021년 1월 26일
0

Udemy Python Course

목록 보기
38/64

OOP bothered me so much in this project!

OOP concept has been haunting me since I leanrt in for the first time. After watching a couple of more videos and reading lots of articles, I can say I understood the basic concepts and can implement it in my code.
Codeit module explained the concept in a easiest way possible. Especially, how they explained the Parameter 'Self' and initializer function was distinve. They say object oriented programming means program is designed that objects are talking to each other to implement the code.
I will have to learn more about decorators, four pillars of OOP and so on. That's for another time.
OOP article
신입 개발자 면접 기초 개념설명들

Capstone Part 1: Flight Deal

Goal: Find the flight deal and compare it to previous cheapest price written on google sheet. If cheaper, send an alert message.

  • APIs Required:
  1. Google Sheet Data Management - https://sheety.co/

  2. Flight Search API (Free Signup, Requires Credit Card Details) - https://partners.kiwi.com/
    Flight Search API Documentation - https://tequila.kiwi.com/portal/docs/tequila_api

  3. Twilio SMS API - https://www.twilio.com/docs/sms


  • Program Requirements:
  1. Use the Flight Search and Sheety API to populate your own copy of the Google Sheet with International Air Transport Association (IATA) codes for each city. Most of the cities in the sheet include multiple airports, you want the city code, not the airport code see here.

  2. Use the Flight Search API to check for the cheapest flights from tomorrow to 6 months later for all the cities in the Google Sheet.

  3. If the price is lower than the lowest price listed in the Google Sheet then send a SMS to your own number with the Twilio API.

  4. The SMS should include the departure airport IATA code, destination airport IATA code, departure city, destination city, flight price and flight dates. e.g.

Sheety

KEY : overlaping value btween a list and a dict, to connect each other.
"iataCode": iata
case and space matters in sheety

timedelta()

timedelta() from the datatime module to define a 6 month period (6 x 30 days).

day = datetime(year=2021, month=1, day=23)
three_days_later = day + timedelta(days=3)


now = datetime.now()
tmr = now + timedelta(days=1)
f_tmr = tmr.strftime("%d/%m/%Y")
print(f_tmr)

six_month = tmr + timedelta(days=180)
f_six_month = six_month.strftime("%d/%m/%Y")
print(f_six_month)

#printed: 
23/01/2021
22/07/2021

https://stackoverflow.com/questions/4541629/how-to-create-a-datetime-equal-to-15-minutes-ago/4541668

pprint() / initialise empty dict for function and return output

pretty print for json data
클래스는 자료형을 만드는 것
self 매개변수는 생성된 인스턴스 그 자체를 의미함.

인스턴스는 생성될 때 sheet_data 함수에 빈 딕셔너리를 가짐.
함수가 실행되면 self.sheet_data가 리턴됨.
왜 빈 딕셔너리를 먼저 지정해준건지? -> 메인에서 키:벨류 페어가 있는 딕셔너리 자료형이 필요해짐. 안젤라는 클래스에서 미리 지정해준 것.

<Angela's code>
class DataManager:
    def __init__(self):
        self.sheet_data() = {}

    def sheet_data(self):

        sheety_response = requests.get(url=sheety_endpoint)
        sheety_response.raise_for_status()
        data = sheety_response.json()
        self.sheet_data = data['prices']
        pprint(data)
        return self.sheet_data
        
 #-----------------------------------------------
 <MY CODE>
class DataManager:
    def __init__(self):
        self.sheet_data()

    def sheet_data(self):

        sheety_response = requests.get(url=sheety_endpoint)
        sheety_response.raise_for_status()
        data = sheety_response.json()

        return data['prices']
        

IATA code to google sheet

Endpoint is a constant. Use upper case. Put it up on the first line for reuse. Use formatting instead of repeating same url.

<Angela's code>
 def update_destination_codes(self):
        for city in self.destination_data:
            new_data = {
                "price": {
                    "iataCode": city["iataCode"]
                }
            }
            response = requests.put(
                url=f"{SHEETY_PRICES_ENDPOINT}/{city['id']}",
                json=new_data
            )
            print(response.text) 
 #-----------------------------------------------
 <My Code>
 #[{'city': 'Paris', 'iataCode': 'PAR', 'lowestPrice': 54, 'id': 2},
 
     def sheet_update(self, sheet_data):
     	

        sheet_data = self.sheet_data()
        #sheet_data[0]['id'] == 2

        for i in sheet_data:
        	sheet_update_endpoint = f"https://api.sheety.co/4d7e4e0cd9c3943545a14a41700a73f3/flightDeals/prices/{i['id']}"
            # print(iata)
            update_params = {
                "price": {
                    "iataCode": i['iataCode']
                }
            }
            sheet_response = requests.put(url=sheet_update_endpoint, json=update_params)

            # print(sheet_response.text)

flight_search.py

Angela's FlightSearch class returns 'code'
My FlightSearch class returns broader category 'flight_data' which includes 'code' inside.
It causes the difference when used in main.py.

Learning: to make things simpler at main.py, better to make a class to do specific functions and hide all inside it. Like return smaller chunk of data str'code' instead of broader category dict'flight_data', which include city name, code, etc.
If I retrieve broader data, it's reusable tho. In this project, def get_destination_code at flight_search.py does only one thing. => Get destination code!! Name holds all the purpose and meaning.


<Angela's code> 
TEQUILA_ENDPOINT = "https://tequila-api.kiwi.com"
TEQUILA_API_KEY = YOUR FLIGHT SEARCH API KEY


class FlightSearch:

    def get_destination_code(self, city_name):
        location_endpoint = f"{TEQUILA_ENDPOINT}/locations/query"
        headers = {"apikey": TEQUILA_API_KEY}
        query = {"term": city_name, "location_types": "city"}
        response = requests.get(url=location_endpoint, headers=headers, params=query)
        results = response.json()["locations"]
        code = results[0]["code"]
        return code
 #-----------------------------------------------
<My code>
class FlightSearch:
    #This class is responsible for talking to the Flight Search API.
    def __init__(self):
        self.flight_search(self)

    def flight_search(self, city):
        parameters = {
            "term": city
        }
        headers = {
            "apikey": API_KEY
        }
        response = requests.get(url=FLIGHT_ENDPOINT, params=parameters, headers=headers)
        response.raise_for_status()
        flight_data = response.json()
        # pprint(flight_data)
        return flight_data
        
<my code from main.py>        
city_iata ={}
for city in city_data:
    flight = FlightSearch()
    each_city = flight.flight_search(city)
    code = each_city['locations'][0]['code']
    city_iata[city] = code
        

flight_data.py

FlightData class only holds attributes for instances. Instance of FlightData will have all these attributes. There is no method.
FlightData is later used at FlightSearch class to find the cheapest flight from API.

OOP) Why make Flight data object? When used at FlightData class, to find the cheapest tickets for multiple destinations one by one, we need to retrieve each information repeatedly. When we set instances variables using parameters, we don't need to write all these variables for each cities.

class FlightData:

    def __init__(self, price, origin_city, origin_airport, destination_city, destination_airport, out_date, return_date):
        self.price = price
        self.origin_city = origin_city
        self.origin_airport = origin_airport
        self.destination_city = destination_city
        self.destination_airport = destination_airport
        self.out_date = out_date
        self.return_date = return_date
     
     
#main.py        
        
tomorrow = datetime.now() + timedelta(days=1)
six_month_from_today = datetime.now() + timedelta(days=(6 * 30))

for destination in sheet_data:
    flight = flight_search.check_flights(
        ORIGIN_CITY_IATA,
        destination["iataCode"],
        from_time=tomorrow,
        to_time=six_month_from_today
    )        

split() with datetimme

String is sliced with a divider, which was T in this example.

            out_date=data['route'][0]['local_departure'].split("T")[0],
            
            # 'local_departure': '2021-04-20T07:50:00.000Z',
            #result: 2021-04-20
           

Words: aficionados
a person who is very knowledgeable and enthusiastic about an activity, subject, or pastime.
"aficionados of the finest wines"

profile
Dayeon Lee | Django & Python Web Developer

0개의 댓글