| 1 | from django.db.models import Q |
| 2 | from django.core.management import BaseCommand |
| 3 | from django.template import loader, Template, Context |
| 4 | from optparse import make_option |
| 5 | import os.path |
| 6 | import sys |
| 7 | |
| 8 | usage="""The django ORM will be queried with the filters on the commandline. Records |
| 9 | will be separated with newlines, fields with the specified separator |
| 10 | (the default is a comma). Alternatively, a template can be specified which |
| 11 | will be passed the result of the query as the 'objects' variable |
| 12 | |
| 13 | Query key/value pairs can be prefixed with a '!' to negate it, internally this uses |
| 14 | a Q object. |
| 15 | |
| 16 | Examples: |
| 17 | - Display name and assettag of all mc01 servers |
| 18 | %prog query name__startswith=mc01 -f name,assettag |
| 19 | - Get a list of name, ip, mac for all servers where the does not contain .82. |
| 20 | %prog query -m Interface !ip_address__contains='.82.' -f server.name,ip_address,mac_address |
| 21 | - Use a template to get the roles, depending on mac address |
| 22 | %prog query interface__mac_address=00:17:A4:8D:E6:BC -t '{{ objects.0.role_set.all|join:"," }}' |
| 23 | |
| 24 | /!\\ Warning /!\\ |
| 25 | This script does not do much error checking. If you spell your query wrong, or |
| 26 | do something wrong with templates, you will get a python traceback and not a |
| 27 | nice error message.""" |
| 28 | |
| 29 | class Command(BaseCommand): |
| 30 | option_list = BaseCommand.option_list + ( |
| 31 | make_option('-a', '--application', dest="application", |
| 32 | default=os.environ.get("DJANGO_QUERY_DEFAULT_APPLICATION", None), |
| 33 | help="Use this application", metavar="APP"), |
| 34 | make_option('-m', '--model', dest="model", |
| 35 | default=os.environ.get("DJANGO_QUERY_DEFAULT_MODEL", None), |
| 36 | help="Query this model"), |
| 37 | make_option('-f', '--fields', dest="fields", default=None, |
| 38 | help="Give these fields"), |
| 39 | make_option('-o', '--order', dest="order", default=None, |
| 40 | help="Order by this field"), |
| 41 | make_option('-s', '--separator', dest="separator", default=",", |
| 42 | help="Output separator"), |
| 43 | make_option('-t', '--template', dest="template", default='', |
| 44 | help="Template in django syntax"), |
| 45 | make_option('-T', '--template-file', dest="template_file", default=None, |
| 46 | help="File containing the template (abs/rel path or loader path)") |
| 47 | ) |
| 48 | help = usage |
| 49 | args = 'filter [filter ...]' |
| 50 | |
| 51 | def handle(self, *args, **options): |
| 52 | if not options['application']: |
| 53 | print "You must specify which application to use" |
| 54 | sys.exit(1) |
| 55 | if not options['model']: |
| 56 | print "You must specify which model to use" |
| 57 | sys.exit(1) |
| 58 | if not options['fields'] and not options['template'] and not options['template_file']: |
| 59 | print "You must specify a list of fields or a template" |
| 60 | sys.exit(1) |
| 61 | |
| 62 | # Import the model |
| 63 | models = options['application'] + '.models' |
| 64 | __import__(models) |
| 65 | models = sys.modules[models] |
| 66 | model = getattr(models, options['model']) |
| 67 | |
| 68 | # Create queryset |
| 69 | qargs = [] |
| 70 | for x in args: |
| 71 | key, val = x.split('=',1) |
| 72 | if key.startswith('!') or key.startswith('~'): |
| 73 | qargs.append(~Q(**{key[1:]: val})) |
| 74 | else: |
| 75 | qargs.append(Q(**{key: val})) |
| 76 | queryset = model.objects.filter(*qargs) |
| 77 | if options['order']: |
| 78 | queryset = queryset.order_by(options['order']) |
| 79 | |
| 80 | # Generate output |
| 81 | if options['template'] or options['template_file']: |
| 82 | template = Template(options['template']) |
| 83 | tf = options['template_file'] |
| 84 | if tf == '-': |
| 85 | template = Template(sys.stdin.read()) |
| 86 | elif tf and os.path.exists(tf): |
| 87 | template = Template(open(tf).read()) |
| 88 | elif tf: |
| 89 | template = loader.get_template(tf) |
| 90 | print template.render(Context({'objects': queryset})) |
| 91 | else: |
| 92 | def getattr_r(obj, attr): |
| 93 | if '.' in attr: |
| 94 | me, next = attr.split('.',1) |
| 95 | return getattr_r(getattr(obj, me), next) |
| 96 | return getattr(obj, attr) |
| 97 | fields = options['fields'].split(',') |
| 98 | for record in queryset: |
| 99 | print options['separator'].join([unicode(getattr_r(record, x)) for x in fields]) |