30 กรกฎาคม 2560

รู้จัก firebase realtime datatabase on python

ก่อนจะไปเขียน python ก็ต้องมี firebase ให้เรียกใช้งานก่อน
เริ่มต้นไปที่ firebase google (ต้องใช้ google account)

firebase คือ อะไร ไปอ่านเวปนี้ ref. เวปนี้จะเน้นไปทาง java


สร้าง project ขึ้นมาก่อน (google ให้เราสร้างได้ฟรี 25 projects)

click ที่ Database ก็จะมีหน้าตาประมาณนี้ ส่วนที่จะเอาไปใช้คือ ลิงค์

[ https://sample-app-a1e7f.firebaseio.com/ ] แต่ละคน จะได้ส่วนนี้แตกต่างกันไป

ลิงค์นี้คือ ส่วนที่เอาไว้เรียกใช้งาน


แต่โดย default ตรง Ruls (กฎ) จะไม่ยอมให้คนอื่น acces ได้เลย ดังนั้น เราต้องเข้าไปแก้ไขซะ

เบื้องต้นก็แก้ให้เป็น true ให้หมดไปก่อน



อ่านที่เวปนี้ เขียนอธิบายไว้ละเอียด ref.

ตัวอย่างข้อมูล ก็จะได้หน้าตาประมาณนี้ เป็น JSON


ทดสอบว่าสามารถใช้งานได้ สามารถเรียกดูได้จาก

https://sample-app-a2e7f.firebaseio.com/mydata.json


ต่อมาในส่วนของ python

ขั้นแรก import firebase package ตอนนี้ มีอยู่ 3 แหล่งที่ทาง google แนะนำ ref



1. python-firebase by   Özgür Vatansever


ลง package ที่ต้องจำเป็นก่อนที่จะใช้งานตัวนี้คือ requests

$ sudo pip install requests
$ sudo pip install python-firebase
$ sudo pip install python-firebase-gae 
** ตัวนี้ถ้าไปใช้กับ google appengine standard จะมีปัญหา เนื่องจากไม่ support multi processor ให้ติดตั้ง python-firebase อีกตัวแทน
ดูรายละเอียดได้ที่ https://github.com/b4oshany/python-firebase-gae/



ใน code python ให้เพิ่ม 2 บรรทัดนี้ลงไป

from firebase import firebase
firebase = firebase.FirebaseApplication('https://sample-app-x.firebaseio.com', None)

ตรงส่วนสีแดง ก็ใส่ URL link ของตัวเองลงไป

วิธีเขียนข้อมูลลง DB ref


PUT กับ POST ใช้ต่างกันยังไง

- PUT จะต้องระบุ key
- POST จะสร้าง random key ให้

เช่น

result = firebase.post(id, data['comment'])
firebase จะ random key ให้

/id
   -Kq7rSDsQRXWKAVu0phH: "comment"
หากอยากระบุ key ของตัวเอง และ ให้ firebase สร้าง key ให้

result = firebase.post(id,{'comment': 'mycomment'})
ได้ nested JSON

/id
   -Kq7swawlLJlz07VEBFT
      comment: "mycomment"
กรณี PUT จะต้องระบุ key ให้ด้วย
result = firebase.put(id,'comment',{'msg': 'mycomment'})
จะได้ผลลัพธ์แบบนี้

/id
   -comment
      msg: "mycomment"
ถ้าอ้างอิง id , comment เดิม ข้อมูลที่ put ลงมาจะเขียนทับ ข้อมูลเก่า

PATCH ใช้ update key ที่ระบุไว้ โดยไม่กระทบ กับ ข้อมูลส่วนอื่น

DELETE เอาไว้ลบข้อมูล

firebase.delete(id, 'comment')

วิธีการเรียกอ่านข้อมูล  GET ref

result = firebase.get('/users', '1')
ใส่ option {'print': 'pretty'} เพื่อให้ ผลออกมาอ่านได้ง่ายขึ้น

result = firebase.get('/users/2', None, {'print': 'pretty'}, {'X_FANCY_HEADER': 'VERY FANCY'})
ลองเอา URL นี้วางใน browser  https://sample-app-a1e7f.firebaseio.com/mydata.json

จะได้ผลออกมาแบบนี้ ซึ่งอ่านยากมาก


ลองเพิ่ม option print = pretty

https://sample-app-a1e7f.firebaseio.com/mydata.json?print=pretty

จะได้ผลออกมาแบบนี้ ซึ่งอ่านง่ายกว่าเยอะ


Authentication


from firebase import firebase
firebase = firebase.FirebaseApplication('https://your_storage.firebaseio.com', authentication=None)
result = firebase.get('/users', None, {'print': 'pretty'})
print result
{'error': 'Permission denied.'}

authentication = firebase.Authentication('THIS_IS_MY_SECRET', 'ozgurvt@gmail.com', extra={'id': 123})
firebase.authentication = authentication
print authentication.extra
{'admin': False, 'debug': False, 'email': 'ozgurvt@gmail.com', 'id': 123, 'provider': 'password'}

user = authentication.get_user()
print user.firebase_auth_token
"eyJhbGciOiAiSFMyNTYiLCAidHlwIjogIkpXVCJ9.eyJhZG1pbiI6IGZhbHNlLCAiZGVidWciOiBmYWxzZSwgIml
hdCI6IDEzNjE5NTAxNzQsICJkIjogeyJkZWJ1ZyI6IGZhbHNlLCAiYWRtaW4iOiBmYWxzZSwgInByb3ZpZGVyIjog
InBhc3N3b3JkIiwgImlkIjogNSwgImVtYWlsIjogIm96Z3VydnRAZ21haWwuY29tIn0sICJ2IjogMH0.lq4IRVfvE
GQklslOlS4uIBLSSJj88YNrloWXvisRgfQ"

result = firebase.get('/users', None, {'print': 'pretty'})
print result
{'1': 'John Doe', '2': 'Jane Doe'}
เมื่อ sign-in ด้วย email,password  ใช้ function Authentication เพื่อ ให้ firebase สร้าง token สำหรับใช้ตรวจสอบว่ากับ rule ว่ามีสิทธิ์มั้ย

authentication = firebase.Authentication('password', 'email', extra={'id': 123})
ดูค่าที่ทาง server return กลับมา

print authentication.extra

{'admin': False, 
 'debug': False,
 'email': 'ozgurvt@gmail.com',
 'id': 123,
 'provider': 'password'}

provider คือ attribute ที่บอกว่า เรา authen ด้วยวิธีใด
เนื่องจาก firebase รองรับ multi provider คือ login ด้วย google , facebook .. สามารถมี accout id เดียวกันได้ id คือ ตัวบอกว่า login ด้วยวิธีนี้ แล้วจะได้ id อะไร

2.  Pyrebase by Jame childs-maidment

* ควรใช้กับ python3 หากใช้กับ python2 อาจจะมีข้อผิดพลาด

pip install pyrebase
เรียกใช้

import pyrebase

config = {
  "apiKey": "apiKey",
  "authDomain": "projectId.firebaseapp.com",
  "databaseURL": "https://databaseName.firebaseio.com",
  "storageBucket": "projectId.appspot.com",
  "serviceAccount": "path/to/serviceAccountCredentials.json"
}

firebase = pyrebase.initialize_app(config)

serviceAccount ไว้สำหรับเมื่อ admin login เข้ามาสามารถใช้งานได้โดยไม่สน rule ที่ประกาศใน firebase

วิธีการ create serviceAccountCredentials ref

1. เข้าไปที่หน้า firebase console แล้วเลือก setting (รูปเฟือง) > users and permissions



2.  เลือก Service accounts



3. ที่ฝั่งขวา เลือก firebase-adminsdk  แล้วกด create key



4. เมื่อได้ไฟล์มา เอาไปวางไว้ที่ server เพื่อ เรียกใช้  (ตัวอย่าง ส่วนหนึ่ง)

Pyrebase เรียกใช้ firebase service ได้ถึง 3 (python-firebase ได้แค่ database , authen)

- firebase.auth() - Authentication
- firebase.database() - Database
- firebase.storage() - Storage

Authentication

sign_in_with_email_and_password() จะส่ง user data และ token เพื่อใช้กับ firebase rule

# Get a reference to the auth service
auth = firebase.auth()

# Log the user in
user = auth.sign_in_with_email_and_password(email, password)

# Get a reference to the database service
db = firebase.database()

# data to save
data = {
    "name": "Mortimer 'Morty' Smith"
}

# Pass the user's idToken to the push method
results = db.child("users").push(data, user['idToken'])
ระบุ user['idToken'] ด้วยเพื่อให้มี สิทธิ์ในการ write

ปกติ token จะ expire ภายใน 1 ชม. ดังนั้นหากมีการใช้อยู่ให้เรา refresh ใหม่เรื่อยๆ

user = auth.sign_in_with_email_and_password(email, password)
# before the 1 hour expiry:
user = auth.refresh(user['refreshToken'])
# now we have a fresh token
user['idToken']

Manage User

create user ที่ใช้ email /password

auth.create_user_with_email_and_password(email, password)
* ต้อง enable sign-in method ที่ firebase dashboard ด้วย



Verifying emails
auth.send_email_verification(user['idToken'])

Sending password reset emails
auth.send_password_reset_email("email")

Get account information
auth.get_account_info(user['idToken'])

Database

 - Save data

ใช้ child() method ในการสร้าง path ลงไปในแต่ละ level (google support 32 levels)
db = firebase.database()
db.child("users").child("Morty")
push : ใช้เก็บข้อมูลที่ต้องไม่ซ้ำ สร้าง key อัตโนมัติ, timestamp-based key
data = {"name": "Mortimer 'Morty' Smith"}
db.child("users").push(data)
set : เมื่อต้องการระบุ key ของตัวเอง key ที่ระบุคือ "Morty"
data = {"name": "Mortimer 'Morty' Smith"}
db.child("users").child("Morty").set(data)
update : อัพเดทข้อมูลที่มีอยู่แล้ว
db.child("users").child("Morty").update({"name": "Mortiest Morty"})
remove : ลบข้อมูลที่มีอย่แล้ว
db.child("users").child("Morty").remove()

multi-location updates : อัพเดทพร้อมกับหลายที่
data = {
    "users/Morty/": {
        "name": "Mortimer 'Morty' Smith"
    },
    "users/Rick/": {
        "name": "Rick Sanchez"
    }
}

db.update(data)

ใช้ push อัพเดทพร้อมกันหลายที่ต้องใช้คู่กับ generate_key() method.
data = {
    "users/"+db.generate_key(): {
        "name": "Mortimer 'Morty' Smith"
    },
    "users/"+db.generate_key(): {
        "name": "Rick Sanchez"
    }
}

db.update(data)

 - Retrieve data

val : เมื่อได้ object มา ใช้ val() ในการ

users = db.child("users").get()
print(users.val()
# {"Morty": {"name": "Mortimer 'Morty' Smith"},
        "Rick": {"name": "Rick Sanchez"}}
ดึงเฉพาะ value จาก attribute ที่ต้องการ
print(users.val()["name"])
#{ Mortimer 'Morty' Smith ,
# Rick Sanchez }
key : method key() เรียกค่า key อย่างเดียว

user = db.child("users").get()

print(user.key())

 # users
each : ดึงค่าออกมาเป็น list แล้วใช้ key() , val() แสดงค่าอีกที

all_users = db.child("users").get()

for user in all_users.each():

    print(user.key()) # Morty

    print(user.val()) # {name": "Mortimer 'Morty' Smith"}

    print(user.val()["name"])
get : ดึงค่าจาก path ทั้งหมด
all_users = db.child("users").get()
shallow : ดึงเฉพาะ ค่า key ออกมาเท่านั้น
all_user_ids = db.child("users").shallow().get()

# {"Morty",
        "Rick"}
* shallow() ใช้ร่วมกับ complex querie ไม่ได้

streaming : จับการเปลี่ยนแปลงของข้อมูลทันที ที่มีการเปลี่ยน

def stream_handler(message):

    print(message["event"]) # put

    print(message["path"]) # /-K7yGTTEp7O549EzTYtI

    print(message["data"]) # {'title': 'Pyrebase', "body": "etc..."}



my_stream = db.child("posts").stream(stream_handler)
อย่างน้อยควรจะ put หรือ patch ข้อมูลด้วย Streaminig from the REST API

ถ้ามีการทำ multiple stream ควรระบุ stream_id ด้วย

my_stream = db.child("posts").stream(stream_handler, stream_id="new_posts")
close the stream
my_stream.close()

Complex Queries

Queries สามารถใช้ method ต่อกันได้เรื่อยๆ

users_by_name = db.child("users").order_by_child("name").limit_to_first(3).get()
ผลลัพธ์จะได้ 3 users แรกเรียงตามชื่อ

order_by_child : เรียงตาม level ที่กำหนด ตาม key

users_by_name = db.child("users").order_by_child("name").get()
equal_to : คืนค่าที่มี value ตามที่กำหนด

users_by_score = db.child("users").order_by_child("score").equal_to(10).get()
คืนค่า users ที่มี score เท่ากับ 10

start_at and end_at : ระบุ range ของข้อมูล

users_by_score = db.child("users").order_by_child("score").start_at(3).end_at(10).get()
คืนค่า users เรียงตาม score ที่มี score อยู่ระหว่าง 3-10

limit_to_first and limit_to_last : limit ข้อมูลที่รับ

users_by_score = db.child("users").order_by_child("score").limit_to_first(5).get()
order_by_key : เรียง key ตาม ascending (น้อยไปมาก)

users_by_key = db.child("users").order_by_key().get()
order_by_value : เรียงตาม value

users_by_value = db.child("users").order_by_value().get()

Storage

ใช้เก็บข้อมูลรูปภาพ ไฟล์

child : ระบุ path ที่จะใช้เก็บ

storage.child("images/example.jpg")
put : รับ path จาก local file และ ใส่ token เป็น option ได้

storage = firebase.storage()

# as admin

storage.child("images/example.jpg").put("example2.jpg")

# as user

storage.child("images/example.jpg").put("example2.jpg", user['idToken'])
หากรับ filename มาจาก <input type="file" name="image" />
ตอนรับข้อมูลให้ส่ง request.files.get('image') มาให้ put

storage.child("images/example.jpg").put(request.files.get('image'))

download : ดึงข้อมูลมาเก็บลง local และ สามารถเปลี่ยนชื่อได้

storage.child("images/example.jpg").download("downloaded.jpg")
get_url : คืนค่า url สำหรับ access ผ่าน http

storage.child("images/example.jpg").get_url()
# https://firebasestorage.googleapis.com/v0/b/storage-url.appspot.com/o/images%2Fexample.jpg?alt=media
generate_key : db.generate_key() ใช้ตาม Firebase's key generation algorithm

sort : ปกติ เราจะใช้ orderby แต่ถ้าเราต้องการเรียงอีกที ให้ใช้ sort() method
.
articles = db.child("articles").order_by_child("date").start_at(startDate).end_at(endDate).get()

articles_by_likes = db.sort(articles, "likes")

*Storage ยังไม่มี method delete()





1 ความคิดเห็น: