Tuesday, February 23, 2016

w7d2 - Progress, step by bloody step by custom django template tag

It's a weird feeling to realize that I'm still taking in vast amounts of information, while feeling like I'm spinning my wheels, so to speak.  I'm at the point where I need to know so much that each little thing I add to my stock of knowledge disappears almost without a trace.

The lecture today was on making our own APIs and returning information from an external query as json or xml.  The exciting part was learning how to implement this within my own project.

For example: I have a "location" page that asks users to determine the location they wish to search.  For some reason, cats are not yet stored as destinations in google maps, so I need to query the catfinder database to find all the cats in a given area.  To do this I needed:

  • to work with decimal data types since geolocation data is best handled as decimal(10,6) data type (i.e. up to 10 total characters, with no more than 6 places to the right of the decimal.  Not ridiculously difficult, but I spent some time playing with mathematical operations to see that I wouldn't be fouling anything.
  • work out how to query sql for distance from a point.  The general formula I found is 

SELECT id, ( 3959 * acos( cos( radians(37) ) * cos( radians( lat ) ) * cos( radians( lng ) - radians(-122) ) + sin( radians(37) ) * sin( radians( lat ) ) ) ) AS distance FROM markers HAVING distance < 25 ORDER BY distance LIMIT 0 , 20;
although that's for a distance of a mile from a point, taking into account the curve of the Earth's surface.  My distances need to be pretty close (since most cats don't wander far), so I'm going to ignore curvature.

My solution was to define a search "radius" as 0.010000 decimal degrees.  This translates to about 1 km (courtesy of http://www.csgnetwork.com/gpsdistcalc.html) and to return all cat sightings that are within 0.010000 degrees of the search point.


  • (back to bullets)
  • Next problem: My data for "local cats" page (showing proximal cats) looks like this 
  • to populate that page, I need to organize by "cat".  One cat can have many sightings (cat_id is a foreign key in sightings)
  • Each sighting has several photos (in a separate cat_photos table with a foreign key from each photo to a sighting)
  • Each sighting has a user who submitted the info, and who may wish to edit old submissions
I worked out the query structure in for use with django (a bunch of filter requests) and returned the data as dictionary. 

Dictionaries are awesome!  So easy to use in python!

Not in django templates, however.  Or at least not as we were taught django templates.  You can pass a dictionary into a template as part of context, but you can't readily access the values using standard dictionary __get_item__. (see here for relevant Stack Overflow discussion).  

I'll spare you the misery I experienced as I tried everything I could think of, before getting the right search results to figure out what was going on.  

Solution (I think) is to write a custom tag.  I spent all evening looking reading and rereading sections, but I got one that works for dictionary lookup!  It's too late now to fully test it, and I don't have my locations page working like I want yet...but it works in basic form.  
tag:

@register.filter(name='lookup',is_safe=True)
def lookup(dict,key):
    return dict[key]

implementation:

{{ <dict>| lookup:<key> }}


  • Also (this deserves it's own bullet): I was able to assign a variable using the templating language {% with info| lookup:"id" as x %}
                    <p>cat name: {{ x.name }}</p>
                    {% endwith %}
  • woo hoo!
So, now that I look back on it, that's a huge amount of ground covered in one day.  I don't 100% understand everything (decorators are still beyond my own efforts), but I was able to read and implement the documentation.  I worked with a new data type (decimal).  I figured out my own (hacktastic!) geo-distance formula.  I avoided a tantrum at the 100th error message.

So.  Win.

No comments:

Post a Comment