Home » Odeon Blogs »

Nai Chng

IOError: encoder jpeg not available

Recently, I ran into this bug on my new Macbook Pro


  1. Traceback (most recent call last):
  2. File "userprofile/tests.py", line 410, in test_profile_image_change
  3. image1 = self.generate_image()
  4. File "userprofile/tests.py", line 238, in generate_image
  5. Image.new('RGB', (800, 600)).save(tmp, 'JPEG')
  6. File "/Library/Python/2.7/site-packages/PIL/Image.py", line 1439, in save
  7. save_handler(self, fp, filename)
  8. File "/Library/Python/2.7/site-packages/PIL/JpegImagePlugin.py", line 471, in _save
  9. ImageFile._save(im, fp, [("jpeg", (0,0)+im.size, 0, rawmode)])
  10. File "/Library/Python/2.7/site-packages/PIL/ImageFile.py", line 495, in _save
  11. e = Image._getencoder(im.mode, e, a, im.encoderconfig)
  12. File "/Library/Python/2.7/site-packages/PIL/Image.py", line 401, in _getencoder
  13. raise IOError("encoder %s not available" % encoder_name)
  14. IOError: encoder jpeg not available

The fix for this was simple as provided by Quan, one of the devs I work with on a project. The reason is JPEG support is not available in PIL 1.1.7. To fix this:

  1. sudo pip uninstall PIL
  2. sudo brew install jpeg
  3. sudo pip install PIL
The should resolve the error.


Category: Python


Tagged as: django python

Leave a Comment

List of useful Django Links

Here are some useful Django links I've came across over the last few months:

  1. Video
    1. https://code.djangoproject.com/wiki/DjangoScreencasts - A bit underwhelming to be honest
    2. http://blip.tv/djangocon - Over 100 videos from the past DjangoCon's in one place
  2. Tips/Tricks
    1. http://stevelosh.com/blog/2011/06/django-advice/ - A very helpful list of information. A must read!
    2. http://www.kenjiyamamoto.com/blog/2009/05/28/some-django-tips-and-tricks-pages-that-ive-found-helpful/ - Written in 2009, this is kinda dated but contains a good list of tips nonetheless
    3. http://elweb.co/programacion/33-projects-that-make-developing-django-apps-awesome/ - List of use Django apps made by other people
    4. http://agiliq.com/blog/ - The guys are agiliq.com write a lot of stuff about Django
    5. http://stackoverflow.com/questions/550632/favorite-django-tips-features - Pretty much guess it from the title
    6. http://lincolnloop.com/django-best-practices/#table-of-contents - Good walkthrough of a Django project. This is before Django 1.3 so the bits on static media aren't are relevant
  3. Presentations
    1. http://media.revsys.com/images/django-1.3-cheatsheet.pdf - List of commands for Django 1.3
    2. http://www.slideshare.net/zeeg/djangocon-2010-scaling-disqus - Lessons from the largest site (I believe) using Django
    3. http://thebuild.com/presentations/unbreaking-django.pdf - Optimisation tips
  4. Vim Plugins (Not necessarily Django specific)
    1. https://github.com/kevinw/pyflakes-vim - Checks for un-used variables and imports
    2. https://github.com/mhz/vim-matchit - Useful for jumping between HTML tags
    3. https://github.com/tpope/vim-ragtag - Mappings
    4. https://github.com/scrooloose/nerdcommenter - Commenting
  5. Other
    1. http://www.reddit.com/r/django - Django sub-reddit in reddit
    2. irc://irc.freenode.net/django - This is where all the pro's hangout on IRC.
Come across any other useful links? Do add them to the comments and I'll update the post accordingly!


Category: Django


Tagged as: django

Leave a Comment

Django Shortcuts: render

One of the great things about being a web developer is that you're always constantly learning new tricks to make your job easier. Yesterday, I found this really neat django shortcut render.

According to Django docs:

  1. render
  2. render(request, template[, dictionary][, context_instance][, content_type][, status][, current_app])

  3. Combines a given template with a given context dictionary and returns an HttpResponse object with that rendered text.
  4. render() is the same as a call to render_to_response() with a context_instance argument that forces the use of a RequestContext.


So basically, you go from having something like this: 

  1. return render_to_response(template, locals(), context_instance=RequestContext(request))


to this:

  1. return render(request, template, locals())


I like! :)


Category: Django


Tagged as: django django-shortcuts render

Leave a Comment

Learning Vim: Tab Autocomplete

I recently made the switch to Vim mainly due to my frustrations with folder navigation in Geany. When pairing with my colleagues, seeing them move through folders and changing code made me feel like I was programming with the handbrakes on. 


Two weeks on, I've been learning more tricks day by day and I can say it's one of the best decisions I've made so far in my short programming journey. For those who are learning, I found this blog post to be very true in that I learnt vim progressively. I had an idea of the basics before I decided to make the jump permanently.

One of my major gripes with Vim was that the auto-complete shortcut was mapped to control-n. This felt very unnatural to me. So, I hunted around for a snippet I could paste into my .vimrc file that could solve this problem and viola, I found the follow code snippet on http://vim.wikia.com/wiki/Autocomplete_with_TAB_when_typing_words:

  1. "Use TAB to complete when typing words, else inserts TABs as usual.
  2. "Uses dictionary and source files to find matching words to complete.

  3. "See help completion for source,
  4. "Note: usual completion is on <c-n> but more trouble to press all the time.
  5. "Never type the same word twice and maybe learn a new spellings!
  6. "Use the Linux dictionary when spelling is in doubt.
  7. "Window users can copy the file to their machine.
  8. function! Tab_Or_Complete()
  9. if col('.')>1 && strpart( getline('.'), col('.')-2, 3 ) =~ '^\w'
  10. return "\</c-n><c-n>"
  11. else
  12. return "\<tab>"
  13. endif
  14. endfunction
  15. :inoremap </tab><tab> <c-r>=Tab_Or_Complete()<cr>
  16. :set dictionary="/usr/dict/words"</cr></c-r></tab></c-n>


Category: vim


Tagged as: vim

Leave a Comment

Django Admin Template Customization

Recently, I had to do some Django Admin customisation for a client at Odeon. The client requested changing the name of the Add <model_name> button to Activate <model_name> for a specific model. 




Just to be sure we're all on the same page, I'm referring to the gray Add user button at the top right corner.

To change this value, we will have to over-ride the Django Admin template that renders this view. The location for Django Admin templates are at django/contrib/admin/templates/admin. For this particular page, I will need to over-ride the change_list.html file. Specifically, I will need to over-ride the following block of code:

 61           {% block object-tools-items %}
 62             <li>
 63               <a href="add/{% if is_popup %}?_popup=1{% endif %}" class="addlink">
 64                 {% blocktrans with cl.opts.verbose_name as name %}Add {{ name }}{% endblocktrans %}
 65               </a>
 66             </li>
 67           {% endblock %}

According to Django docs, I will need to set the directory and folders in a specific manner. Given that I am changing the template for a specific model in a specific app, I will need to create a change_list.html file in the following path: <project_name>/<app>/templates/admin/<app>/<model_name>. 

Finally, this is what the change_list.html file looks like in the above mentioned path:

  1 {% extends "admin/change_list.html" %}
  2 {% load i18n %}
  3 
  4 {% block object-tools-items %}
  5 <li>
  6     <a href="add/{% if is_popup %}?_popup=1{% endif %}" class="addlink">
  7         {% blocktrans with cl.opts.verbose_name as name %}Activate {{ name }}{% endblocktrans %}</a>
  8 </li>
  9 {% endblock %}

As you can see, I've changed Add to Activate. The best thing about this is that you can re-use this process to change other parts of Django Admin if you wish. 

Hope this helps!


Category: Django


Tagged as: django django-admin

Leave a Comment

Django PayPal Step-by-Step Integration

Is this your first time integrating Paypal with Django? Can't get the signals to work? Don't know how to test django-paypal on your local machine? Hopefully, this step-by-step blog post will address all the above mentioned problems and more. This tutorial will cover only Paypal Standard IPN although most of the initial steps are applicable for the other payments methods as well.

1. Install django-paypal

There are a couple of version floating around namely: 
Cramer's is a fork from Boxall's version so it's more update. For this tutorial, we will be using Boxall because we found Boxall's first.
  1. git clone git://github.com/johnboxall/django-paypal.git paypal

2. Create a PayPal developer account

  1. Goto https://developer.paypal.com and sign up.
  2. Once you're in, create a preconfigured account
  3. Do this twice, one for account type Buyer and one for account type Seller
  4. Your dashboard should then look like this:

3. Modify settings.py file

  1. For the PAYPAL_RECEIVER_EMAIL, set this to the business account email you created in step 2. In this example, it is naiyun_1311845021_biz@od-eon.com
  2. After you have entered this, run syncdb to create the paypal tables
  1. # settings.py
  2. ...
  3. INSTALLED_APPS = (... 'paypal.standard.ipn', ...)
  4. ...
  5. PAYPAL_RECEIVER_EMAIL = "naiyun_1311845021_biz@od-eon.com" #change this to yours

4. Create a url

# urls.py

  1. from django.conf.urls.defaults import patterns, include, url

  2. urlpatterns = patterns('',
  3. # Examples:
  4. url(r'^$', 'cat.homepage.views.home', name='home'),
  5. url(r'^paypal/$', 'cat.homepage.views.paypal', name='paypal'),

  6. url(r'^admin/doc/', include('django.contrib.admindocs.urls')),
  7. url(r'^admin/', include(admin.site.urls)),
  8. )

  9. urlpatterns += patterns('',
  10. (r'^something/hard/to/guess/', include('paypal.standard.ipn.urls')),
  11. )

  1. Replace cat.homepage with your project.appname

5. Create a view and template

  1. # views.py
  2. ...
  3. from paypal.standard.forms import PayPalPaymentsForm
  4. from django.conf import settings
  5. from django.core.urlresolvers import reverse

  6. def paypal(request):

  7. # What you want the button to do.

  8. paypal_dict = {
  9. "business": settings.PAYPAL_RECEIVER_EMAIL,
  10. "amount": "1.00",
  11. "item_name": "name of the item",
  12. "invoice": "unique-invoice-id",
  13. "notify_url": "%s%s" % (settings.SITE_NAME, reverse('paypal-ipn')),
  14. "return_url": "http://www.example.com/your-return-location/"
  15. "cancel_return": "http://www.example.com/your-cancel-location/",
  16. }

  17. # Create the instance.
  18. form = PayPalPaymentsForm(initial=paypal_dict)
  19. context = {"form": form.sandbox()}
  20. return render_to_response("paypal.html", context)

  21. # paypal.html

  22. {{ form }}

  1. Don't worry about what to put for settings.SITE_NAME first, we'll get to that in a bit
  2. The notify_url is the url that PayPal will try to send a POST request
  3. return_url is the page that Paypal redirects you to when the transaction is complete
  4. The form key in context renders a PayPal button. Right now we're using form.sandbox() to initiate the test process. Change this to form.render() to send the user to the real PayPal site
  5. You can add a "custom" key and value to the paypal_dict if you want to add a custom field later on
  6. If you're doing this test multiple times, you might run into an error message given by Paypal that says something like: This invoice has already been paid. For more information, please contact the merchant. To get around this, just change the invoice value everytime you try to make a purchase.

6. Now we fix the SITE_NAME

Sign up for an account at www.dyndns.com
  1. Add a new hostname. For service type, choose Host with IP address. Next, click on the link to populate the IP Address
  2. You should have something that looks like this:
  3. Add the Hostname to your settings.py file as SITE_NAME like so
  1. # settings.py
  2. ...
  3. SITE_NAME = 'http://nai.dyndns-free.com'
  4. ...

7. Run Django development server on your local IP

  1. For this to work, you need to configure your router to open port 80. The normal process is roughly like this:
    1. Goto your router IP e.g. 192.168.1.1
    2. Look for firewall or port forwarding
    3. Create an exception called 'django' or whatever with port 80 open
    4. Add this exception to the list of allowed applications that is tied to your computer
    5. Save
  2. Now, run Django's development server using sudo /etc/init.d/apache2 stop; sudo ./manage.py runserver 192.168.2.102:80
  3. Change 192.168.2.102:80 to your own IP address which you can locate by running ifconfig in bash. Retain port 80
  4. If all goes well, you should be able to open up in your browser the hostname you created at dyndns. In my case, nai.dyndns-free.com/paypal looks like this:


8. What goes on under the hood?

When someone uses this button to buy something PayPal makes a HTTP POST to your "notify_url" which comes as part of the Paypal package. PayPal calls this Instant Payment Notification (IPN). The view paypal.standard.ipn.views.ipn handles IPN processing. We have already set the notify_url in step 4 as: urlpatterns += patterns('',(r'^something/hard/to/guess/', include('paypal.standard.ipn.urls')),)

When the notify_url is called, the ipn view is executed as shown below. You will need to include @csrf_exempt in the view as well

  1. @require_POST
  2. @csrf_exempt
  3. def ipn(request, item_check_callable=None):

  4. """
  5. PayPal IPN endpoint (notify_url).
  6. Used by both PayPal Payments Pro and Payments Standard to confirm transactions.
  7. http://tinyurl.com/d9vu9d

  8. PayPal IPN Simulator:
  9. https://developer.paypal.com/cgi-bin/devscr?cmd=_ipn-link-session
  10. """

  11. flag = None
  12. ipn_obj = None
  13. form = PayPalIPNForm(request.POST)
  14. if form.is_valid():
  15. try:
  16. ipn_obj = form.save(commit=False)
  17. except Exception, e:
  18. flag = "Exception while processing. (%s)" % e
  19. else:
  20. flag = "Invalid form. (%s)" % form.errors

  21. if ipn_obj is None:
  22. ipn_obj = PayPalIPN()

  23. ipn_obj.initialize(request)

  24. if flag is not None:
  25. ipn_obj.set_flag(flag)
  26. else:
  27. # Secrets should only be used over SSL.
  28. if request.is_secure() and 'secret' in request.GET:
  29. ipn_obj.verify_secret(form, request.GET['secret'])
  30. else:
  31. try:
  32. ipn_obj.verify(item_check_callable)
  33. except Exception, e:
  34. flag = "Exception while processing. (%s)" % e
  35. ipn_obj.save()

  36. return HttpResponse("OKAY")


Just to elaborate a bit on the view, this line here ipn_obj.verify(item_check_callable) is the part that will invoke the sending of the signals. The verify() method can be found in paypal/models/standard/models.py which in turn calls the send_signals() method which can be found in paypal/models/standard/ipn/models.py

9. Final Stretch

So now we need to set up something to receive these signals. This can live anywhere in the project. The examples use models, so lets go with that.

  1. # models.py
  2. ...
  3. from paypal.standard.ipn.signals import payment_was_successful

  4. def show_me_the_money(sender, **kwargs):
  5. ipn_obj = sender
  6. # Undertake some action depending upon `ipn_obj`.
  7. if ipn_obj.custom == "Upgrade all users!":
  8. Users.objects.update(paid=True)
  9. print __file__,1, 'This works'
  10. payment_was_successful.connect(show_me_the_money)

  1. If everything works ok when we click the buy now button, console should print the line 'This works'
  2. So, go back to your domain/paypal page. Click on the buy button link, it should re-direct you to the Paypal sandbox page. Log in using the personal account you created in step 2. Mine is naiyun_1311850509_per@od-eon.com
  3. Go through the buying process and if everything works, you should see something like this in your console
  1. [05/Aug/2011 03:06:50] "GET /paypal/ HTTP/1.1" 200 1075
  2. /home/nai/GitProjects/cat/homepage/models.pyc 1 This works
  3. [05/Aug/2011 03:08:02] "POST /something/hard/to/guess/ HTTP/1.0" 200 4


Hope this tutorial has been helpful. If you have any questions, do leave them in the comments and I 'll do my best to answer them. 

UPDATE

Just in case anyone is running into DB related problems, django-paypal uses South to handle it's model creation. So running ./manage.py syncdb will *not* create the Paypal related tables. 


Category: Django


Tagged as: django django-paypal

4 Comments
Page generated in: 1.63s