| | 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]) |