Statistics
| Branch: | Tag: | Revision:

root / snf-django-lib / snf_django / management / commands / __init__.py @ 07661d4d

History | View | Annotate | Download (14.4 kB)

1 fa532396 Christos Stavrakakis
# Copyright 2012-2014 GRNET S.A. All rights reserved.
2 7cfc0cef Christos Stavrakakis
#
3 7cfc0cef Christos Stavrakakis
# Redistribution and use in source and binary forms, with or
4 7cfc0cef Christos Stavrakakis
# without modification, are permitted provided that the following
5 7cfc0cef Christos Stavrakakis
# conditions are met:
6 7cfc0cef Christos Stavrakakis
#
7 7cfc0cef Christos Stavrakakis
#   1. Redistributions of source code must retain the above
8 7cfc0cef Christos Stavrakakis
#      copyright notice, this list of conditions and the following
9 7cfc0cef Christos Stavrakakis
#      disclaimer.
10 7cfc0cef Christos Stavrakakis
#
11 7cfc0cef Christos Stavrakakis
#   2. Redistributions in binary form must reproduce the above
12 7cfc0cef Christos Stavrakakis
#      copyright notice, this list of conditions and the following
13 7cfc0cef Christos Stavrakakis
#      disclaimer in the documentation and/or other materials
14 7cfc0cef Christos Stavrakakis
#      provided with the distribution.
15 7cfc0cef Christos Stavrakakis
#
16 7cfc0cef Christos Stavrakakis
# THIS SOFTWARE IS PROVIDED BY GRNET S.A. ``AS IS'' AND ANY EXPRESS
17 7cfc0cef Christos Stavrakakis
# OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 7cfc0cef Christos Stavrakakis
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19 7cfc0cef Christos Stavrakakis
# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GRNET S.A OR
20 7cfc0cef Christos Stavrakakis
# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21 7cfc0cef Christos Stavrakakis
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22 7cfc0cef Christos Stavrakakis
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
23 7cfc0cef Christos Stavrakakis
# USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
24 7cfc0cef Christos Stavrakakis
# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 7cfc0cef Christos Stavrakakis
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
26 7cfc0cef Christos Stavrakakis
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27 7cfc0cef Christos Stavrakakis
# POSSIBILITY OF SUCH DAMAGE.
28 7cfc0cef Christos Stavrakakis
#
29 7cfc0cef Christos Stavrakakis
# The views and conclusions contained in the software and
30 7cfc0cef Christos Stavrakakis
# documentation are those of the authors and should not be
31 7cfc0cef Christos Stavrakakis
# interpreted as representing official policies, either expressed
32 7cfc0cef Christos Stavrakakis
# or implied, of GRNET S.A.
33 7cfc0cef Christos Stavrakakis
34 fa532396 Christos Stavrakakis
from optparse import (make_option, OptionParser, OptionGroup,
35 fa532396 Christos Stavrakakis
                      TitledHelpFormatter)
36 7cfc0cef Christos Stavrakakis
37 7cfc0cef Christos Stavrakakis
from django.core.management.base import BaseCommand, CommandError
38 7cfc0cef Christos Stavrakakis
from django.core.exceptions import FieldError
39 7cfc0cef Christos Stavrakakis
40 7cfc0cef Christos Stavrakakis
from snf_django.management import utils
41 7cfc0cef Christos Stavrakakis
from snf_django.lib.astakos import UserCache
42 7cfc0cef Christos Stavrakakis
43 c406d7d9 Dionysis Grigoropoulos
import distutils
44 c406d7d9 Dionysis Grigoropoulos
45 4845dfaa Christos Stavrakakis
USER_EMAIL_FIELD = "user.email"
46 4845dfaa Christos Stavrakakis
47 7cfc0cef Christos Stavrakakis
48 fa532396 Christos Stavrakakis
class SynnefoCommandFormatter(TitledHelpFormatter):
49 fa532396 Christos Stavrakakis
    def format_heading(self, heading):
50 fa532396 Christos Stavrakakis
        if heading == "Options":
51 fa532396 Christos Stavrakakis
            return ""
52 fa532396 Christos Stavrakakis
        return "%s\n%s\n" % (heading, "=-"[self.level] * len(heading))
53 fa532396 Christos Stavrakakis
54 fa532396 Christos Stavrakakis
55 7cfc0cef Christos Stavrakakis
class SynnefoCommand(BaseCommand):
56 7cfc0cef Christos Stavrakakis
    option_list = BaseCommand.option_list + (
57 7cfc0cef Christos Stavrakakis
        make_option(
58 7cfc0cef Christos Stavrakakis
            "--output-format",
59 7cfc0cef Christos Stavrakakis
            dest="output_format",
60 7cfc0cef Christos Stavrakakis
            metavar="[pretty, csv, json]",
61 7cfc0cef Christos Stavrakakis
            default="pretty",
62 7cfc0cef Christos Stavrakakis
            choices=["pretty", "csv", "json"],
63 85ddc6a3 Christos Stavrakakis
            help="Select the output format: pretty [the default], json, "
64 85ddc6a3 Christos Stavrakakis
                 "csv [comma-separated output]"),
65 7cfc0cef Christos Stavrakakis
    )
66 7cfc0cef Christos Stavrakakis
67 fa532396 Christos Stavrakakis
    def create_parser(self, prog_name, subcommand):
68 fa532396 Christos Stavrakakis
        parser = OptionParser(prog=prog_name, add_help_option=False,
69 fa532396 Christos Stavrakakis
                              formatter=SynnefoCommandFormatter())
70 fa532396 Christos Stavrakakis
71 fa532396 Christos Stavrakakis
        parser.set_usage(self.usage(subcommand))
72 fa532396 Christos Stavrakakis
        parser.version = self.get_version()
73 fa532396 Christos Stavrakakis
74 fa532396 Christos Stavrakakis
        # Handle Django's and common options
75 fa532396 Christos Stavrakakis
        common_options = OptionGroup(parser, "Common Options")
76 fa532396 Christos Stavrakakis
        common_options.add_option("-h", "--help", action="help",
77 fa532396 Christos Stavrakakis
                                  help="show this help message and exit")
78 fa532396 Christos Stavrakakis
79 fa532396 Christos Stavrakakis
        common_options.add_option("--version", action="version",
80 fa532396 Christos Stavrakakis
                                  help="show program's version number and"
81 fa532396 Christos Stavrakakis
                                       "  exit")
82 fa532396 Christos Stavrakakis
        [common_options.add_option(o) for o in self.option_list]
83 fa532396 Christos Stavrakakis
        if common_options.option_list:
84 fa532396 Christos Stavrakakis
            parser.add_option_group(common_options)
85 fa532396 Christos Stavrakakis
86 fa532396 Christos Stavrakakis
        # Handle command specific options
87 fa532396 Christos Stavrakakis
        command_options = OptionGroup(parser, "Command Specific Options")
88 fa532396 Christos Stavrakakis
        [command_options.add_option(o)
89 fa532396 Christos Stavrakakis
         for o in getattr(self, "command_option_list", ())]
90 fa532396 Christos Stavrakakis
        if command_options.option_list:
91 fa532396 Christos Stavrakakis
            parser.add_option_group(command_options)
92 fa532396 Christos Stavrakakis
93 fa532396 Christos Stavrakakis
        return parser
94 fa532396 Christos Stavrakakis
95 07661d4d Christos Stavrakakis
    def pprint_table(self, *args, **kwargs):
96 07661d4d Christos Stavrakakis
        utils.pprint_table(self.stdout, *args, **kwargs)
97 07661d4d Christos Stavrakakis
98 7cfc0cef Christos Stavrakakis
99 85ddc6a3 Christos Stavrakakis
class ListCommand(SynnefoCommand):
100 7cfc0cef Christos Stavrakakis
    """Generic *-list management command.
101 7cfc0cef Christos Stavrakakis

102 7cfc0cef Christos Stavrakakis
    Management command to handle common tasks when implementing a -list
103 7cfc0cef Christos Stavrakakis
    management command. This class handles the following tasks:
104 7cfc0cef Christos Stavrakakis

105 7cfc0cef Christos Stavrakakis
    * Retrieving objects from database.
106 7cfc0cef Christos Stavrakakis

107 7cfc0cef Christos Stavrakakis
    The DB model class is declared in ``object_class`` class attribute. Also,
108 7cfc0cef Christos Stavrakakis
    results can be filter using either the ``filters`` and ``excludes``
109 7cfc0cef Christos Stavrakakis
    attribute or the "--filter-by" option.
110 7cfc0cef Christos Stavrakakis

111 7cfc0cef Christos Stavrakakis
    * Display specific fields of the database objects.
112 7cfc0cef Christos Stavrakakis

113 7cfc0cef Christos Stavrakakis
    List of available fields is defined in the ``FIELDS`` class attribute,
114 7cfc0cef Christos Stavrakakis
    which is a dictionary mapping from field names to tuples containing the
115 7cfc0cef Christos Stavrakakis
    way the field is retrieved and a text help message to display. The first
116 7cfc0cef Christos Stavrakakis
    field of the tuple is either a string containing a chain of attribute
117 7cfc0cef Christos Stavrakakis
    accesses (e.g. "machine.flavor.cpu") either a callable function, taking
118 7cfc0cef Christos Stavrakakis
    as argument the DB object and returning a single value.
119 7cfc0cef Christos Stavrakakis

120 7cfc0cef Christos Stavrakakis
    The fields that will be displayed be default is contained in the ``fields``
121 7cfc0cef Christos Stavrakakis
    class attribute. The user can specify different fields using the "--fields"
122 7cfc0cef Christos Stavrakakis
    option.
123 7cfc0cef Christos Stavrakakis

124 7cfc0cef Christos Stavrakakis
    * Handling of user UUIDs and names.
125 7cfc0cef Christos Stavrakakis

126 7cfc0cef Christos Stavrakakis
    If the ``user_uuid_field`` is declared, then "--user" and "--display-mails"
127 7cfc0cef Christos Stavrakakis
    options will become available. The first one allows filtering via either
128 7cfc0cef Christos Stavrakakis
    a user's UUID or display name. The "--displayname" option will append
129 7cfc0cef Christos Stavrakakis
    the displayname of ther user with "user_uuid_field" to the output.
130 7cfc0cef Christos Stavrakakis

131 7cfc0cef Christos Stavrakakis
    * Pretty printing output to a nice table.
132 7cfc0cef Christos Stavrakakis

133 7cfc0cef Christos Stavrakakis
    """
134 7cfc0cef Christos Stavrakakis
135 7cfc0cef Christos Stavrakakis
    # The following fields must be handled in the ListCommand subclasses!
136 7cfc0cef Christos Stavrakakis
137 7cfc0cef Christos Stavrakakis
    # The django DB model
138 7cfc0cef Christos Stavrakakis
    object_class = None
139 7cfc0cef Christos Stavrakakis
    # The name of the field containg the user ID of the user, if any.
140 7cfc0cef Christos Stavrakakis
    user_uuid_field = None
141 7cfc0cef Christos Stavrakakis
    # The name of the field containg the deleted flag, if any.
142 7cfc0cef Christos Stavrakakis
    deleted_field = None
143 7cfc0cef Christos Stavrakakis
    # Dictionary with all available fields
144 7cfc0cef Christos Stavrakakis
    FIELDS = {}
145 7cfc0cef Christos Stavrakakis
    # List of fields to display by default
146 7cfc0cef Christos Stavrakakis
    fields = []
147 7cfc0cef Christos Stavrakakis
    # Default filters and excludes
148 7cfc0cef Christos Stavrakakis
    filters = {}
149 7cfc0cef Christos Stavrakakis
    excludes = {}
150 7cfc0cef Christos Stavrakakis
    # Order results
151 7cfc0cef Christos Stavrakakis
    order_by = None
152 7cfc0cef Christos Stavrakakis
153 7cfc0cef Christos Stavrakakis
    # Fields used only with user_user_field
154 ef57e622 Ilias Tsitsimpis
    astakos_auth_url = None
155 7cfc0cef Christos Stavrakakis
    astakos_token = None
156 7cfc0cef Christos Stavrakakis
157 2052c40e Christos Stavrakakis
    # Optimize DB queries
158 2052c40e Christos Stavrakakis
    prefetch_related = []
159 2052c40e Christos Stavrakakis
    select_related = []
160 2052c40e Christos Stavrakakis
161 7cfc0cef Christos Stavrakakis
    help = "Generic List Command"
162 85ddc6a3 Christos Stavrakakis
    option_list = SynnefoCommand.option_list + (
163 7cfc0cef Christos Stavrakakis
        make_option(
164 7cfc0cef Christos Stavrakakis
            "-o", "--output",
165 7cfc0cef Christos Stavrakakis
            dest="fields",
166 7cfc0cef Christos Stavrakakis
            help="Comma-separated list of output fields"),
167 7cfc0cef Christos Stavrakakis
        make_option(
168 7cfc0cef Christos Stavrakakis
            "--list-fields",
169 7cfc0cef Christos Stavrakakis
            dest="list_fields",
170 7cfc0cef Christos Stavrakakis
            action="store_true",
171 7cfc0cef Christos Stavrakakis
            default=False,
172 7cfc0cef Christos Stavrakakis
            help="List available output fields"),
173 7cfc0cef Christos Stavrakakis
        make_option(
174 7cfc0cef Christos Stavrakakis
            "--filter-by",
175 7cfc0cef Christos Stavrakakis
            dest="filter_by",
176 7cfc0cef Christos Stavrakakis
            metavar="FILTERS",
177 7cfc0cef Christos Stavrakakis
            help="Filter results. Comma separated list of key `cond` val pairs"
178 7cfc0cef Christos Stavrakakis
                 " that displayed entries must satisfy. e.g."
179 7cfc0cef Christos Stavrakakis
                 " --filter-by \"deleted=False,id>=22\"."),
180 7cfc0cef Christos Stavrakakis
        make_option(
181 7cfc0cef Christos Stavrakakis
            "--list-filters",
182 7cfc0cef Christos Stavrakakis
            dest="list_filters",
183 7cfc0cef Christos Stavrakakis
            action="store_true",
184 7cfc0cef Christos Stavrakakis
            default=False,
185 7cfc0cef Christos Stavrakakis
            help="List available filters"),
186 7cfc0cef Christos Stavrakakis
        make_option(
187 7cfc0cef Christos Stavrakakis
            "--no-headers",
188 7cfc0cef Christos Stavrakakis
            dest="headers",
189 7cfc0cef Christos Stavrakakis
            action="store_false",
190 7cfc0cef Christos Stavrakakis
            default=True,
191 7cfc0cef Christos Stavrakakis
            help="Do not display headers"),
192 7cfc0cef Christos Stavrakakis
    )
193 7cfc0cef Christos Stavrakakis
194 7cfc0cef Christos Stavrakakis
    def __init__(self, *args, **kwargs):
195 7cfc0cef Christos Stavrakakis
        if self.user_uuid_field:
196 ef57e622 Ilias Tsitsimpis
            assert(self.astakos_auth_url), "astakos_auth_url attribute is "\
197 ef57e622 Ilias Tsitsimpis
                                           "needed when user_uuid_field "\
198 ef57e622 Ilias Tsitsimpis
                                           "is declared"
199 7cfc0cef Christos Stavrakakis
            assert(self.astakos_token), "astakos_token attribute is needed"\
200 7cfc0cef Christos Stavrakakis
                                        " when user_uuid_field is declared"
201 7cfc0cef Christos Stavrakakis
            self.option_list += (
202 7cfc0cef Christos Stavrakakis
                make_option(
203 7cfc0cef Christos Stavrakakis
                    "-u", "--user",
204 7cfc0cef Christos Stavrakakis
                    dest="user",
205 7cfc0cef Christos Stavrakakis
                    metavar="USER",
206 7cfc0cef Christos Stavrakakis
                    help="List items only for this user."
207 7cfc0cef Christos Stavrakakis
                         " 'USER' can be either a user UUID or a display"
208 7cfc0cef Christos Stavrakakis
                         " name"),
209 7cfc0cef Christos Stavrakakis
                make_option(
210 7cfc0cef Christos Stavrakakis
                    "--display-mails",
211 7cfc0cef Christos Stavrakakis
                    dest="display_mails",
212 7cfc0cef Christos Stavrakakis
                    action="store_true",
213 7cfc0cef Christos Stavrakakis
                    default=False,
214 7cfc0cef Christos Stavrakakis
                    help="Include the user's email"),
215 7cfc0cef Christos Stavrakakis
            )
216 7cfc0cef Christos Stavrakakis
217 7cfc0cef Christos Stavrakakis
        if self.deleted_field:
218 7cfc0cef Christos Stavrakakis
            self.option_list += (
219 7cfc0cef Christos Stavrakakis
                make_option(
220 7cfc0cef Christos Stavrakakis
                    "-d", "--deleted",
221 7cfc0cef Christos Stavrakakis
                    dest="deleted",
222 7cfc0cef Christos Stavrakakis
                    action="store_true",
223 7cfc0cef Christos Stavrakakis
                    help="Display only deleted items"),
224 7cfc0cef Christos Stavrakakis
            )
225 7cfc0cef Christos Stavrakakis
        super(ListCommand, self).__init__(*args, **kwargs)
226 7cfc0cef Christos Stavrakakis
227 7cfc0cef Christos Stavrakakis
    def handle(self, *args, **options):
228 7cfc0cef Christos Stavrakakis
        if len(args) > 0:
229 7cfc0cef Christos Stavrakakis
            raise CommandError("List commands do not accept any argument")
230 7cfc0cef Christos Stavrakakis
231 7cfc0cef Christos Stavrakakis
        assert(self.object_class), "object_class variable must be declared"
232 7cfc0cef Christos Stavrakakis
233 4845dfaa Christos Stavrakakis
        # If an user field is declared, include the USER_EMAIL_FIELD in the
234 4845dfaa Christos Stavrakakis
        # available fields
235 4845dfaa Christos Stavrakakis
        if self.user_uuid_field is not None:
236 4845dfaa Christos Stavrakakis
            self.FIELDS[USER_EMAIL_FIELD] =\
237 4845dfaa Christos Stavrakakis
                ("_user_email", "The email of the owner")
238 4845dfaa Christos Stavrakakis
239 7cfc0cef Christos Stavrakakis
        if options["list_fields"]:
240 7cfc0cef Christos Stavrakakis
            self.display_fields()
241 7cfc0cef Christos Stavrakakis
            return
242 7cfc0cef Christos Stavrakakis
243 7cfc0cef Christos Stavrakakis
        if options["list_filters"]:
244 7cfc0cef Christos Stavrakakis
            self.display_filters()
245 7cfc0cef Christos Stavrakakis
            return
246 7cfc0cef Christos Stavrakakis
247 7cfc0cef Christos Stavrakakis
        # --output option
248 7cfc0cef Christos Stavrakakis
        if options["fields"]:
249 7cfc0cef Christos Stavrakakis
            fields = options["fields"]
250 7cfc0cef Christos Stavrakakis
            fields = fields.split(",")
251 7cfc0cef Christos Stavrakakis
            self.validate_fields(fields)
252 7cfc0cef Christos Stavrakakis
            self.fields = options["fields"].split(",")
253 7cfc0cef Christos Stavrakakis
254 4845dfaa Christos Stavrakakis
        # --display-mails option
255 4845dfaa Christos Stavrakakis
        if options.get("display_mails"):
256 4845dfaa Christos Stavrakakis
            self.fields.append(USER_EMAIL_FIELD)
257 4845dfaa Christos Stavrakakis
258 7cfc0cef Christos Stavrakakis
        # --filter-by option
259 7cfc0cef Christos Stavrakakis
        if options["filter_by"]:
260 48233747 Christos Stavrakakis
            filters, excludes = \
261 48233747 Christos Stavrakakis
                utils.parse_queryset_filters(options["filter_by"])
262 7cfc0cef Christos Stavrakakis
        else:
263 7cfc0cef Christos Stavrakakis
            filters, excludes = ({}, {})
264 7cfc0cef Christos Stavrakakis
265 7cfc0cef Christos Stavrakakis
        self.filters.update(filters)
266 7cfc0cef Christos Stavrakakis
        self.excludes.update(excludes)
267 7cfc0cef Christos Stavrakakis
268 7cfc0cef Christos Stavrakakis
        # --user option
269 7cfc0cef Christos Stavrakakis
        user = options.get("user")
270 7cfc0cef Christos Stavrakakis
        if user:
271 7cfc0cef Christos Stavrakakis
            if "@" in user:
272 ef57e622 Ilias Tsitsimpis
                ucache = UserCache(self.astakos_auth_url, self.astakos_token)
273 7cfc0cef Christos Stavrakakis
                user = ucache.get_uuid(user)
274 7cfc0cef Christos Stavrakakis
            self.filters[self.user_uuid_field] = user
275 7cfc0cef Christos Stavrakakis
276 7cfc0cef Christos Stavrakakis
        # --deleted option
277 7cfc0cef Christos Stavrakakis
        if self.deleted_field:
278 7cfc0cef Christos Stavrakakis
            deleted = options.get("deleted")
279 7cfc0cef Christos Stavrakakis
            if deleted:
280 7cfc0cef Christos Stavrakakis
                self.filters[self.deleted_field] = True
281 7cfc0cef Christos Stavrakakis
            else:
282 7cfc0cef Christos Stavrakakis
                self.filters[self.deleted_field] = False
283 7cfc0cef Christos Stavrakakis
284 7cfc0cef Christos Stavrakakis
        # Special handling of arguments
285 7cfc0cef Christos Stavrakakis
        self.handle_args(self, *args, **options)
286 7cfc0cef Christos Stavrakakis
287 3b6afb38 Christos Stavrakakis
        select_related = getattr(self, "select_related", [])
288 3b6afb38 Christos Stavrakakis
        prefetch_related = getattr(self, "prefetch_related", [])
289 3b6afb38 Christos Stavrakakis
290 7cfc0cef Christos Stavrakakis
        objects = self.object_class.objects
291 7cfc0cef Christos Stavrakakis
        try:
292 787f7372 Giorgos Korfiatis
            if select_related:
293 787f7372 Giorgos Korfiatis
                objects = objects.select_related(*select_related)
294 787f7372 Giorgos Korfiatis
            if prefetch_related:
295 787f7372 Giorgos Korfiatis
                objects = objects.prefetch_related(*prefetch_related)
296 7cfc0cef Christos Stavrakakis
            objects = objects.filter(**self.filters)
297 c8922d01 Giorgos Korfiatis
            for key, value in self.excludes.iteritems():
298 c8922d01 Giorgos Korfiatis
                objects = objects.exclude(**{key:value})
299 7cfc0cef Christos Stavrakakis
        except FieldError as e:
300 7cfc0cef Christos Stavrakakis
            raise CommandError(e)
301 7cfc0cef Christos Stavrakakis
        except Exception as e:
302 7cfc0cef Christos Stavrakakis
            raise CommandError("Can not filter results: %s" % e)
303 7cfc0cef Christos Stavrakakis
304 7cfc0cef Christos Stavrakakis
        order_key = self.order_by if self.order_by is not None else 'pk'
305 7cfc0cef Christos Stavrakakis
        objects = objects.order_by(order_key)
306 7cfc0cef Christos Stavrakakis
307 4845dfaa Christos Stavrakakis
        if USER_EMAIL_FIELD in self.fields:
308 4845dfaa Christos Stavrakakis
            if '_user_email' in self.object_class._meta.get_all_field_names():
309 7cfc0cef Christos Stavrakakis
                raise RuntimeError("%s has already a 'user_mail' attribute")
310 7cfc0cef Christos Stavrakakis
            uuids = [getattr(obj, self.user_uuid_field) for obj in objects]
311 ef57e622 Ilias Tsitsimpis
            ucache = UserCache(self.astakos_auth_url, self.astakos_token)
312 7cfc0cef Christos Stavrakakis
            ucache.fetch_names(list(set(uuids)))
313 7cfc0cef Christos Stavrakakis
            for obj in objects:
314 7cfc0cef Christos Stavrakakis
                uuid = getattr(obj, self.user_uuid_field)
315 4845dfaa Christos Stavrakakis
                obj._user_email = ucache.get_name(uuid)
316 7cfc0cef Christos Stavrakakis
317 7cfc0cef Christos Stavrakakis
        # Special handling of DB results
318 7cfc0cef Christos Stavrakakis
        objects = list(objects)
319 7cfc0cef Christos Stavrakakis
        self.handle_db_objects(objects, **options)
320 7cfc0cef Christos Stavrakakis
321 7cfc0cef Christos Stavrakakis
        headers = self.fields
322 7cfc0cef Christos Stavrakakis
        columns = [self.FIELDS[key][0] for key in headers]
323 7cfc0cef Christos Stavrakakis
324 7cfc0cef Christos Stavrakakis
        table = []
325 7cfc0cef Christos Stavrakakis
        for obj in objects:
326 7cfc0cef Christos Stavrakakis
            row = []
327 7cfc0cef Christos Stavrakakis
            for attr in columns:
328 7cfc0cef Christos Stavrakakis
                if callable(attr):
329 7cfc0cef Christos Stavrakakis
                    row.append(attr(obj))
330 7cfc0cef Christos Stavrakakis
                else:
331 7cfc0cef Christos Stavrakakis
                    item = obj
332 7cfc0cef Christos Stavrakakis
                    attrs = attr.split(".")
333 7cfc0cef Christos Stavrakakis
                    for attr in attrs:
334 7cfc0cef Christos Stavrakakis
                        item = getattr(item, attr)
335 7cfc0cef Christos Stavrakakis
                    row.append(item)
336 7cfc0cef Christos Stavrakakis
            table.append(row)
337 7cfc0cef Christos Stavrakakis
338 7cfc0cef Christos Stavrakakis
        # Special handle of output
339 7cfc0cef Christos Stavrakakis
        self.handle_output(table, headers)
340 7cfc0cef Christos Stavrakakis
341 7cfc0cef Christos Stavrakakis
        # Print output
342 7cfc0cef Christos Stavrakakis
        output_format = options["output_format"]
343 7cfc0cef Christos Stavrakakis
        if output_format != "json" and not options["headers"]:
344 7cfc0cef Christos Stavrakakis
            headers = None
345 7cfc0cef Christos Stavrakakis
        utils.pprint_table(self.stdout, table, headers, output_format)
346 7cfc0cef Christos Stavrakakis
347 7cfc0cef Christos Stavrakakis
    def handle_args(self, *args, **kwargs):
348 7cfc0cef Christos Stavrakakis
        pass
349 7cfc0cef Christos Stavrakakis
350 7cfc0cef Christos Stavrakakis
    def handle_db_objects(self, objects, **options):
351 7cfc0cef Christos Stavrakakis
        pass
352 7cfc0cef Christos Stavrakakis
353 7cfc0cef Christos Stavrakakis
    def handle_output(self, table, headers):
354 7cfc0cef Christos Stavrakakis
        pass
355 7cfc0cef Christos Stavrakakis
356 7cfc0cef Christos Stavrakakis
    def display_fields(self):
357 7cfc0cef Christos Stavrakakis
        headers = ["Field", "Description"]
358 7cfc0cef Christos Stavrakakis
        table = []
359 7cfc0cef Christos Stavrakakis
        for field, (_, help_msg) in self.FIELDS.items():
360 7cfc0cef Christos Stavrakakis
            table.append((field, help_msg))
361 7cfc0cef Christos Stavrakakis
        utils.pprint_table(self.stdout, table, headers)
362 7cfc0cef Christos Stavrakakis
363 7cfc0cef Christos Stavrakakis
    def validate_fields(self, fields):
364 7cfc0cef Christos Stavrakakis
        for f in fields:
365 7cfc0cef Christos Stavrakakis
            if f not in self.FIELDS.keys():
366 7cfc0cef Christos Stavrakakis
                raise CommandError("Unknown field '%s'. 'Use --list-fields"
367 7cfc0cef Christos Stavrakakis
                                   " option to find out available fields."
368 7cfc0cef Christos Stavrakakis
                                   % f)
369 7cfc0cef Christos Stavrakakis
370 7cfc0cef Christos Stavrakakis
    def display_filters(self):
371 7cfc0cef Christos Stavrakakis
        headers = ["Filter", "Description", "Help"]
372 7cfc0cef Christos Stavrakakis
        table = []
373 7cfc0cef Christos Stavrakakis
        for field in self.object_class._meta.fields:
374 7cfc0cef Christos Stavrakakis
            table.append((field.name, field.verbose_name, field.help_text))
375 7cfc0cef Christos Stavrakakis
        utils.pprint_table(self.stdout, table, headers)
376 c406d7d9 Dionysis Grigoropoulos
377 c406d7d9 Dionysis Grigoropoulos
378 c406d7d9 Dionysis Grigoropoulos
class RemoveCommand(BaseCommand):
379 c406d7d9 Dionysis Grigoropoulos
    help = "Generic remove command"
380 c406d7d9 Dionysis Grigoropoulos
    option_list = BaseCommand.option_list + (
381 c406d7d9 Dionysis Grigoropoulos
        make_option(
382 c406d7d9 Dionysis Grigoropoulos
            "-f", "--force",
383 c406d7d9 Dionysis Grigoropoulos
            dest="force",
384 c406d7d9 Dionysis Grigoropoulos
            action="store_true",
385 c406d7d9 Dionysis Grigoropoulos
            default=False,
386 c406d7d9 Dionysis Grigoropoulos
            help="Do not prompt for confirmation"),
387 c406d7d9 Dionysis Grigoropoulos
    )
388 c406d7d9 Dionysis Grigoropoulos
389 c406d7d9 Dionysis Grigoropoulos
    def confirm_deletion(self, force, resource='', args=''):
390 c406d7d9 Dionysis Grigoropoulos
        if force is True:
391 c406d7d9 Dionysis Grigoropoulos
            return True
392 c406d7d9 Dionysis Grigoropoulos
393 c406d7d9 Dionysis Grigoropoulos
        ids = ', '.join(args)
394 c406d7d9 Dionysis Grigoropoulos
        self.stdout.write("Are you sure you want to delete %s %s?"
395 0f89715b Dionysis Grigoropoulos
                          " [Y/N] " % (resource, ids))
396 c406d7d9 Dionysis Grigoropoulos
        try:
397 c406d7d9 Dionysis Grigoropoulos
            answer = distutils.util.strtobool(raw_input())
398 c406d7d9 Dionysis Grigoropoulos
            if answer != 1:
399 c406d7d9 Dionysis Grigoropoulos
                raise CommandError("Aborting deletion")
400 c406d7d9 Dionysis Grigoropoulos
        except ValueError:
401 d27b16cc Dionysis Grigoropoulos
            raise CommandError("Unaccepted input value. Please choose yes/no"
402 d27b16cc Dionysis Grigoropoulos
                               " (y/n).")