Database
 sql >> Teknologi Basis Data >  >> RDS >> Database

Membangun Aplikasi Web Sederhana Dengan Botol, SQLAlchemy, dan Twitter API

Oktober lalu kami menantang audiens PyBites kami untuk membuat aplikasi web untuk menavigasi umpan Tip Python Harian dengan lebih baik. Dalam artikel ini, saya akan membagikan apa yang saya buat dan pelajari selama ini.

Dalam artikel ini Anda akan mempelajari:

  1. Cara mengkloning repo proyek dan menyiapkan aplikasi.
  2. Cara menggunakan API Twitter melalui modul Tweepy untuk memuat tweet.
  3. Cara menggunakan SQLAlchemy untuk menyimpan dan mengelola data (tips dan hashtag).
  4. Cara membuat aplikasi web sederhana dengan Bottle, sebuah web-framework mikro yang mirip dengan Flask.
  5. Cara menggunakan kerangka kerja pytest untuk menambahkan pengujian.
  6. Bagaimana panduan Code Hub yang Lebih Baik menghasilkan kode yang lebih mudah dipelihara.

Jika Anda ingin mengikuti, membaca kode secara detail (dan mungkin berkontribusi), saya sarankan Anda membayar repo. Mari kita mulai.


Penyiapan Proyek

Pertama, Ruang nama adalah salah satu ide bagus yang membunyikan klakson jadi mari kita lakukan pekerjaan kita di lingkungan virtual. Menggunakan Anaconda saya membuatnya seperti ini:

$ virtualenv -p <path-to-python-to-use> ~/virtualenvs/pytip

Buat database produksi dan pengujian di Postgres:

$ psql
psql (9.6.5, server 9.6.2)
Type "help" for help.

# create database pytip;
CREATE DATABASE
# create database pytip_test;
CREATE DATABASE

Kami memerlukan kredensial untuk terhubung ke database dan Twitter API (buat aplikasi baru terlebih dahulu). Sesuai praktik terbaik, konfigurasi harus disimpan di lingkungan, bukan kode. Letakkan variabel env berikut di akhir ~/virtualenvs/pytip/bin/activate , skrip yang menangani aktivasi / penonaktifan lingkungan virtual Anda, pastikan untuk memperbarui variabel untuk lingkungan Anda:

export DATABASE_URL='postgres://postgres:password@localhost:5432/pytip'
# twitter
export CONSUMER_KEY='xyz'
export CONSUMER_SECRET='xyz'
export ACCESS_TOKEN='xyz'
export ACCESS_SECRET='xyz'
# if deploying it set this to 'heroku'
export APP_LOCATION=local

Dalam fungsi menonaktifkan skrip yang sama, saya menghapusnya sehingga kami menjaga hal-hal di luar cakupan shell saat menonaktifkan (meninggalkan) lingkungan virtual:

unset DATABASE_URL
unset CONSUMER_KEY
unset CONSUMER_SECRET
unset ACCESS_TOKEN
unset ACCESS_SECRET
unset APP_LOCATION

Sekarang adalah waktu yang tepat untuk mengaktifkan lingkungan virtual:

$ source ~/virtualenvs/pytip/bin/activate

Kloning repo dan, dengan lingkungan virtual diaktifkan, instal persyaratan:

$ git clone https://github.com/pybites/pytip && cd pytip
$ pip install -r requirements.txt

Selanjutnya, kami mengimpor kumpulan tweet dengan:

$ python tasks/import_tweets.py

Kemudian, verifikasi bahwa tabel telah dibuat dan tweet telah ditambahkan:

$ psql

\c pytip

pytip=# \dt
          List of relations
 Schema |   Name   | Type  |  Owner
--------+----------+-------+----------
 public | hashtags | table | postgres
 public | tips     | table | postgres
(2 rows)

pytip=# select count(*) from tips;
 count
-------
   222
(1 row)

pytip=# select count(*) from hashtags;
 count
-------
    27
(1 row)

pytip=# \q

Sekarang mari kita jalankan tesnya:

$ pytest
========================== test session starts ==========================
platform darwin -- Python 3.6.2, pytest-3.2.3, py-1.4.34, pluggy-0.4.0
rootdir: realpython/pytip, inifile:
collected 5 items

tests/test_tasks.py .
tests/test_tips.py ....

========================== 5 passed in 0.61 seconds ==========================

Dan terakhir jalankan aplikasi Botol dengan:

$ python app.py

Jelajahi http://localhost:8080 dan voilà:Anda akan melihat tips yang diurutkan berdasarkan popularitas. Mengklik tautan hashtag di sebelah kiri, atau menggunakan kotak pencarian, Anda dapat dengan mudah memfilternya. Di sini kita melihat panda kiat misalnya:

Desain yang saya buat dengan MUI - kerangka kerja CSS ringan yang mengikuti pedoman Desain Material Google.



Detail Implementasi


DB dan SQLAlchemy

Saya menggunakan SQLAlchemy untuk berinteraksi dengan DB untuk mencegah keharusan menulis banyak SQL (berlebihan).

Di tips/models.py , kami mendefinisikan model kami - Hashtag dan Tip - bahwa SQLAlchemy akan dipetakan ke tabel DB:

from sqlalchemy import Column, Sequence, Integer, String, DateTime
from sqlalchemy.ext.declarative import declarative_base

Base = declarative_base()


class Hashtag(Base):
    __tablename__ = 'hashtags'
    id = Column(Integer, Sequence('id_seq'), primary_key=True)
    name = Column(String(20))
    count = Column(Integer)

    def __repr__(self):
        return "<Hashtag('%s', '%d')>" % (self.name, self.count)


class Tip(Base):
    __tablename__ = 'tips'
    id = Column(Integer, Sequence('id_seq'), primary_key=True)
    tweetid = Column(String(22))
    text = Column(String(300))
    created = Column(DateTime)
    likes = Column(Integer)
    retweets = Column(Integer)

    def __repr__(self):
        return "<Tip('%d', '%s')>" % (self.id, self.text)

Di tips/db.py , kami mengimpor model ini, dan sekarang mudah untuk bekerja dengan DB, misalnya untuk berinteraksi dengan Hashtag model:

def get_hashtags():
    return session.query(Hashtag).order_by(Hashtag.name.asc()).all()

Dan:

def add_hashtags(hashtags_cnt):
    for tag, count in hashtags_cnt.items():
        session.add(Hashtag(name=tag, count=count))
    session.commit()


Kueri API Twitter

Kami perlu mengambil data dari Twitter. Untuk itu, saya membuat tasks/import_tweets.py . Saya mengemas ini di bawah tugas karena harus dijalankan di cronjob harian untuk mencari tips baru dan memperbarui statistik (jumlah suka dan retweet) pada tweet yang ada. Demi kesederhanaan, saya membuat tabel dibuat ulang setiap hari. Jika kita mulai mengandalkan hubungan FK dengan tabel lain, kita pasti harus memilih pernyataan update daripada delete+add.

Kami menggunakan skrip ini di Project Setup. Mari kita lihat apa fungsinya secara lebih rinci.

Pertama, kita membuat objek sesi API yang kita teruskan ke tweepy.Cursor. Fitur API ini sangat bagus:berkaitan dengan pagination, iterasi melalui timeline. Untuk jumlah tip - 222 pada saat saya menulis ini - sangat cepat. exclude_replies=True dan include_rts=False argumen nyaman karena kami hanya menginginkan tweet Daily Python Tip sendiri (bukan tweet ulang).

Mengekstrak tagar dari kiat hanya membutuhkan sedikit kode.

Pertama, saya mendefinisikan regex untuk sebuah tag:

TAG = re.compile(r'#([a-z0-9]{3,})')

Kemudian, saya menggunakan findall untuk mendapatkan semua tag.

Saya meneruskannya ke collections.Counter yang mengembalikan objek seperti dict dengan tag sebagai kunci, dan dihitung sebagai nilai, diurutkan dalam urutan menurun berdasarkan nilai (paling umum). Saya mengecualikan tag python yang terlalu umum yang akan mengubah hasil.

def get_hashtag_counter(tips):
    blob = ' '.join(t.text.lower() for t in tips)
    cnt = Counter(TAG.findall(blob))

    if EXCLUDE_PYTHON_HASHTAG:
        cnt.pop('python', None)

    return cnt

Terakhir, import_* fungsi di tasks/import_tweets.py lakukan impor tweet dan tagar yang sebenarnya, dengan memanggil add_* Metode DB dari tips direktori/paket.



Membuat aplikasi web sederhana dengan Botol

Dengan pra-pekerjaan ini, membuat aplikasi web ternyata sangat mudah (atau tidak mengherankan jika Anda menggunakan Flask sebelumnya).

Pertama-tama temui Botol:

Bottle adalah kerangka web mikro WSGI yang cepat, sederhana, dan ringan untuk Python. Ini didistribusikan sebagai modul file tunggal dan tidak memiliki dependensi selain Pustaka Standar Python.

Bagus. Aplikasi web yang dihasilkan terdiri dari <30 LOC dan dapat ditemukan di app.py.

Untuk aplikasi sederhana ini, hanya diperlukan satu metode dengan argumen tag opsional. Mirip dengan Flask, perutean ditangani dengan dekorator. Jika dipanggil dengan tag, ia memfilter tip pada tag, jika tidak, ia akan menampilkan semuanya. Dekorator tampilan mendefinisikan template yang akan digunakan. Seperti Flask (dan Django) kami mengembalikan dict untuk digunakan dalam template.

@route('/')
@route('/<tag>')
@view('index')
def index(tag=None):
    tag = tag or request.query.get('tag') or None
    tags = get_hashtags()
    tips = get_tips(tag)

    return {'search_tag': tag or '',
            'tags': tags,
            'tips': tips}

Sesuai dokumentasi, untuk bekerja dengan file statis, Anda menambahkan cuplikan ini di bagian atas, setelah impor:

@route('/static/<filename:path>')
def send_static(filename):
    return static_file(filename, root='static')

Terakhir, kami ingin memastikan bahwa kami hanya berjalan dalam mode debug di localhost, maka APP_LOCATION variabel env yang kami definisikan di Pengaturan Proyek:

if os.environ.get('APP_LOCATION') == 'heroku':
    run(host="0.0.0.0", port=int(os.environ.get("PORT", 5000)))
else:
    run(host='localhost', port=8080, debug=True, reloader=True)


Template Botol

Bottle hadir dengan mesin template bawaan yang cepat, kuat, dan mudah dipelajari yang disebut SimpleTemplate.

Dalam subdirektori views saya mendefinisikan header.tpl , index.tpl , dan footer.tpl . Untuk tag cloud, saya menggunakan beberapa CSS sebaris sederhana yang meningkatkan ukuran tag berdasarkan hitungan, lihat header.tpl :

% for tag in tags:
  <a style="font-size: {{ tag.count/10 + 1 }}em;" href="/{{ tag.name }}">#{{ tag.name }}</a>&nbsp;&nbsp;
% end

Di index.tpl kami mengulangi tipsnya:

% for tip in tips:
  <div class='tip'>
    <pre>{{ !tip.text }}</pre>
    <div class="mui--text-dark-secondary"><strong>{{ tip.likes }}</strong> Likes / <strong>{{ tip.retweets }}</strong> RTs / {{ tip.created }} / <a href="https://twitter.com/python_tip/status/{{ tip.tweetid }}" target="_blank">Share</a></div>
  </div>
% end
{{ tip.likes }} Suka / {{ tip.retweets }} RT / {{ tip.created }} / Bagikan
% akhir

Jika Anda sudah familiar dengan Flask dan Jinja2 ini akan terlihat sangat familiar. Menyematkan Python bahkan lebih mudah, dengan lebih sedikit mengetik—(% ... vs {% ... %} ).

Semua css, gambar (dan JS jika kita menggunakannya) masuk ke subfolder statis.

Dan hanya itu yang diperlukan untuk membuat aplikasi web dasar dengan Botol. Setelah Anda mendefinisikan lapisan data dengan benar, itu cukup mudah.



Tambahkan tes dengan pytest

Sekarang mari kita buat proyek ini sedikit lebih kuat dengan menambahkan beberapa tes. Menguji DB membutuhkan sedikit lebih banyak penggalian ke dalam kerangka kerja pytest, tetapi saya akhirnya menggunakan dekorator pytest.fixture untuk menyiapkan dan menghancurkan database dengan beberapa tweet uji.

Alih-alih memanggil API Twitter, saya menggunakan beberapa data statis yang disediakan di tweets.json .Dan, daripada menggunakan DB langsung, di tips/db.py , saya memeriksa apakah pytest adalah pemanggilnya (sys.argv[0] ). Jika demikian, saya menggunakan tes DB. Saya mungkin akan memfaktorkan ulang ini, karena Botol mendukung bekerja dengan file konfigurasi.

Bagian hashtag lebih mudah untuk diuji (test_get_hashtag_counter ) karena saya bisa menambahkan beberapa hashtag ke string multiline. Tidak perlu perlengkapan.



Kualitas kode penting - Hub Kode Lebih Baik

Better Code Hub memandu Anda secara tertulis, kode yang lebih baik. Sebelum menulis tes, proyek ini mendapat skor 7:

Tidak buruk, tapi kita bisa melakukan yang lebih baik:

  1. Saya menambahkannya ke angka 9 dengan membuat kode lebih modular, mengeluarkan logika DB dari app.py (aplikasi web), meletakkannya di folder tips/paket (refactoring 1 dan 2)

  2. Kemudian dengan pengujian yang ada, proyek ini mendapat skor 10:




Kesimpulan dan Pembelajaran

Tantangan Kode kami #40 menawarkan beberapa praktik yang baik:

  1. Saya membuat aplikasi berguna yang dapat diperluas (saya ingin menambahkan API).
  2. Saya menggunakan beberapa modul keren yang perlu dijelajahi:Tweepy, SQLAlchemy, dan Bottle.
  3. Saya belajar lebih banyak pytest karena saya membutuhkan perlengkapan untuk menguji interaksi dengan DB.
  4. Yang terpenting, karena harus membuat kode dapat diuji, aplikasi menjadi lebih modular yang membuatnya lebih mudah untuk dipelihara. Better Code Hub sangat membantu dalam proses ini.
  5. Saya menerapkan aplikasi ke Heroku menggunakan panduan langkah demi langkah kami.

Kami Menantang Anda

Cara terbaik untuk belajar dan meningkatkan keterampilan pengkodean Anda adalah dengan berlatih. Di PyBites kami memperkuat konsep ini dengan mengatur tantangan kode Python. Lihat koleksi kami yang terus bertambah, garpu repo, dan dapatkan pengkodean!

Beri tahu kami jika Anda membuat sesuatu yang keren dengan membuat Permintaan Tarik dari pekerjaan Anda. Kami telah melihat orang-orang benar-benar berusaha keras melalui tantangan ini, begitu pula kami.

Selamat membuat kode!




  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Tingkat Isolasi Baca Berkomitmen

  2. Tata Kelola Keamanan Data

  3. Easysoft Rilis ODBC-ODBC Bridge untuk Windows 10

  4. Memperhatikan Perkiraan

  5. Cara Menghapus Revisi Postingan menggunakan WP-CLI