Table of contents
1.
Introduction🙋
2.
Setting up the Project🖥️
3.
Understanding the Implementation🚀
3.1.
🛢️DataBase and SQLAlchemy
4.
Query the Twitter API🎳
5.
Making the App🧑‍💻
6.
Frequently Asked Questions
6.1.
What do you understand about the bottle web framework?
6.2.
Describe Django and the Bottle.
6.3.
What does WSGI stand for?
6.4.
Is Apache a WSGI?
6.5.
What is Falcon for Python?
7.
Conclusion
Last Updated: Mar 27, 2024
Medium

Building Simple Web Applications Using Bottle Framework, SQLAlchemy and Twitter API

Author ANKIT MISHRA
0 upvote
Career growth poll
Do you think IIT Guwahati certified course can help you in your career?

Introduction🙋

The bottle is a WSGI-compliant single Source File web framework using only the Python standard library as its only external dependency (stdlib).

Introduction

The bottle is fantastic in the following web development scenarios:

🔥Idea prototyping

🔥Understanding the creation of web frameworks

🔥Creating and maintaining a straightforward personal web application

In this blog, we will be Building a Simple Bottle App using the Twitter API and SQLAlchemy with the help of Bottle Framework.

Setting up the Project🖥️

Create a Virtual environment using Anaconda(SHELL):

$ virtualenv -p <path-to-python-to-use> ~/virtualenvs/pytip
You can also try this code with Online Python Compiler
Run Code

 

Now, you have to create a production and a test database in Postgres(SQL):

$ psql
psql (9.6.4, server 9.6.2)

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

 

To connect to the database and the Twitter API, we'll need credentials (create a new app first). Best practices recommend that environment data, not code, be used to hold configuration. Make sure to change the environment-specific variables before adding the following env variables at the end of your virtual environment's activation/deactivation script, located at /virtualenvs/pytip/bin/activate:

export DATABASE_URL='postgres://postgres:password@localhost:6273/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

 

To prevent objects from entering the shell scope after deactivating (leaving) the virtual environment, I unset them in the deactivate method of the same script.

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

 

Now we will activate the virtual environment:

$ source ~/virtualenvs/pytip/bin/activate
You can also try this code with Online Python Compiler
Run Code

 

Now clone the repo and, with the virtual-environment enabled, install the requirements:

$ git clone https://github.com/pybites/pytip && cd pytip
$ pip install -r requirements.txt
You can also try this code with Online Python Compiler
Run Code

 

Next, we will import the collection of tweets using:

$ python tasks/import_tweets.py
You can also try this code with Online Python Compiler
Run Code

 

Now, verify that the tables were created and the tweets were added:

$ 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

 

✅Run the Tests:

$ pytest
====================== test session starts ======================
platform darwin -- Python 3.6.1, 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 ==========================
You can also try this code with Online Python Compiler
Run Code

 

🎯Running the Bottle App:

$ python app.py
You can also try this code with Online Python Compiler
Run Code

 

Visit http://localhost:8080 and bingo. You should see the suggestions listed in order of decreasing popularity. You may quickly filter them by using the search box or a hashtag link on the left. Here are some examples of panda advice:

Output image

Understanding the Implementation🚀

🛢️DataBase and SQLAlchemy

We have used SQLAlchemy to interface with the DB to prevent having to write a lot of (redundant) SQL in our App.

In tips/models.py, we define our own models - Hashtag and Tip - that SQLAlchemy will map to the DB tables in the SQL:

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


Base = declarative_base()


class Hashtag(Base):
   __tablename__ = 'hashtags'
   id_name = 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_name  = 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_name , self.text)
You can also try this code with Online Python Compiler
Run Code

 

In tips/db.py, we import all of these models, and now it's pretty much easy to work with DB,. Like, to interface with the Hashtag model is as follows:

def get_hashtags():
    #returns all the hashtags provided in API
   return session.query(Hashtag).order_by(Hashtag.name.asc()).all()
You can also try this code with Online Python Compiler
Run Code
def add_hashtags(hashtags_cnt):
   for tag, count in hashtags_cnt.items():
       session.add(Hashtag(name=tag, count=count))
   session.commit()
You can also try this code with Online Python Compiler
Run Code

Query the Twitter API🎳

TWitter API image

We must gather the data from Twitter. We have made tasks/import tweets.py to do that. I packaged this under tasks since a daily cronjob should be used to search for fresh tips and update statistics (such as the number of likes and retweets) on posted tweets. I have the tables updated every day for the purpose of simplicity. Update statements are always preferable to delete+add if we begin to rely on FK relations with other tables.

Before using tweepy.Cursor, we first establish an API session object. The API has a beneficial function that deals with pagination and iterating across the timeline. It moves along quite quickly for the number of tips it has—222 as of this writing. We just want Daily Python Tip's tweets. Thus, the exclude replies=True and include rts=False options are convenient (not re-tweets).

First, I defined the regex for a tag like:

TAG = re.compile(r'#([a-z0-9]{3,})')
You can also try this code with Online Python Compiler
Run Code

 

I then used findall to retrieve every tag. They were passed off to collections.

With the counts as values and the tags as keys, the counter returns a dict-like object that is sorted by values (most common). I removed the overused Python tag because it would bias the results.

def get_hashtag_counter(tips):
    #adding in the variables
   blob = ' '.join(t.text.lower() for t in tips)
   cnt = Counter(TAG.findall(blob))
   #It is an hashtag counter


   if EXCLUDE_PYTHON_HASHTAG:
       #excluding the arguement value
       cnt.pop('python', None)


   return cnt
You can also try this code with Online Python Compiler
Run Code

 

Finally, the import_* functions in tasks/import_tweets.py do the actual import of the tweets and hashtags, calling add_* DB methods of the tips directory/package.

Making the App🧑‍💻

Making the APP

Only one method is required for this straightforward app, along with an optional tag argument. The routing is managed using decorators, much like Flask. When called with a tag, the tips are filtered; otherwise, they are all displayed. The view decorator specifies the template to use. For use in the template, we return a dict, just as Flask (and Django).

@route('/')
@route('/<tag>')
@view('index')
def index(tag=None):
   #Bottle App setup
   tag = tag or request.query.get('tag') or None
   #collecting tags
   tags = get_hashtags()
   tips = get_tips(tag)
   #returning the values
   return {'search_tag': tag or '',
           'tags': tags,
           'tips': tips}
You can also try this code with Online Python Compiler
Run Code

 

As per official documentation, to work with static files, you add this snippet at the top after the imports:

@route('/static/<filename:path>')
def send_static(filename):
   return static_file(filename, root='static')
You can also try this code with Online Python Compiler
Run Code

 

Finally, we want to make sure we only run in debug mode on localhost, hence the APP_LOCATION env variable we defined in Project Setup:

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)
You can also try this code with Online Python Compiler
Run Code

 

In the views subdirectory, We have defined a header.tpl, index.tpl, and footer.tpl. For the tag name cloud, I used some simple inline CSS to increase the tag size by count, see header.tpl:

% for tag in tags:
 <a style="font-size: {{ tag.count/10 + 1 }}em;" href="/{{ tag.name }}">#{{ tag.name }}</a>  
% end
You can also try this code with Online Python Compiler
Run Code

 

In index.tpl we will loop over the tips:

% 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
You can also try this code with Online Python Compiler
Run Code

 

If you are familiar with the Flask and Jinja2 this should look very familiar. Embedding Python is easier, with less typing—(% ... vs {% ... %}).

If we'd use it, all CSS and images (and JS) go into the static subfolder.

And that's all there is to make a basic web app with Bottle Framework. Once you have the data layer properly defined, now it's pretty straightforward.

Frequently Asked Questions

What do you understand about the bottle web framework?

The bottle is a Python WSGI micro web framework that is quick, easy, and lightweight. It is supplied as a single file module and only requires the Python Standard Library as a dependency.

Describe Django and the Bottle.

Model-template-view (MTV) is the basis for its design. It includes many tools that application developers require, including an ORM framework, admin panel, directory structure, and more.

What does WSGI stand for?

The Web Server Gateway Interface (pronounced whiskey or WIZ-ghee) is a straightforward calling standard used by web servers to route requests to web applications or frameworks created in the Python programming language.

Is Apache a WSGI?

A Python application is embedded within the Apache HTTP Server using the mod WSGI module, which enables communication via the Python WSGI interface as specified in Python PEP 333. One Python method for creating high-quality, high-performance web apps is WSGI.

What is Falcon for Python?

Falcon is a dependable, high-performance Python web framework for creating microservices and the backends of large-scale applications. It supports the REST architectural movement and strives to be as efficient as possible by doing the bare minimum.

Conclusion

In this article, we have extensively discussed Building Simple Web Applications Using Bottle Framework, SQLAlchemy and Twitter API.

To learn more about Bottle Web Framework, see Bottle DocumentationBottleand Python Frameworks.

Be curious

Refer to our guided paths on Coding Ninjas Studio to learn more about DSA, Competitive Programming, JavaScript, System Design, etc. Enroll in our courses, refer to the mock test and problems; look at the interview experiences and interview bundle for placement preparations.

Do upvote our blogs if you find them helpful and engaging!

Happy Learning, Ninjas!

Thank You!
Live masterclass