Kaarsemaker.net


query.py
5.85 KB

127 lines

Download

hosturl.py
sqlfixtables.py

Preview

 1 # Copyright (c) 2009 Dennis Kaarsemaker <dennis@kaarsemaker.net>
 2 # All rights reserved.
 3 # 
 4 # Redistribution and use in source and binary forms, with or without modification,
 5 # are permitted provided that the following conditions are met:
 6 # 
 7 #     1. Redistributions of source code must retain the above copyright notice, 
 8 #        this list of conditions and the following disclaimer.
 9 #     
10 #     2. Redistributions in binary form must reproduce the above copyright 
11 #        notice, this list of conditions and the following disclaimer in the
12 #        documentation and/or other materials provided with the distribution.
13 # 
14 #     3. Neither the name of Django nor the names of its contributors may be used
15 #        to endorse or promote products derived from this software without
  1 # Copyright (c) 2009 Dennis Kaarsemaker <dennis@kaarsemaker.net>
  2 # All rights reserved.
  3 # 
  4 # Redistribution and use in source and binary forms, with or without modification,
  5 # are permitted provided that the following conditions are met:
  6 # 
  7 #     1. Redistributions of source code must retain the above copyright notice, 
  8 #        this list of conditions and the following disclaimer.
  9 #     
 10 #     2. Redistributions in binary form must reproduce the above copyright 
 11 #        notice, this list of conditions and the following disclaimer in the
 12 #        documentation and/or other materials provided with the distribution.
 13 # 
 14 #     3. Neither the name of Django nor the names of its contributors may be used
 15 #        to endorse or promote products derived from this software without
 16 #        specific prior written permission.
 17 # 
 18 # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
 19 # ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 20 # WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 21 # DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
 22 # ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 23 # (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 24 # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
 25 # ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 26 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 27 # SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 28 
 29 from django.db.models import Q
 30 from django.core.management import BaseCommand
 31 from django.template import loader, Template, Context
 32 from optparse import make_option
 33 import os.path
 34 import sys
 35 
 36 usage="""The django ORM will be queried with the filters on the commandline. Records
 37 will be separated with newlines, fields with the specified separator 
 38 (the default is a comma). Alternatively, a template can be specified which 
 39 will be passed the result of the query as the 'objects' variable
 40 
 41 Query key/value pairs can be prefixed with a '!' to negate it, internally this uses
 42 a Q object.
 43 
 44 Examples:
 45  - Display name and assettag of all mc01 servers
 46    %prog query name__startswith=mc01 -f name,assettag
 47  - Get a list of name, ip, mac for all servers where the does not contain .82.
 48    %prog query -m Interface !ip_address__contains='.82.' -f server.name,ip_address,mac_address
 49  - Use a template to get the roles, depending on mac address
 50    %prog query interface__mac_address=00:17:A4:8D:E6:BC -t '{{ objects.0.role_set.all|join:"," }}'
 51 
 52 /!\\ Warning /!\\
 53 This script does not do much error checking. If you spell your query wrong, or
 54 do something wrong with templates, you will get a python traceback and not a
 55 nice error message."""
 56 
 57 class Command(BaseCommand):
 58     option_list = BaseCommand.option_list + (
 59         make_option('-a', '--application', dest="application",
 60                     default=os.environ.get("DJANGO_QUERY_DEFAULT_APPLICATION", None),
 61                     help="Use this application", metavar="APP"),
 62         make_option('-m', '--model', dest="model",
 63                     default=os.environ.get("DJANGO_QUERY_DEFAULT_MODEL", None),
 64                     help="Query this model"),
 65         make_option('-f', '--fields', dest="fields", default=None,
 66                     help="Give these fields"),
 67         make_option('-o', '--order', dest="order", default=None,
 68                     help="Order by this field"),
 69         make_option('-s', '--separator', dest="separator", default=",",
 70                     help="Output separator"),
 71         make_option('-t', '--template', dest="template", default='',
 72                     help="Template in django syntax"),
 73         make_option('-T', '--template-file', dest="template_file", default=None,
 74                     help="File containing the template (abs/rel path or loader path)")
 75     )
 76     help = usage
 77     args = 'filter [filter ...]'
 78 
 79     def handle(self, *args, **options):
 80         if not options['application']:
 81             print "You must specify which application to use"
 82             sys.exit(1)
 83         if not options['model']:
 84             print "You must specify which model to use"
 85             sys.exit(1)
 86         if not options['fields'] and not options['template'] and not options['template_file']:
 87             print "You must specify a list of fields or a template"
 88             sys.exit(1)
 89 
 90         # Import the model
 91         models = options['application'] + '.models'
 92         __import__(models)
 93         models = sys.modules[models]
 94         model = getattr(models, options['model'])
 95 
 96         # Create queryset
 97         qargs = []
 98         for x in args:
 99             key, val = x.split('=',1)
100             if key.startswith('!') or key.startswith('~'):
101                 qargs.append(~Q(**{key[1:]: val}))
102             else:
103                 qargs.append(Q(**{key: val}))
104         queryset = model.objects.filter(*qargs)
105         if options['order']:
106             queryset = queryset.order_by(options['order'])
107 
108         # Generate output
109         if options['template'] or options['template_file']:
110             template = Template(options['template'])
111             tf = options['template_file']
112             if tf == '-':
113                 template = Template(sys.stdin.read())
114             elif tf and os.path.exists(tf):
115                 template = Template(open(tf).read())
116             elif tf:
117                 template = loader.get_template(tf)
118             print template.render(Context({'objects': queryset}))
119         else:
120             def getattr_r(obj, attr):
121                 if '.' in attr:
122                     me, next = attr.split('.',1)
123                     return getattr_r(getattr(obj, me), next)
124                 return getattr(obj, attr)
125             fields = options['fields'].split(',')
126             for record in queryset:
127                 print options['separator'].join([unicode(getattr_r(record, x)) for x in fields])

Show all