Using Paypal with Django

by shabda on November 11, 2008

Paypal has a comprehensive API to use their services programatically. The ExpressCheckout API allows you to get the user’s details and then process the payments on your servers. They include a SOAP and NVP API. With NVP you do a GET to the Paypal servers with Url encoded values, get responses in plain text and work with them.

The basic flow for ExpressCheckout is something like this,

  1. You make a SetExpressCheckout request to Paypal, passing your credentials and and the amount you want to charge etc.
  2. Paypal returns an response with ACK of SUCCESS and token which you need to pass to subsequent requests.
  3. You transfer the user to Paypal site, passing the token returned in step 2.
  4. User logs in, and authorises transfer. Paypal redirects back to the SUCCESS_URL specified in step 1, passing the token and PayerID.
  5. You make a GetExpressCheckoutDetails request to Paypal, apssing token, payer id and other details.
  6. Paypal returns the user’s and transactions details.
  7. You ask user to confirm details.
  8. You make a DoExpressCheckoutPayment request to Paypal. At this point the money is transferred from user’s account to your account.

Now you can do the requests to Paypal very simply by sending requests, (it is just Url encoded name-value pair), but here is a Django snippet to make this wonderfully easy.

Before you can make requests to Paypal, servers you need to get API credentials. While developing your app, you of course, do not want to use actual Paypal money. Paypal makes available a sandbox where you can use virtual money before you go live.

  1. Go to developer.paypal.com and request a new sandbox API credentials.
  2. (Optionally)Read https://cms.paypal.com/us/cgi-bin/?cmd=_render-content&content_ID=developer/howto_api_reference to understand how does the Paypal NVP api works.
  3. We would two pages. [a] View 1: Where we do SetExpressCheckout and show a link to Paypal. [b] View 2: Where we do GetExpressCheckoutDetails, get the user’s details, get a confirm from user. On a confirmation from user we post to the same page and do a DoExpressCheckoutPayment.

[Totally untested code ahead. I am copying and simplifying from one of our applications.]

#view 1

def veiw1(request):
        ...........
    pp = paypal.PayPal()
    token = pp.SetExpressCheckout(...)
    paypal_url = pp.PAYPAL_URL + token
    payload = {'paypal_url':paypal_url}
    return render_to_response('template1.html', payload, RequestContext(request))

In the template send user to {{ paypal_url }} when they want to pay.

#View 2
#View 2 would be called after Paypal redirects after user authorises the transfer.

def view2(request):
    token = request.GET.get('token', '')
    pp = paypal.PayPal()
    if request.method == 'GET':
        paypal_details = pp.GetExpressCheckoutDetails(token, return_all = True)
        payload = {}
        if 'Success' in paypal_details['ACK']:
            payload['ack'] = True
            token = paypal_details['TOKEN'][0]
            first_name = paypal_details['FIRSTNAME'][0]
            .....
        return render_to_response('template2.html', payload, RequestContext(request))
    if request.method == POST:
        payment_details  = pp.DoExpressCheckoutPayment(token = token)
        if 'Success' in payment_details['ACK']:
            pass
            #We have been paid. DO things like, enable subsciprion, ship goods etc.
            return HttpResponseRedirect(payment_done_url)

Here in template2.html, we show the user/transaction details, and a on user’s confirmation do a post to the same url. This should help you get started with integrating Paypal with Django.

Resources.

  1. Paypal developer forums
  2. Paypal developer documentation

Need to build a Paypal enabled webapp? We can help

{ 5 comments }

Building reusable Django apps

by shabda on November 11, 2008

Recently I updated a lot of our old apps to be compatible with Django 1.0 and be reusable. Before we go further, let me define a _ Reusable Django App _.

A Django app is reusable if 

*  It is app. (That is, it is not a project, and has no settings.py/manage.py.)
* It can be dropped in an existing project, and only places where the project should need editing are `settings.py` `installed_apps` and the projects level `urls.py`.
* It can be used in the project with an arbitrary url prefix.

The updated apps were written initially for Django 0.96 and were coupled to the projects, so it was not possible to include them in other projects. After updating these I was able to include them in in a single project as a part of this site.

The apps were,

The following apps from 7days7apps.com


Without further ado hints to help you make your apps reusable,

Always use models.permalink with get_absolute_url type of functions:

If you have code like

def get_absolute_url(self):
    return '/project/%s/' % self.name

this is tying your app to a specific url structure. (and hence to a specific project). Instead a code like,

@models.permalink
def get_absolute_url(self):
    return ('app.views.view_func', [self.name])

allows you to use this app with any arbitrary url structure in the project.

Always use reverse when you use HttpResponseRedirect.

For a similar reason as 1. Of course this does not apply if you are doing return HttpResponseRedirect('.')

Always use {% url %} with <a href=".

For reasons as in 1.

Do all imports assuming your apps exist on Pythonpath. So your imports should look like
from myapp.models import ModelClass

and not

from myproject.myapp.models import ModelClass

as this ties the app to a specific project.

Use named urlpatterns. Prefix app name to url patterns names.

Named url patterns make point 2 and 3 much simpler. Prefixing appname to url pattern name makes removes name collision and simplifies using reverse and {% url %}.

Serve your static media from /MEDIAURL/<appname>/:

Each app could be using a stylesheet named style.css. If we were serving media from user /MEDIAURL/, we are tied to one stylesheet for the whole project. If you were serving it from /MEDIAURL/<app_name>/ it is as simple as symlinking a directory.

After using these pointers, your apps are decoupled from the project. To use the apps with Usware site, all we needed to do was to add the following lines to svn:externals

blogango https://svn.uswaretech.com/blogango/trunk/blogango/
djikiki https://svn.uswaretech.com/djikiki/trunk/djikiki/
...............
pastebin https://svn.uswaretech.com/7days7apps/trunk/djpaste/pastebin   site_media/kamp https://svn.uswaretech.com/7days7apps/trunk/kasekamp/site_media/kamp/

And put the apps in settings.INSTALLED_APPS and include the app urls.py in the projects urls.py.


Need an Amazing Webapp built? Talk to Usware. Need help with any of these apps? Talk to Usware.

{ 0 comments }

Using subdomains with Django

by shabda on October 10, 2008

Django makes using beautiful urls a snap. However using subdomains with Django is not so obvious. Here is an article explaining this.

Advantages of subdomain

  1. Sometimes looks more professional. Users will prefer someblog.wordpress.com over wordpress.com/someblog.
  2. If each part of your site is Under a different untrusted users, you might want to give them a separate subdomain, so that if they do Blackhat Seo on their part, the main site is not harmed.
  3. Your users can point a Cname to their subdomain to use domain of their choice with their subdomain.

Disadvantages of subdomain

  1. When you need subdomains, you will know it. If you do not if you need it or not, you probably do not.

Getting the current subdomain is ridiculously easy.

bits = urlparse.urlsplit(request.META['HTTP_HOST'])[0].split('.')
bits[0]

now bits[0] is you subdomain.

However if you are using subdomains you are probably going to be needing this,

  1. In all your views.
  2. In all your templates.

So you need to expose the subdomains using

  1. A Middleware for all requests.
  2. A request context for all templates.

A Middleware is nothing but a normal Python class which can implement process_request, process_response and others.

The code to expose subdomains for all requests via a middleware is,

import urlparse

class GetSubdomainMiddleware:

    def process_request(self, request):
    bits = urlparse.urlsplit(request.META['HTTP_HOST'])[0].split('.')
    if not( len(bits) == 3):
        pass#Todo Raise an exception etc
    request.subdomain = bits[0]

The way to populate subdomain in all templates is similar

def populate_board(request):
    "Populate the board in the template"
    return {'board':request.subdomain}#request.subdomain has been populated via the Middleware.

And now you need to edit you settings.py file to add TEMPLATE_CONTEXT_PROCESSORS and MIDDLEWARE_CLASSES to include your Middleware and context processor.

You are almost ready to go, however your cookies will not work across sub domains. To make your cookies work across subdomains, add this line to your settings.py

SESSION_COOKIE_DOMAIN = ‘.example.com’ if not DEBUG else ‘.local

Thanks

{ 0 comments }

Dynamic forms with Django

by shabda on October 10, 2008

Newforms, (or forms now) are without doubt one of the coolest features of Django. (Of course after Admin, Localflavor, and many others). Here is some sample code.

class EmployeeForm(forms.Form):
    name = forms.CharField()
    age = forms.IntegerField()
    resume = forms.FileField()

Just this code gives you

  1. A form which knows how to render itself as Html.
  2. A form which knows how to validate data on the server side.
  3. A form which knows how to show the relevant errors.

However think of this scenario,

You need to customise your form depending on values in the Database.

What you want to do is

class EmployeeForm(forms.Form):
    name = forms.CharField()
    "Show more fields depending on the Values in DB for a specific employees."
    #....
    #....
    #....

You can do this without resorting to any black magic. Here is the code to do so,

#in models.py

type_mapping = {'CharField':forms.CharField(max_length = 100), 'TextField': forms.CharField(widget = forms.Textarea),
        'BooleanField':forms.BooleanField(required = False),
        'URLField': forms.URLField(), 'EmailField': forms.EmailField()
        }

class EmployeeFieldModel(models.Model):
    "Model for employee form fields for a specific Job board."
    employee = models.ForeignKey(Employee)
    name = models.CharField(max_length = 100)
    type = models.CharField(max_length = 100)
    order = models.IntegerField()

#in forms.py

def get_employee_form(employee):
    """Return the form for a specific Board."""
    employee_fields = EmployeeFieldModel.objects.filter(employee = employee).order_by('order')
    class EmployeeForm(forms.Form):
    def __init__(self, *args, **kwargs):
        forms.Form.__init__(self, *args, **kwargs)
        self.employee = employee
    def save(self):
        "Do the save"
    for field in employee_fields:
    setattr(EmployeeForm, field.name, copy(type_mapping[field.type]))
    return type('EmployeeForm', (forms.Form, ), dict(EmployeeForm.__dict__))

#in views.py

employee = Employee.objects.get(employee_slug)
get_employee_form(employee)

PS. A similar techniques works for Dynamic models.
PPS. Yes I have worked with Oracle. Yes, all my data models start with Employee and Departments.


Want to build an Web Application. Talk to Usware

{ 3 comments }

Generating PDFs with Django

by shabda on October 7, 2008

If your web app creates report chances are you also want this report in PDF form. The Django docs describe a way to generate PDFs using ReportLab. Here is some code from there.

from reportlab.pdfgen import canvas
from django.http import HttpResponse

def some_view(request):
    # Create the HttpResponse object with the appropriate PDF headers.
    response = HttpResponse(mimetype='application/pdf')
    response['Content-Disposition'] = 'attachment; filename=somefilename.pdf'

    # Create the PDF object, using the response object as its "file."
    p = canvas.Canvas(response)

    # Draw things on the PDF. Here's where the PDF generation happens.
    # See the ReportLab documentation for the full list of functionality.
    p.drawString(100, 100, "Hello world.")

    # Close the PDF object cleanly, and we're done.
    p.showPage()
    p.save()
    return response

This suffers from two problems,

  1. You are laying out your PDF using Python, which means if you later want to change the design of the PDF you need to change the Python code.
  2. Most of the time you already have the report in Html, form, writing the same PDF via ReportLab is error prone.

Both these problems can be cleanly solved using Pisa, a Html2Pdf library. We proceed as,

  1. Generate a Html representation of Pdf using normal Django macienry.
  2. Convert to Pdf using Pisa.
  3. Return PDF.

This solves both our problems as,

  1. Designers can edit the template to change the layout of Pdf.
  2. The code to generate the Html and Pdf views can share code.

Here is some example code.

def html_view(request, as_pdf = False):
    #Get varaibles to populate the template
    payload = {'data':data, ....}
    if as_pdf:
        return payload
    return render_to_response('app/template.html', payload, RequestContext(request))

def pdf_view(request):
    payload = html_view(request, as_pdf = True)
    file_data = render_to_string('app/template.pdf', payload, RequestContext(request))
    myfile = StringIO.StringIO()
    pisa.CreatePDF(file_data, myfile)
    myfile.seek(0)
    response =  HttpResponse(myfile, mimetype='application/pdf')
    response['Content-Disposition'] = 'attachment; filename=coupon.pdf'
    return response

{ 4 comments }

Building SEO optimised Django web applications

by shabda on October 7, 2008

This is an article about building SEO, optmised web applications with Django. I assume you already have an idea how Seo works. We will take the example of a hypothetical Blog app to explain the suggestions made.

Without further ado, here are the tips.

Basic

  1. Use beautiful URLs.
  2. Learn the difference between HTTP 301 and HTTP 302 redirects.
  3. Layout content in a SEO friendly way.
  4. Create a sitmaps.

Not so obvious

  1. Use the Admin to allow end users to update fields.
  2. Do not get your Url structures too deep.
  3. Create a robots.txt file.
  4. Link to your pages wisely.
  5. Minimise duplicate content.
  6. Ping Google when your site gets updated.

Basic tips.

If you are building a production web app, you should really be using these techniques.

Use beautiful URLs.

Say our app has a model like,

class Entry(models.Model):
      title = models.CharField(max_length = 100)
      body = models.TextField()

It would be very tempting to have Urls like /entry/15/, and map this url to the entry with PK 15. Resist this temptation. Search Engines need help to decide what a page is about, and the Urls plays a major part in that. Instead we want the Url to depend on the title.

class Entry(models.Model):
      title = models.CharField(max_length = 100)
      body = models.TextField()
      slug = models.SlugField()

      def save(self):
        self.slug = '-'.join(self.title.split())#And clean title, and make sure this is unique.
        super(Entry, self).save()

Then we can use slug, and have Urls like /entry/seo-tips-for-django/

Read more:
[1]: Dynamic URLs vs. Static URLs

Learn the difference between HTTP 301 and HTTP 302 redirects.

A HTTP 301 redirects says that the url currently being accessed has moved permanenetly, while a HTTP 302 is temporary redirect which asks search engines to try the same url next time. In Django a Http 301 maps to HttpResponsePermanenetRedirect, and a HTTP 302 maps to HttpResponseRedirect. A 301 redirect makes the search engines count the links pointing to a old Url for the new Url.

Suppose our old Url was /entry/seo-tips-for-django/, and we edited the title to “Best SEO tips for Django”, and want the new url to be /entry/best-seo-tips-for-django/. Now as “Cool URIs Do not change”, we want to do an redirect from /entry/seo-tips-for-django/ to /entry/best-seo-tips-for-django/. As some people may have already linked to /entry/seo-tips-for-django/, we want a HttpResponsePermananentRedirect here.

Layout content in a SEO friendly way.

Django gives you complete control over how your Html will appear. Use this to your advantage.

Search engines give more weight to the content which appears earlier in a page layout. So layout your page where the the content area appears before the footer, and then layout your pages using CSS.

For example the first base template is better than second,

<body>
{% block content %}
{% endblock %}
{% block sidebar %}
{% endblock %}
{% block footer %}
{% endblock %}
</body>


<body>
{% block footer %}
{% endblock %}
{% block sidebar %}
{% endblock %}
{% block content %}
{% endblock %}
</body>

Create a sitmaps.

Django comes with a wonderful Sitemaps framework. Use this to generate a Sitemap for all our dynamic pages.

Here is the all the code you need to generate the sitemap for our Entries, taken directly from Django Sitemaps page, and it works perfectly. Plus this is your urls.py and you have a shiny xml sitemap ready.

Read More
[1]: Site Map

Use the Admin to allow end users to update fields.

Use the wonderful Admin interface to your advantage. For example, for /entry/seo-tips-for-django/ we can use the Admin to allow users to update the slug without updating the title.

Do not get your Url structures too deep.

Search Engines give more weight to pages which are closer to the root of the site. Instead of /blog/entry/2008/oct/2008/seo-tips-for-django/, prefer /entry/seo-tips-for-django/. As Django makes including urlconfs inside other urlconfs so easy, this can lead to deeper Url structure than needed.

For example your Django project has a main urls.py,

which does,

url(r'^blog/', include('blog.urls')),

and blog/urls.py does

url(r'^search/', include('blog.searchurls')),

and blog/urls.py does

url(r'^search/$', 'search_view'),

then your serach page will be at /blog/search/search/, when it should probably be at /search/. Include with care.

which includes blog/urls.py

Create a robots.txt file.

Use Django Robots to create robots,txt file for your Django site.

Link to your pages wisely.

Eg. When you are linking to the the entry page from main page/other page on your site use, use descriptive anchor texts. SO the permalink for our entry pages shuld not be,

<a href="{{ entry.get_absolute_url }}">Read More</a>

But rather,

<a href="{{ entry.get_absolute_url }}">{{ entry.title }}</a>

Minimise duplicate content.

Search engines hate duplicate content. So try not to have the same content on multiple Urls.

For example see this innocous looking url pattern

urlpatterns = patterns('',
    (r'^entry/(\w+)/', 'blog.view.entry'),

    ...

This url pattern will match for all of /entry/seo-tips-for-django/1, /entry/seo-tips-for-django/2, /entry/seo-tips-for-django/3 and similar.

To make sure only /entry/seo-tips-for-django/ matches, use

urlpatterns = patterns('',
    (r'^entry/(\w+)/$', 'blog.view.entry'),
    ...

On a similar note, say you have commenst for your Blog, which you want permalinks for.

Do not do this.

class Comment(models.Model):
     def get_absolute_url(self):
      #You would use permalink here.
      return '/comment/%s/' % self.id # or even '/comment/%s/'  % self.slug

Instead what you want here is,

class Comment(models.Model):
     def get_absolute_url(self):
      return '%s#%s' % (self.entry.get_absolute_url(), self.id)

And create named anchors in your entries template. This makes sure that each comment is visible at only one Url.

Ping Google when your site gets updated.

You would have created a Dynamic sitemap using the sitemaps framework. SO when your content gets updated, you sitemap would get updated too. Let Google know of this using django.contrib.sitemaps.ping_google

from django.contrib.sitemaps import ping_google

 class Entry(models.Model):
     # ...
     def save(self, force_insert=False, force_update=False):
     super(Entry, self).save(force_insert, force_update)
     try:
         ping_google()
     except Exception:
         # Bare 'except' because we could get a variety
         # of HTTP-related exceptions.
         pass

http://docs.djangoproject.com/en/dev/ref/contrib/sitemaps/#pinging-google


Need a web application built? Talk to us.

{ 4 comments }

What is Usware Technologies?

by shabda on August 27, 2008

From the sales pitch,

Usware Technologies is a Web Application Development Studio specialising in Django and Jquery. We build “Amazing Web Apps”.

But why Usware?

A lot of software is built as Themware. They give you specifications, you take the specification, you never talk to them till the software is built. Waterfall Model of software development suck.

Software development does not have to suck. There is a better way to develop software.

With rise of Agile Languages, and Agile Methodology, we can start to build Usware. They give you specifications, you read it, and US builds it. Iterative development FTW.

Enough theory. Why Usware?

Your customers do not know what they want. When they say “we will know it, when we see it” they are correct. Software Development is complex not because the technology is complex, it is complex because your client requirements are complex, because people are complex. Themware models of development may help you fight technical complexity, but how can they fight the human complexity, if you never talk to end users during development.

Even more enough theory. How Usware?

Iterative Development, FTW! As Usware we develop Usware (Imagine that!). We use a Project Management tool, which does not fight us. We have at least a weekly iteration. The end users get a chance to give feedback early in the development cycle.

{ 0 comments }

Hello world!

by admin on August 17, 2008

In [1]: print 'Hello World'
Hello World

In [2]: from __future__ import braces
------------------------------------------------------------
SyntaxError: not a chance (<ipython console>, line 1)


In [3]: import this
The Zen of Python, by Tim Peters

Beautiful is better than ugly.
Explicit is better than implicit.
Simple is better than complex.
Complex is better than complicated.
Flat is better than nested.
Sparse is better than dense.
Readability counts.
Special cases aren't special enough to break the rules.
Although practicality beats purity.
Errors should never pass silently.
Unless explicitly silenced.
In the face of ambiguity, refuse the temptation to guess.
There should be one-- and preferably only one --obvious way to do it.
Although that way may not be obvious at first unless you're Dutch.
Now is better than never.
Although never is often better than *right* now.
If the implementation is hard to explain, it's a bad idea.
If the implementation is easy to explain, it may be a good idea.
Namespaces are one honking great idea -- let's do more of those!

In [4]: 

Thank you for reading The Usware Blog.

{ 0 comments }