Monday, February 1, 2010

Remaining character count in django admin

- Link

Want to display the remaining characters on a text field in admin? (based off of maxlength or an override)

#have your ModelAdmin inherit this to use
class CounterAdmin(admin.ModelAdmin):
    counted_fields = ()
    
    #really for textareas
    max_lengths = {'abstract': 400,}
    
    class Media:
        js = ('js/jquery.js',
              'js/jquery.charCount.js',)
        
    def formfield_for_dbfield(self, db_field, **kwargs):
        field = super(CounterAdmin, self).formfield_for_dbfield(db_field, **kwargs)
        print db_field.name
        print self.counted_fields
        if db_field.name in self.counted_fields:
            try:
                len = self.max_lengths[db_field.name]
                field.widget.attrs['maxlength'] = len
            except: pass
            field.widget.attrs['class'] = 'counted ' + field.widget.attrs.get('class','')
        return field


"""
jquery,charCount.js

/*
 *  Character Count Plugin - jQuery plugin
 *  Dynamic character count for text areas and input fields
 * written by Alen Grakalic 
 * http://cssglobe.com/post/7161/jquery-plugin-simplest-twitterlike-dynamic-character-count-for-textareas
 *
 * Copyright (c) 2009 Alen Grakalic (http://cssglobe.com)
 * Dual licensed under the MIT (MIT-LICENSE.txt)
 * and GPL (GPL-LICENSE.txt) licenses.
 *
 * Built for jQuery library
 * http://jquery.com
 *
 */

/*
 * Modified 2010 Tim Broder for django-admin-charcount
 * http://gpowered.net
 */
 
(function($) {
 $.fn.charCount = function(options){
  // default configuration properties
  var defaults = { 
   allowed: 140,  
   warning: 20,
   css: 'help',
   counterElement: 'p',
   cssWarning: 'warning',
   cssExceeded: 'exceeded',
   counterText: ''
  }; 
   
  var options = $.extend(defaults, options); 
  
  function calculate(obj){
   var count = $(obj).val().length;
   var available = options.allowed - count;
   if(available <= options.warning && available >= 0){
    $(obj).next().addClass(options.cssWarning);
   } else {
    $(obj).next().removeClass(options.cssWarning);
   }
   if(available < 0){
    $(obj).next().addClass(options.cssExceeded);
   } else {
    $(obj).next().removeClass(options.cssExceeded);
   }
   $(obj).next().html(options.counterText + available);
  };

  this.each(function() {     

   $(this).after('<'+ options.counterElement +' class="' + options.css + '">'+ options.counterText +'');
   calculate(this);
   $(this).keyup(function(){calculate(this); });
   $(this).change(function(){calculate(this)});
  });
   
 };

})(jQuery);

/*function init_counters(selector, len){
 $(selector).each(function() {
  //console.log($(this).attr('maxlength'));
  if(len==null){
   len = $(this).attr('maxlength');
  }
  $(this).charCount({
   counterText: 'Characters Remaining: ',
   allowed: len,
  });
 });
}*/

$(document).ready(function(){
 $(".counted").each(function(){
  console.log($(this));
  len = $(this).attr('maxlength');
  $(this).charCount({
   counterText: 'Characters Remaining: ',
   allowed: len,
  });
 });
 //init_counters("input[maxlength]", 80);
 //init_counters("textarea[maxlength]");
 //init_counters("#id_abstract", 400);
});

/*
 * 
*/
"""

Thursday, January 7, 2010

Override QuerySet.delete() (one way of preventing cascading deletes)

- Link

We needed to override the default QuerySet delete function to deal with a client problem that we were facing

Yes This is monkey-patching, and probably bad practice but if anyone needs to conditionally override the cascading delete that django does at the application level from a queryset, this is how to do it

from django.db.models.query import QuerySet

#save original delete method
orrigdelete = QuerySet.delete
def showdelete(self):
    #add on to delete method
    for test in self:
        if isinstance(test, YourObject):
            raise Exception('someone tried to delete your object')
            return  
        else:
            break   
    #call original delete
    return orrigdelete(self)

#set the queryset delete as our new method
QuerySet.delete = showdelete

Tuesday, January 5, 2010

A quick way to display your delicious links by tag

quick, dirty, and slow with lots of tags

<html>
<body>
<script type="text/javascript"> 
function goforit (posts) {
 for ( var tagname in posts ) {
  document.writeln('<scr'+'ipt type="text/javascript" src="http://feeds.delicious.com/v2/js/NYCEndurance/' + tagname + '?title=' + tagname + '&icon=s&count=100&sort=alpha&tags"></scr'+'ipt>'); 
 }
}
</script>
<script type="text/javascript" src="http://feeds.delicious.com/v2/json/tags/NYCEndurance?callback=goforit"></script>
</body>
</html>

Thursday, December 24, 2009

Jack Vs Spider and Happy Holidays

- Link

Happy Holidays and thanks everyone for a great year.

Check out my company's holiday E-card here

Our VP of Security takes on an 8 legged intruder

Tuesday, December 22, 2009

Django gets Multi-DB

- Link

For his Google Summer of Code project Alex Gaynor added Multiple Database support to Django, which just got pushed to Trunk.

The Documentation is available here

Some of the offhand benifits I can see:

  1. Multiple of databases.  Got some legacy systems you don't want to migrate but have access to the data? no problem
  2. Have a read and a write database.  Want one of your databases to speed up by configuring faster indexes and disabling writes? done.
  3. Multiple TYPES of databases.  This is the one I'm most excited about.  This is going to enable people to use some of the NoSQL databases (MongoDB, CouchDB, see here for a more complete list)

    For a great application of MongoDB on a news site see Business Insider

Share Google Reader folders with friends

A quick rundown on how to share whole folders with friends so they can see what you are reading, there might be an easier way to do this but this was the quickest I found

  1. Click explore
  2. click "View all recommendations"

  3. click Browse
  4. click Create a bundle






  5. Fill out the form and drag folders or individual feeds.





  6. After this is done you can email the bundle to your friends

Thursday, December 17, 2009

Sneak some advanced logic into a Django template

I was adding on an app to a Django project at work where I was overriding an existing template but did not have access to the view that called that template. I was left in a scenario where I had the variables that the view was originally set up with, but non of the new models that I had added.

In a filter you can do whatever logic you want, and then pass information back to the view. Please keep in mind, this is probably a horrible practice, but it does have its uses. In this specific scenario I needed to query the new models without modifying the existing view, solution: add a filter and do the querying there.

This is the filter that I used to do the querying:

from django import template
from stager.jira.models import JiraProject, ProjectLink
from stager.staging.models import *

register = template.Library()

def has_jira(value, arg):
    client = Client.objects.get(path=value)
    project = client.projects.get(path=arg)
    try:
        jiras = ProjectLink.objects.get(ClientProject=project).JiraProject.exclude(filter_id='')
        return True
    except:
        return False
register.filter('has_jira', has_jira)

Then, in my template:
{% load has_jira %}
{% if client.path|has_jira:project.path %}
     
  • Jira
  • {% endif %}

    A more general example if this would be to work around the annoyance of not being able to have multiple tests in an if statement in a template: You can't do {% if this and that %}

    A solution would be:
    def if_and(value, arg):
        if value and arg:
            return True
        else:
            return False
        
    def if_or(value, arg):
        if value or arg:
            return True
        else:
            return False
    

     {% if True|if_and:False %}
     show
     {% else %}
     don't show
     {% endif %}
    

    Let me know your thoughts, pros/cons of this method.

    Ai's stager project is open source and can be found at github