Tuesday, May 13, 2014

A break from the tutorial: Intuitive stuff

Hey guys! Let's take a break from the bombarding of information, and let's do something interesting. Let's talk about some of the features that are taken for granted in all the giant websites. You may already have noticed them. If not, double back and check them out. We'll also see how to implement them in your website.

The "Keep me logged in":
Many websites like Facebook and Gmail offer this option at the time of login. What it does is even if you close the browser/tab/window, the next time you open it it opens on your homepage. Even more fascinating, if you try to log in from some other device it you're not logged in, and you even get an alert that someone tried to access your account from an unknown location. Let's see how this is done in steps:

  • When you log in, cookies with your username are stored in your browser. If you close it and reopen it, and access that site again, it checks for that-site-specific cookies. If they are there, they take you to your homepage. Else, you're redirected to the login page.
  • To prevent multiple people accessing the account at the same type, the session is logged in to the database. The username/email is unique, so only one session of that name can be logged in to the database. If another one tries, it captures the IP address, denies it access and warns the user. (We'll see how to track IP addresses in the next article)
  • When you log in, it notes down your IP address. It is added to the list of addresses from which you frequently access that site.
  • On log out, it deletes the cookies and logs you out of the database.

The "Display n search results":
This is very easy. Just maintain a count of how many results are wanted. Assume the form method is GET:
count = int (request.GET['count'])
temp = 0
for row in cur/cur.fetchall ():
    if temp == count:
        break
    else:
        print row[0]
        temp += 1


Opening a new tab on hyperlink or button press:
For hyperlink: <a href = "foo/bar.html" target = "_blank">
For button press: <form action = "/foo/" method = "GET" target = "_blank">

The target = "_blank" does the trick. Note that it have to be inserted into form attributes and not the button's.

That's it for today! Tell me if I missed anything.
Cheers!




Friday, May 9, 2014

Custom queries III: MySQL

Ok, we saw how to connect to an SQLite database in Python. Now let's see MySQL. There's only a small difference in syntax, but it's significant. The steps, however, are the same.

Import the library
import MySQLdb as ms

Note: The as specifies an alternate name for the library. In this case, I won't have to type MySQLdb again and again. I'll just type ms.

Establish a connection
conn = ms.connect (host, username, password, database_name)

If you're running this on a machine, normally host is localhost. You'll have to create a root user, which you'll have to see how to do in your particular OS on the Internet. Provide that username and password. Then execute the command create database db_name and use this database as the fourth field.

Exhausted? So am I. I know it's a lot of effort, but trust me, the results are totally worth it.

Create a cursor as usual
cur = conn.cursor ()

Remember I said %s doesn't work in SQLite? Well, that's the only thing that works here. Let's write a query.

query = "select name from employee where empid = %s" % empid

READ THIS VERY CAREFULLY:
Now, empid is an integer, but you still have to pass is as a string. Assume empid is 1234. The query then becomes:
select name from employee where empid = 1234

Let's look at a query where we need to pass a string.
query = "select empid from employee where name = '%s'" % name

Notice the difference? %s from the first query is replace by '%s' in the second. Assume name is Douglas. The query now becomes:
select empid from employee where name = 'Douglas'

Don't worry if you're confused, go through the paragraph once again. Let it sink in.

OK, NOW RELAX AND ENJOY THE REMAINING PART.

Ok, the rest is pretty much the same.

cur.execute (query)
for row in cur.fetchall ():
    print row[0]

for row in cur: in SQLite is replaced by cur.fetchall (): in MySQL.

Alternatively, you can also use cur.fetchone () if you're sure only one row is going to be returned (for primary keys) or just want it that way.

Hope I didn't miss anything. If I did, please comment. The remaining things are the same for both SQLite and MySQL. Don't forget to commit and close the connection once the job is done.
Cheers!

Wednesday, May 7, 2014

Custom queries II: SQLite

Let's see how to connect to an SQLite database from Python. The current version is SQLite3.
Open a Python file, and import the library:
import sqlite3

Now, open a connection to the database. If the .db file already exists, connection to that file is opened, else a file of that name is created and connection is opened.
conn = sqlite3.connect ("/foo/bar/filename.db")

For executing queries, we need a cursor. So let's initialize that:
cur = conn.cursor ()

Now let's write a query.
cur.execute ("select something from some_table")

You can directly pass the string as a parameter, but for more customisations, you should initialize it separately and pass it as follows:
query = "select foo from bar"
cur.execute (query)

If you want to insert data dynamically into your query, the following is the syntax:
THIS DOES NOT WORK:
query = "select empid from employee where name = '%s'" % name
cur.execute (query)

THIS SHOULD BE DONE:
query = "select empid from employee where name = ?"
data = (name,)
cur.execute (query)

Note that data has to be a list or tuple. The syntax shown forces a single element to be a tuple. However, if there are multiple elements, just list them out normally like this:
query = "select empid, dept from employee where name = ? and salary = ?"
data = (name, sal)
cur.execute (query)

No data needs to be passed for insert and update queries, so just write those normally.
For delete, pass data in the same way as shown.
Now we need to fetch the data we get from select statement. Here's how you do it (assume I executed the previous query):
for row in cur:
    print row[0], row[1]

We selected two values here, namely empid and dept. So row[0] and row[1] will hold empid and dept respectively. This can be extended for several values.

Once you're done, you should commit the changes and close the connection.
conn.commit ()
conn.close ()

In the next article, we'll see how to handle a MySQL database in Python.
Cheers!

Custom queries I: Comparison between SQLite and MySQL

I've already said in earlier posts that you can use SQLite or MySQL as a database for your website. Recently when I was working on one I had to move to MySQL (I'll tell you why later in this article). So I thought I'll tell you guys how to transition.
But first, let's compare.

SQLite:

  • It is a lightweight DBMS
  • It is mainly used for testing and for small websites that do not generate too much data.
  • The biggest advantage is that it handles all the data through a .db file which can be transported elsewhere and used in the same way
  • It supports up to 2^64 rows (wow!)
  • On the downside, for the kind of data that giants like Facebook and Google generate, SQLite falls laughably short
  • It also has low concurrency control, which means that it crashes if too many people are trying to access the same data
The last point, the concurrency control, was the main reason I decided to switch to MySQL. The database of the website was crashing again and again. Let's look at MySQL now.

MySQL:

  • It is tough, inflexible and an extremely powerful DBMS
  • It is used by Facebook, Google, Twitter, pretty much all the web giants that exist today
  • It has very high concurrency control
  • It has the potential to store and handle an unlimited amount of data
  • It has quick crash recovery
  • There is very low chance of deadlocks
  • All in all, if you plan to build a large site this is the DBMS for you
  • The only downside is that it does not generate any file as earlier, so there has to be one native machine running the DBMS
This article is just the first of three of the series Custom queries. The reason I'm writing these three is that the query API that Django provides is good, but it does not allow custom queries (as far as my knowledge goes). For example, you want to customize search parameters and find all people that satisfy multiple conditions. To do this, Python's database API is very useful and can be used very well in Django.
In the next article, we'll see how to write custom queries for SQLite.
Cheers!

Sending emails

If you've noticed, on many sites, once you sign up, it sends you an automated confirmation email. This is another function your site should be able to perform. So today let's take a look at that.
Let's assume you have a Gmail account (if you don't, create one today, it's great!). We'll be using Gmail's email host (wow that rhymed).
Go to the settings.py file and add the following code anywhere in between.

EMAIL_USE_TLS = True
EMAIL_HOST = "smtp.gmail.com"
EMAIL_HOST_USER = "your_name@example.com"
EMAIL_HOST_PASSWORD = "your_password"
EMAIL_PORT = 587

The port number 587 is pretty standard. Also, it is very important to set TLS to True. We'll go into why later.
You have to enter your Gmail password there, but I assure you it is secure. Only the programmer(s) can see it. You may also create another common account and use those credentials instead.
Ok, now we'll need to write the Python code to send emails.
Open the views.py file in the appropriate app and write the following code:

At the top, import the Django's send_mail:
from django.core.mail import send_mail

Also import settings.py:
from django.conf import settings

Later, create this function:
def foo (request):
    title = "some title"
    message = "some message"
    host = settings.EMAIL_HOST_USER
    receiver = ["someone@example.com"]
    send_mail (title, message, host, receiver, fail_silently = False)
    return HttpResponse ("Mail sent successfully")

Some important things to note here:

  • You can directly write send_mail () and pass all the above values as arguments. I just wrote them separately so it's easier to understand.
  • receiver variable has to be a list or tuple, as Django supports sending emails to multiple people (a.k.a. multicasting).
  • fail_silently = False enables you to see what error was generated in case the email wasn't successfully sent. You can then use error handling to do stuff for each error. Or if the mail you're sending is not important (or an advertisement, 'cause people hate that), you can set it to True and set your mind at ease.
That's all for now! I just covered the basics here, there's a lot you can do with exceptions, responses etc. If you have questions, or are getting some error you can't identify the solution for, please feel free to ask in the comments.
Cheers!

Monday, May 5, 2014

Github

Hey guys! For those of you who don't know, Github is a code sharing site on which you can review and edit other people's code and post your own. I have shown you a lot of code on this blog. Some of the code like file upload, login sessions etc is the same and can be reused. So I'm going to post such pieces of code on Github for you guys to review and edit. Please do so, I would be very happy if someone improved upon the code I've written.
Also, my favorite language is Python and I do a lot of other things like software development, hacking in it. I've posted repos for these also. Please feel free to review and edit those too.

Here's the link:

https://github.com/AgentK1729

Cheers!

Sunday, May 4, 2014

File upload

One of the most common functions your website should be able to do is to upload/download pictures, PDFs and other files. In this tutorial I will show you how to create an upload script and save the files to server.
If you recall, I already showed you how to host your site on a free server. Now there are two parts to uploading files:

  1. Creating an upload script post which the file gets stored on either the server or temporary storage on your computer depending on which has more space.
  2. Copying the file from temporary storage to a permanent destination.
Let's take care of this in two parts.

Part I: Creating an upload script
Ok, first we need to create an HTML form. In a file called upload.html, type the following code.

<form action = "/uploaded/" method = "post" enctype="multipart/form-data">
Select an image: <input type = "file" name = "img"><br><br>
<input type = "submit" name = "upload" value = "Upload picture">
</form>

The enctype="multipart/form-data" is extremely important, as it specifies the encryption type of the temp file. With this done, when the 'upload' button is pressed, the file gets stored on temp storage. To render the upload page, write a simple view.

def upload (request):
    return render (request, "upload.html")

The view that we need to write for uploaded is important. But that is in part two.

Part II: Copying file to permanent storage
Now that we have the file, let's copy it to the server. We'll do this in the uploaded view.

def uploaded (request):
  file = request.FILES['img']
  dest = open ("/foo/bar/image_name.jpeg", "w")
for bit in file.read ():
dest.write (bit)
return HttpResponse ("Uploaded")

Note that the extensions of both the files should be same. We can access the temp file through request.FILES. We're reading each unit of the temp file and putting it into our permanent one.
Easy enough, right?
Don't forget to add the URLs in ulrs.py

url (r'^upload/', 'myproject.myapp.views.upload'),
url(r'^uploaded/', 'myproject.myapp.views.uploaded'),

Cheers!

Thursday, May 1, 2014

Session management: Login and logout using cookies

Hey! I know I've not posted for a long time. Truthfully, there was not much new. But there is now, so here I am! Today we'll see how to manage login and logout sessions. If you've noticed when you're on Facebook, if you accidentally close the window, reopen it and go to facebook.com, your homepage is displayed. This is because your browser has received cookies from Facebook and you're still logged in in their database.
For those who don't know, cookies are small packets of information that the user's browser stores in its cache. We'll see how to manage them in Django.

I assume you're familiar with how to use dictionaries in Python. So to create a cookie, simply do the following:
request.session[key] = value

request.session is a dictionary where all cookie data gets stored. For example,
request.session['username'] = 'someUser'

This will store the username as someUser in the browser. Do this when the user logs in. This value can be accessed many views and apps later.
In case the cookie is not erased while logging out then the next time the user opens the site he will stil be logged in.
If no one is logged in and you try to access request.session['username'], it raises a KeyError. You can use this with exception handling to check if anyone is logged into your site.

try:
    username = request.session['username']
    return HttpResponse (username)
except KeyError:
    return HttpRepsonse ("No one is logged in")

On log out, delete the cookies.
del request.session ['username']

Like this, delete all the relevant ones.
Cheers!