पिछले अक्टूबर में हमने अपने PyBites के दर्शकों को डेली पायथन टिप फीड को बेहतर ढंग से नेविगेट करने के लिए एक वेब ऐप बनाने की चुनौती दी थी। इस लेख में, मैंने जो कुछ भी बनाया और सीखा, उसे मैं साझा करूँगा।
इस लेख में आप सीखेंगे:
- प्रोजेक्ट रेपो का क्लोन कैसे बनाएं और ऐप कैसे सेट करें।
- ट्वीपी मॉड्यूल के माध्यम से ट्वीट में लोड करने के लिए ट्विटर एपीआई का उपयोग कैसे करें।
- डेटा (टिप्स और हैशटैग) को स्टोर और प्रबंधित करने के लिए SQLAlchemy का उपयोग कैसे करें।
- बोतल के साथ एक साधारण वेब ऐप कैसे बनाएं, फ्लास्क के समान एक माइक्रो वेब-फ्रेमवर्क।
- परीक्षण जोड़ने के लिए पाइटेस्ट ढांचे का उपयोग कैसे करें।
- कैसे बेहतर कोड हब के मार्गदर्शन ने अधिक रखरखाव योग्य कोड बनाया।
यदि आप साथ चलना चाहते हैं, तो कोड को विस्तार से पढ़ें (और संभवतः योगदान दें), मेरा सुझाव है कि आप रेपो को फोर्क करें। आइए शुरू करें।
प्रोजेक्ट सेटअप
सबसे पहले, नेमस्पेस एक बेहतरीन विचार है तो चलिए वर्चुअल वातावरण में अपना काम करते हैं। एनाकोंडा का उपयोग करके मैं इसे इस तरह बनाता हूं:
$ virtualenv -p <path-to-python-to-use> ~/virtualenvs/pytip
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
हमें डेटाबेस और ट्विटर एपीआई से जुड़ने के लिए क्रेडेंशियल्स की आवश्यकता होगी (पहले एक नया ऐप बनाएं)। सर्वोत्तम अभ्यास के अनुसार कॉन्फ़िगरेशन को पर्यावरण में संग्रहित किया जाना चाहिए, न कि कोड में। ~/virtualenvs/pytip/bin/active के अंत में निम्नलिखित env चर रखें , वह स्क्रिप्ट जो आपके वर्चुअल परिवेश के सक्रियण/निष्क्रियण को संभालती है, आपके परिवेश के लिए चरों को अद्यतन करना सुनिश्चित करती है:
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
उसी स्क्रिप्ट के डिएक्टिवेट फंक्शन में, मैं उन्हें अनसेट करता हूं ताकि वर्चुअल एनवायरनमेंट को डिएक्टिवेट (छोड़ते) करते समय हम चीजों को शेल स्कोप से बाहर रखें:
unset DATABASE_URL
unset CONSUMER_KEY
unset CONSUMER_SECRET
unset ACCESS_TOKEN
unset ACCESS_SECRET
unset APP_LOCATION
अब आभासी वातावरण को सक्रिय करने का एक अच्छा समय है:
$ source ~/virtualenvs/pytip/bin/activate
रेपो को क्लोन करें और, वर्चुअल वातावरण सक्षम होने के साथ, आवश्यकताओं को स्थापित करें:
$ git clone https://github.com/pybites/pytip && cd pytip
$ pip install -r requirements.txt
इसके बाद, हम इसके साथ ट्वीट्स का संग्रह आयात करते हैं:
$ python tasks/import_tweets.py
फिर, सत्यापित करें कि तालिकाएँ बनाई गई थीं और ट्वीट जोड़े गए थे:
$ 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
आइए अब परीक्षण चलाते हैं:
$ 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 ==========================
और अंत में बॉटल ऐप को इसके साथ चलाएं:
$ python app.py
http://localhost:8080 और voilà पर ब्राउज़ करें:आपको लोकप्रियता के आधार पर क्रमबद्ध युक्तियों को देखना चाहिए। बाईं ओर हैशटैग लिंक पर क्लिक करके, या खोज बॉक्स का उपयोग करके, आप उन्हें आसानी से फ़िल्टर कर सकते हैं। यहां हम पांडा देखते हैं उदाहरण के लिए युक्तियाँ:
मैंने एमयूआई के साथ जो डिज़ाइन बनाया है - एक हल्का सीएसएस ढांचा जो Google के सामग्री डिज़ाइन दिशानिर्देशों का पालन करता है।
कार्यान्वयन विवरण
डीबी और SQLAlchemy
मैंने बहुत सारे (अनावश्यक) एसक्यूएल लिखने से रोकने के लिए डीबी के साथ इंटरफेस करने के लिए SQLAlchemy का उपयोग किया।
tips/models.py . में , हम अपने मॉडल को परिभाषित करते हैं - Hashtag
और Tip
- कि SQLAlchemy 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)
टिप्स/db.py . में , हम इन मॉडलों को आयात करते हैं, और अब DB के साथ काम करना आसान है, उदाहरण के लिए Hashtag
के साथ इंटरफेस करना मॉडल:
def get_hashtags():
return session.query(Hashtag).order_by(Hashtag.name.asc()).all()
और:
def add_hashtags(hashtags_cnt):
for tag, count in hashtags_cnt.items():
session.add(Hashtag(name=tag, count=count))
session.commit()
ट्विटर एपीआई क्वेरी करें
हमें ट्विटर से डेटा पुनर्प्राप्त करने की आवश्यकता है। उसके लिए, मैंने tasks/import_tweets.py . बनाया है . मैंने इसे कार्यों . के अंतर्गत पैक किया है क्योंकि इसे मौजूदा ट्वीट्स पर नई युक्तियों और अद्यतन आंकड़े (पसंद और रीट्वीट की संख्या) देखने के लिए दैनिक क्रोनजॉब में चलाया जाना चाहिए। सादगी के लिए मेरे पास रोजाना टेबल बनाए जाते हैं। यदि हम अन्य तालिकाओं के साथ FK संबंधों पर भरोसा करना शुरू करते हैं, तो हमें निश्चित रूप से डिलीट+ऐड पर अपडेट स्टेटमेंट चुनना चाहिए।
हमने इस स्क्रिप्ट का इस्तेमाल प्रोजेक्ट सेटअप में किया था। आइए देखें कि यह और अधिक विस्तार से क्या करता है।
सबसे पहले, हम एक API सत्र ऑब्जेक्ट बनाते हैं जिसे हम tweepy.Cursor में पास करते हैं। एपीआई की यह विशेषता वास्तव में अच्छी है:यह समयरेखा के माध्यम से पुनरावृति करते हुए, पेजिनेशन से संबंधित है। सुझावों की मात्रा के लिए - 222 जब मैं इसे लिखता हूं - यह वास्तव में तेज़ है। exclude_replies=True
और include_rts=False
तर्क सुविधाजनक हैं क्योंकि हम केवल डेली पायथन टिप के अपने ट्वीट चाहते हैं (पुनः ट्वीट नहीं)।
युक्तियों से हैशटैग निकालने के लिए बहुत कम कोड की आवश्यकता होती है।
सबसे पहले, मैंने एक टैग के लिए एक रेगेक्स परिभाषित किया:
TAG = re.compile(r'#([a-z0-9]{3,})')
फिर, मैंने findall
. का उपयोग किया सभी टैग प्राप्त करने के लिए।
मैंने उन्हें संग्रह में पास कर दिया। काउंटर जो कुंजी के रूप में टैग के साथ ऑब्जेक्ट की तरह एक ताना देता है, और मूल्यों के रूप में गिना जाता है, मूल्यों द्वारा अवरोही क्रम में आदेश दिया जाता है (सबसे आम)। मैंने बहुत सामान्य पायथन टैग को बाहर कर दिया जो परिणामों को तिरछा कर देगा।
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
अंत में, import_*
कार्यों/import_tweets.py . में कार्य करता है add_*
. पर कॉल करके ट्वीट और हैशटैग का वास्तविक आयात करें टिप्स . की डीबी विधियां निर्देशिका/पैकेज।
बोतल से एक साधारण वेब ऐप बनाएं
इस पूर्व-कार्य के साथ, वेब ऐप बनाना आश्चर्यजनक रूप से आसान है (या यदि आपने पहले फ्लास्क का उपयोग किया है तो आश्चर्य की बात नहीं है)।
सबसे पहले बॉटल से मिलें:
बोतल पायथन के लिए एक तेज, सरल और हल्का WSGI माइक्रो वेब-ढांचा है। इसे एकल फ़ाइल मॉड्यूल के रूप में वितरित किया गया है और इसमें पायथन मानक पुस्तकालय के अलावा कोई निर्भरता नहीं है।
अच्छा। परिणामी वेब ऐप में <30 LOC शामिल है और इसे app.py में पाया जा सकता है।
इस सरल ऐप के लिए, वैकल्पिक टैग तर्क के साथ एक ही विधि की आवश्यकता होती है। फ्लास्क के समान, रूटिंग को डेकोरेटर्स द्वारा नियंत्रित किया जाता है। यदि टैग के साथ कॉल किया जाता है तो यह टैग पर युक्तियों को फ़िल्टर करता है, अन्यथा यह उन सभी को दिखाता है। व्यू डेकोरेटर उपयोग करने के लिए टेम्पलेट को परिभाषित करता है। फ्लास्क (और Django) की तरह हम टेम्पलेट में उपयोग के लिए एक निर्देश लौटाते हैं।
@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}
दस्तावेज़ के अनुसार, स्थिर फ़ाइलों के साथ काम करने के लिए, आप इस स्निपेट को आयात के बाद सबसे ऊपर जोड़ते हैं:
@route('/static/<filename:path>')
def send_static(filename):
return static_file(filename, root='static')
अंत में, हम यह सुनिश्चित करना चाहते हैं कि हम केवल लोकलहोस्ट पर डिबग मोड में चलें, इसलिए APP_LOCATION
env वैरिएबल जिसे हमने प्रोजेक्ट सेटअप में परिभाषित किया है:
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)
बोतल टेम्पलेट
बॉटल एक तेज़, शक्तिशाली और सीखने में आसान बिल्ट-इन टेम्पलेट इंजन के साथ आता है जिसे SimpleTemplate कहा जाता है।
दृश्य उपनिर्देशिका में मैंने एक header.tpl . परिभाषित किया है , index.tpl , और footer.tpl . टैग क्लाउड के लिए, मैंने गिनती के हिसाब से कुछ सरल इनलाइन सीएसएस बढ़ते हुए टैग आकार का उपयोग किया, देखें header.tpl :
टैग में टैग के लिए% for tag in tags:
<a style="font-size: {{ tag.count/10 + 1 }}em;" href="/{{ tag.name }}">#{{ tag.name }}</a>
% end
index.tpl . में हम युक्तियों पर लूप करते हैं:
सुझावों में टिप के लिए% 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
यदि आप फ्लास्क और जिंजा 2 से परिचित हैं तो यह बहुत परिचित दिखना चाहिए। कम टाइपिंग के साथ, पायथन को एम्बेड करना और भी आसान है—(% ...
बनाम {% ... %}
)।
सभी सीएसएस, इमेज (और अगर हम इसका इस्तेमाल करते हैं तो जेएस) स्टैटिक सबफ़ोल्डर में चले जाते हैं।
और बॉटल के साथ एक बेसिक वेब ऐप बनाने के लिए बस इतना ही है। एक बार जब आप डेटा स्तर को ठीक से परिभाषित कर लेते हैं तो यह बहुत आसान हो जाता है।
पाइटेस्ट के साथ परीक्षण जोड़ें
आइए अब कुछ परीक्षण जोड़कर इस परियोजना को थोड़ा और मजबूत बनाते हैं। डीबी का परीक्षण करने के लिए पाइटेस्ट ढांचे में थोड़ी और खुदाई की आवश्यकता थी, लेकिन मैंने कुछ परीक्षण ट्वीट्स के साथ डेटाबेस को स्थापित करने और फाड़ने के लिए pytest.fixture डेकोरेटर का उपयोग करना समाप्त कर दिया।
Twitter API को कॉल करने के बजाय, मैंने tweets.json . में उपलब्ध कराए गए कुछ स्थिर डेटा का उपयोग किया .और, लाइव DB का उपयोग करने के बजाय, tips/db.py . में , मैं जाँचता हूँ कि क्या pytest कॉलर है (sys.argv[0]
) यदि हां, तो मैं परीक्षण डीबी का उपयोग करता हूं। मैं शायद इसे रिफैक्टर करूंगा, क्योंकि बॉटल कॉन्फिग फाइलों के साथ काम करने का समर्थन करता है।
हैशटैग भाग का परीक्षण करना आसान था (test_get_hashtag_counter
) क्योंकि मैं एक मल्टीलाइन स्ट्रिंग में कुछ हैशटैग जोड़ सकता था। किसी फिक्स्चर की आवश्यकता नहीं है।
कोड गुणवत्ता मायने रखती है - बेहतर कोड हब
बेहतर कोड हब आपको लिखित रूप में मार्गदर्शन करता है, ठीक है, बेहतर कोड। परीक्षण लिखने से पहले परियोजना ने 7:
. स्कोर कियाबुरा नहीं है, लेकिन हम बेहतर कर सकते हैं:
-
मैंने कोड को अधिक मॉड्यूलर बनाकर, डीबी लॉजिक को app.py (वेब ऐप) से निकालकर, इसे टिप्स फोल्डर/पैकेज (रिफैक्टरिंग 1 और 2) में डालकर इसे 9 तक बढ़ा दिया।
-
फिर परीक्षणों के साथ परियोजना ने 10:
. का स्कोर बनाया
निष्कर्ष और सीखना
हमारे कोड चैलेंज #40 ने कुछ अच्छे अभ्यास की पेशकश की:
- मैंने एक उपयोगी ऐप बनाया है जिसे बढ़ाया जा सकता है (मैं एक एपीआई जोड़ना चाहता हूं)।
- मैंने खोज के लायक कुछ अच्छे मॉड्यूल का उपयोग किया:ट्वीपी, SQLAlchemy, और बॉटल।
- मैंने कुछ और पाइटेस्ट सीखा क्योंकि मुझे डीबी के साथ बातचीत का परीक्षण करने के लिए फिक्स्चर की आवश्यकता थी।
- सबसे बढ़कर, कोड को परीक्षण योग्य बनाने के लिए, ऐप अधिक मॉड्यूलर बन गया जिससे इसे बनाए रखना आसान हो गया। इस प्रक्रिया में बेटर कोड हब बहुत मददगार साबित हुआ।
- मैंने हमारी चरण-दर-चरण मार्गदर्शिका का उपयोग करके ऐप को Heroku में परिनियोजित किया है।
हम आपको चुनौती देते हैं
अपने कोडिंग कौशल को सीखने और सुधारने का सबसे अच्छा तरीका अभ्यास करना है। PyBites में हमने Python कोड चुनौतियों को व्यवस्थित करके इस अवधारणा को मजबूत किया है। हमारे बढ़ते हुए संग्रह को देखें, रेपो को फोर्क करें, और कोडिंग प्राप्त करें!
अगर आप अपने काम का पुल रिक्वेस्ट करके कुछ कूल बनाते हैं तो हमें बताएं। हमने लोगों को वास्तव में इन चुनौतियों का सामना करते हुए देखा है, और हमने भी ऐसा ही किया है।
हैप्पी कोडिंग!