LiveReload. Best $12 Bucks Spent Ever.

nuff said

nuff said

I’ve been working on angular.js using yeoman for the last couple of weeks. One thing I really liked about it is the live reload functionality. Essentially, any changes made in the DOM or CSS gets updated immediately. It’s a really really powerful feature for web developers. It’s also one of those features you never knew you needed until you’ve used it.

I got so addicted to it, I went hunting around for an app that is able to do the same for my django projects. Enter LiveReload which is quite possibly the best invention since sliced bread. The setup is super trivial. Add my django project to the folder list, install a chrome extension and I’m done. Now, all changes in the DOM or CSS gets updated immediately when I’m working on Django. Best SGD $12 bucks spent on an app ever.

Some Lessons Learnt from Messing with Django and AngularJS

django-logo-negative

square

  1. Key take-away: If you’re thinking of sneaking angular.js as you would any other js file into your ‘static’ folder, you gonna have a bad time. It starts to get really messy when you try to mix and match angular’s url routing mechanism vs. django’s url. The same applies to the templates. I imagine this messiness will always be present if you try to mix a client-side MVC framework with a server-side one.  The best way is to separate angular out from your django project entirely and use the services to communicate with your django application. This means you will need something like django-tastypie or django-rest-framework setup on a separate app. The rest of the points are really more learnings about angular so read on if you’re interested.
  2. You will be confused between the differences of a service and a factory. I’m still confused.
  3. Angular kinda requires you to have a solid understanding of Javascript to be fully effective. You could get away with knowing less Python and still be effective in Django in my opinion.
  4. You can only use one ng-view per view
  5. If your controllers seem to be firing twice, it’s probably because you defined an ng-controller in your html as well as in your route.
  6. If you skipped reading the conceptual overview, it’s a critical document that will help you wrap your head around the angular concepts so don’t.
  7. Angular disables form submissions without an action attribute. If you’re using django-crispy-forms (there’s not reason not to. it’s an excellent form library) to render your form, simply add self.helper.form_action = ‘#’ to fix this.
  8. If you’re wondering why your url end point is getting called twice, its probably because Django is redirecting the url with a trailing slash to a url that does. To fix this, simply escape the backslash like: /custom_api/get_nearest_hotels/:eventId\\/. There is a gotcha to this. It only works in Chrome and Safari. If you’re calling the endpoints via a service factory, Firefox will decide that it’s a good idea to remove the trailing slash from the URL and encode the backslash that was escaping the forward slash to %5C. The result is to use $http. See related angular issue.
  9. Loading templates are a bit of a hassle. There are a few ways to solve this. This guy’s method.
  10. Tricks and tips
    1. http://gpiot.com/angularjs-useful-tips-to-get-started/
    2. http://deansofer.com/posts/view/14/AngularJs-Tips-and-Tricks-UPDATED
  11. Angular and SEO
  12. Get the correct angular folder structure from angular seed
  13. Check out angular-ui
  14. AngularJS in 60 mins
  15. If you see your page flash with angular template tags and then reload again to show the actual content, you need to apply ng-cloak.
  16. $scope.$watch will fire on page load to initialize the watcher.
  17. Always have a ‘.’ in your models. e.g ng-model=user.name and not ng-model=username
  18. $scope.$apply is essentially the way you get the rest of your javascript to sync with angular’s javascript.
  19. Controllers should not contain presentation logic — that belongs in Directives. Controllers strictly should be used for business logic.
  20. If you’re using a moment.js (awesome library) for datetime manipulation, don’t forget that the angular format filters only operate on javascript date objects. So you’ll have to append a .toDate() to cast your moment object into a javascript date.

13 SEO Tips for Django

This is mostly an on-site specific guide
  1. Use the redirects app to manage url changes Django documentation
  2. Use post save signals to handle slug/url changes in your models Link
  3. Use sitemap The sitemap framework
  4. Use slugfield Model field reference
  5. Use cached template loaders to reduce page load times The Django template language: For Python programmers
  6. Use a css/js compressor to reduce page load times django_compressor
  7. Use django-robots to manage your robots file django-robots
  8. If you’re rolling an e-commerce site, don’t reinvent the wheel, just go with The Best Django CMS. It’s the best code and seo friendly cms framework for django
  9. Manage object level meta data with django-seo
  10. Not django specific but submit your site to google webmasters Webmasters – Google. For bing: Bing – Webmaster Tools
  11. Not django specific again but load your page using Make the Web Faster and make all the recommended changes
  12. Crawl your site content to find broken links using Xenu or Integrity for Mac
  13. To generate image sitemaps, use Django Image Sitemaps

Other Stuff

Django Create Session Variables in Unit Test

Came across this snippet some time ago but I can’t remember the source. I’ve since used it quite extensively.

def stuff_session(client, dictionary):
    from django.conf import settings
    from django.utils.importlib import import_module
    engine = import_module(settings.SESSION_ENGINE)
    store = engine.SessionStore()
    store.save()
    client.cookies[settings.SESSION_COOKIE_NAME] = store.session_key
    session = client.session
    session.update(dictionary)
    session.save()

To use simply

stuff_session(self.client, {'customer_session_id': '0ABAA842-7E77-2591-3B02-162716195AD6'})

Code Snippet for Django Unit Test for AJAX Responses

View

def api_get_destinations(request):
    if request.is_ajax():
        searchText = request.GET.get('searchText', '')
        maxResults = request.GET.get('maxResults', '10')
        n = int(maxResults)
        cities = ParentRegionList.city\
                .filter(region_name_long__icontains=searchText, subclass=None)\
                .values_list('pk', 'region_name_long')[:n]

        results = []
        for city in cities:
            city_dict = {'id': city[0],
                    'label': city[1],
                    'value': city[1]}
            results.append(city_dict)
        if not results:
            results.append({
                'id': -1,
                'label': 'No Results Found',
                'value': 'No Results Found'
                })
        data = simplejson.dumps(results)
    else:
        data = 'fail'
    mimetype = 'application/json'
    return HttpResponse(data, mimetype)

Test

class TestAPIResponses(TestCase):
    def setUp(self):
        self.parent_region_list = ParentRegionListFactory()

    def test_get_destinations(self):
        kwargs = {'HTTP_X_REQUESTED_WITH': 'XMLHttpRequest'}
        url = reverse('api_get_destinations')

        get_data = {'searchText': 'Singap',}

        response = self.client.get(url, get_data, **kwargs)
        json_string = response.content
        data = json.loads(json_string)
        self.assertEqual(data[0]['id'], self.parent_region_list.pk)
        self.assertEqual(data[0]['value'],
                self.parent_region_list.region_name_long)
        self.assertEqual(data[0]['label'],
                self.parent_region_list.region_name_long)

Installing Django PostGIS Postgres on OS X: Version Hell

Ran into a day and half’s worth of trouble while trying to install postgis and I still haven’t resolved it yet. Some things to note so far:

  1. If you install postgis via brew, `brew install postgis`, it will also automagically install postgresql9.2.1 for you. So if you have a previous version of postgresql installed, you will now have 2!
  2. Django1.4 doesn’t play will with postgis2.0 for now. So, you have to install postgis1.5 (https://code.djangoproject.com/ticket/16455)
  3. postgis1.5 doesn’t play well with postgresql9.2.1, so you to install postgresql9.1.x (http://trac.osgeo.org/postgis/wiki/UsersWikiPostgreSQLPostGIS)
  4. So, the working versions to use together would be Django1.4.x with postgis1.5 and postgres9.1.x
  5. To NOT get the latests version of postgres from brew, follow this gist (https://gist.github.com/3188632) to install postgres9 which will link you to postgres9.08
  6. The crazy thing is trying to `brew install postgis15` gives me the following error [1]
  7. Client version of psql is different from the server version of postgres. If you run psql in terminal and you see something like `psql (9.2.1)`, it means the client and server versions are the same. If you see something like `psql (Client (9.2.1) Server (9.1.2))` (can’t remember the exact phrasing but the first number would be the client, the second number would be the server itself), it means the client and server versions are different.
  8. If you have a previous version of postgres, you would have had to run `initdb /usr/local/var/postgres`. You gotta move/delete this guy if you’re installing a new version of postgres and rerun the initidb command!
  9. `brew doctor` is your friend

[1]

Error in Question:

nai@nyc ~ $ brew install postgis15
==> Downloading http://postgis.refractions.net/download/postgis-1.5.3.tar.gz
Already downloaded: /Users/nai/Library/Caches/Homebrew/postgis15-1.5.3.tar.gz
==> ./configure –with-projdir=/usr/local –with-pgconfig=/usr/local/Cellar/postgresql/9.2.1/bin/pg_config
==> make
num2_tuples = reltup->reltuples;
^
4 errors generated.
make[1]: *** [lwgeom_estimate.o] Error 1
make: *** [postgis] Error 2

Other Useful Links

http://blog.dyve.net/upgrade-your-mac-to-postgres-9-using-homebrew

http://stackoverflow.com/questions/12547872/trouble-installing-postgis-postgresqldjangomac-os-x-10-7

http://gibuloto.com/blog/install-postgresql-in-mac-osx-lion/

https://gist.github.com/3188632

http://stackoverflow.com/questions/3987683/homebrew-install-specific-version-of-formula

A Naive Code Counter for your Django Project

On a whim, I wrote a short management command that counted the lines of code in only the ‘core’ files in my django project and also code count for my unit test which are mostly written to test these ‘core’ files. This excludes html, css and javascript.

from django.core.management.base import BaseCommand
from django.conf import settings

import os

class Command(BaseCommand):
    """
    This counts the code for each app in the project and displays the 
    lines of code of unit test written.
    """
    help = 'Display Project Code Count and Unit Test Code count'

    def handle(self, *args, **options):
        file_types = ['views.py', 'forms.py', 'models.py', 'utils.py', 'tests.py']
        counter = 0
        unit_test_counter = 0
        for app in settings.APPS:
            for file_type in file_types:
                file_name = app + '/' + file_type
                if os.path.exists(file_name):
                    with open(file_name) as f:
                        for row in f:
                            counter += 1
                            if file_type == 'tests.py':
                                unit_test_counter += 1
        print 'Total lines of code in bbox only apps: %s' % counter
        print 'Total lines of code in bbox excluding tests: %s' % (counter - unit_test_counter)
        print 'Total lines of code in bbox tests: %s' % unit_test_counter
        print 'For every 1 line of code written, %s lines of test code is written' \
                % (float(counter-unit_test_counter) / float(unit_test_counter))

Total lines of code in project specific apps: 20172
Total lines of code in excluding tests: 13145
Total lines of code in tests: 7027
For every 1 line of code written, 1.87064181016 lines of test code is written

Source: https://gist.github.com/3566434