def app_model_error(model_key): try: apps.get_app_config(model_key[0]) model_error = "app '%s' doesn't provide model '%s'" % model_key except LookupError: model_error = "app '%s' isn't installed" % model_key[0] return model_error
def ask_initial(self, app_label): """Should we create an initial migration for the app?""" # If it was specified on the command line, definitely true if app_label in self.specified_apps: return True # Otherwise, we look to see if it has a migrations module # without any Python files in it, apart from __init__.py. # Apps from the new app template will have these; the Python # file check will ensure we skip South ones. try: app_config = apps.get_app_config(app_label) except LookupError: # It's a fake app. return self.defaults.get("ask_initial", False) migrations_import_path, _ = MigrationLoader.migrations_module( app_config.label) if migrations_import_path is None: # It's an application with migrations disabled. return self.defaults.get("ask_initial", False) try: migrations_module = importlib.import_module(migrations_import_path) except ImportError: return self.defaults.get("ask_initial", False) else: # getattr() needed on PY36 and older (replace with attribute access). if getattr(migrations_module, "__file__", None): filenames = os.listdir( os.path.dirname(migrations_module.__file__)) elif hasattr(migrations_module, "__path__"): if len(migrations_module.__path__) > 1: return False filenames = os.listdir(list(migrations_module.__path__)[0]) return not any( x.endswith(".py") for x in filenames if x != "__init__.py")
def parse_apps_and_model_labels(labels): """ Parse a list of "app_label.ModelName" or "app_label" strings into actual objects and return a two-element tuple: (set of model classes, set of app_configs). Raise a CommandError if some specified models or apps don't exist. """ apps = set() models = set() for label in labels: if '.' in label: try: model = installed_apps.get_model(label) except LookupError: raise CommandError('Unknown model: %s' % label) models.add(model) else: try: app_config = installed_apps.get_app_config(label) except LookupError as e: raise CommandError(str(e)) apps.add(app_config) return models, apps
def handle(self, *app_labels, **options): include_deployment_checks = options['deploy'] if options['list_tags']: self.stdout.write('\n'.join( sorted(registry.tags_available(include_deployment_checks)))) return if app_labels: app_configs = [ apps.get_app_config(app_label) for app_label in app_labels ] else: app_configs = None tags = options['tags'] if tags: try: invalid_tag = next( tag for tag in tags if not checks.tag_exists(tag, include_deployment_checks)) except StopIteration: # no invalid tags pass else: raise CommandError( 'There is no system check with the "%s" tag.' % invalid_tag) self.check( app_configs=app_configs, tags=tags, display_num_errors=True, include_deployment_checks=include_deployment_checks, fail_level=getattr(checks, options['fail_level']), )
def basedir(self): migrations_package_name, _ = MigrationLoader.migrations_module(self.migration.app_label) if migrations_package_name is None: raise ValueError( "Server can't create migrations for app '%s' because " "migrations have been disabled via the MIGRATION_MODULES " "setting." % self.migration.app_label ) # See if we can import the migrations module directly try: migrations_module = import_module(migrations_package_name) except ImportError: pass else: try: return module_dir(migrations_module) except ValueError: pass # Alright, see if it's a direct submodule of the app app_config = apps.get_app_config(self.migration.app_label) maybe_app_name, _, migrations_package_basename = migrations_package_name.rpartition(".") if app_config.name == maybe_app_name: return os.path.join(app_config.path, migrations_package_basename) # In case of using MIGRATION_MODULES setting and the custom package # doesn't exist, create one, starting from an existing package existing_dirs, missing_dirs = migrations_package_name.split("."), [] while existing_dirs: missing_dirs.insert(0, existing_dirs.pop(-1)) try: base_module = import_module(".".join(existing_dirs)) except (ImportError, ValueError): continue else: try: base_dir = module_dir(base_module) except ValueError: continue else: break else: raise ValueError( "Could not locate an appropriate location to create " "migrations package %s. Make sure the toplevel " "package exists and can be imported." % migrations_package_name) final_dir = os.path.join(base_dir, *missing_dirs) if not os.path.isdir(final_dir): os.makedirs(final_dir) for missing_dir in missing_dirs: base_dir = os.path.join(base_dir, missing_dir) with open(os.path.join(base_dir, "__init__.py"), "w"): pass return final_dir
def migrations_module(cls, app_label): """ Return the path to the migrations module for the specified app_label and a boolean indicating if the module is specified in settings.MIGRATION_MODULE. """ if app_label in settings.MIGRATION_MODULES: return settings.MIGRATION_MODULES[app_label], True else: app_package_name = apps.get_app_config(app_label).name return '%s.%s' % (app_package_name, MIGRATIONS_MODULE_NAME), False
def set_options(self, **options): """ Set instance variables based on an options dict """ self.interactive = options['interactive'] self.verbosity = options['verbosity'] self.symlink = options['link'] self.clear = options['clear'] self.dry_run = options['dry_run'] ignore_patterns = options['ignore_patterns'] if options['use_default_ignore_patterns']: ignore_patterns += apps.get_app_config( 'staticfiles').ignore_patterns self.ignore_patterns = list(set(ignore_patterns)) self.post_process = options['post_process']
def handle(self, *app_labels, **options): from server.apps import apps try: app_configs = [ apps.get_app_config(app_label) for app_label in app_labels ] except (LookupError, ImportError) as e: raise CommandError( "%s. Are you sure your INSTALLED_APPS setting is correct?" % e) output = [] for app_config in app_configs: app_output = self.handle_app_config(app_config, **options) if app_output: output.append(app_output) return '\n'.join(output)
def get_context_data(self, **kwargs): model_name = self.kwargs['model_name'] # Get the model class. try: app_config = apps.get_app_config(self.kwargs['app_label']) except LookupError: raise Http404(_("App %(app_label)r not found") % self.kwargs) try: model = app_config.get_model(model_name) except LookupError: raise Http404( _("Model %(model_name)r not found in app %(app_label)r") % self.kwargs) opts = model._meta title, body, metadata = utils.parse_docstring(model.__doc__) title = title and utils.parse_rst(title, 'model', _('model:') + model_name) body = body and utils.parse_rst(body, 'model', _('model:') + model_name) # Gather fields/field descriptions. fields = [] for field in opts.fields: # ForeignKey is a special case since the field will actually be a # descriptor that returns the other object if isinstance(field, models.ForeignKey): data_type = field.remote_field.model.__name__ app_label = field.remote_field.model._meta.app_label verbose = utils.parse_rst( (_("the related `%(app_label)s.%(data_type)s` object") % { 'app_label': app_label, 'data_type': data_type, }), 'model', _('model:') + data_type, ) else: data_type = get_readable_field_data_type(field) verbose = field.verbose_name fields.append({ 'name': field.name, 'data_type': data_type, 'verbose': verbose or '', 'help_text': field.help_text, }) # Gather many-to-many fields. for field in opts.many_to_many: data_type = field.remote_field.model.__name__ app_label = field.remote_field.model._meta.app_label verbose = _("related `%(app_label)s.%(object_name)s` objects") % { 'app_label': app_label, 'object_name': data_type, } fields.append({ 'name': "%s.all" % field.name, "data_type": 'List', 'verbose': utils.parse_rst( _("all %s") % verbose, 'model', _('model:') + opts.model_name), }) fields.append({ 'name': "%s.count" % field.name, 'data_type': 'Integer', 'verbose': utils.parse_rst( _("number of %s") % verbose, 'model', _('model:') + opts.model_name), }) methods = [] # Gather model methods. for func_name, func in model.__dict__.items(): if inspect.isfunction(func): try: for exclude in MODEL_METHODS_EXCLUDE: if func_name.startswith(exclude): raise StopIteration except StopIteration: continue verbose = func.__doc__ verbose = verbose and (utils.parse_rst( utils.trim_docstring(verbose), 'model', _('model:') + opts.model_name)) # If a method has no arguments, show it as a 'field', otherwise # as a 'method with arguments'. if func_has_no_args(func) and not func_accepts_kwargs( func) and not func_accepts_var_args(func): fields.append({ 'name': func_name, 'data_type': get_return_data_type(func_name), 'verbose': verbose or '', }) else: arguments = get_func_full_args(func) # Join arguments with ', ' and in case of default value, # join it with '='. Use repr() so that strings will be # correctly displayed. print_arguments = ', '.join([ '='.join( list(arg_el[:1]) + [repr(el) for el in arg_el[1:]]) for arg_el in arguments ]) methods.append({ 'name': func_name, 'arguments': print_arguments, 'verbose': verbose or '', }) # Gather related objects for rel in opts.related_objects: verbose = _("related `%(app_label)s.%(object_name)s` objects") % { 'app_label': rel.related_model._meta.app_label, 'object_name': rel.related_model._meta.object_name, } accessor = rel.get_accessor_name() fields.append({ 'name': "%s.all" % accessor, 'data_type': 'List', 'verbose': utils.parse_rst( _("all %s") % verbose, 'model', _('model:') + opts.model_name), }) fields.append({ 'name': "%s.count" % accessor, 'data_type': 'Integer', 'verbose': utils.parse_rst( _("number of %s") % verbose, 'model', _('model:') + opts.model_name), }) return super().get_context_data( **{ **kwargs, 'name': '%s.%s' % (opts.app_label, opts.object_name), 'summary': title, 'description': body, 'fields': fields, 'methods': methods, })
def handle(self, *app_labels, **options): self.verbosity = options['verbosity'] self.interactive = options['interactive'] self.dry_run = options['dry_run'] self.merge = options['merge'] self.empty = options['empty'] self.migration_name = options['name'] check_changes = options['check_changes'] # Make sure the app they asked for exists app_labels = set(app_labels) bad_app_labels = set() for app_label in app_labels: try: apps.get_app_config(app_label) except LookupError: bad_app_labels.add(app_label) if bad_app_labels: for app_label in bad_app_labels: if '.' in app_label: self.stderr.write( "'%s' is not a valid app label. Did you mean '%s'?" % ( app_label, app_label.split('.')[-1], )) else: self.stderr.write( "App '%s' could not be found. Is it in INSTALLED_APPS?" % app_label) sys.exit(2) # Load the current graph state. Pass in None for the connection so # the loader doesn't try to resolve replaced migrations from DB. loader = MigrationLoader(None, ignore_no_migrations=True) # Raise an error if any migrations are applied before their dependencies. consistency_check_labels = { config.label for config in apps.get_app_configs() } # Non-default databases are only checked if database routers used. aliases_to_check = connections if settings.DATABASE_ROUTERS else [ DEFAULT_DB_ALIAS ] for alias in sorted(aliases_to_check): connection = connections[alias] if (connection.settings_dict['ENGINE'] != 'server.db.backends.dummy' and any( # At least one model must be migrated to the database. router.allow_migrate(connection.alias, app_label, model_name=model._meta.object_name ) for app_label in consistency_check_labels for model in apps.get_app_config(app_label).get_models())): loader.check_consistent_history(connection) # Before anything else, see if there's conflicting apps and drop out # hard if there are any and they don't want to merge conflicts = loader.detect_conflicts() # If app_labels is specified, filter out conflicting migrations for unspecified apps if app_labels: conflicts = { app_label: conflict for app_label, conflict in conflicts.items() if app_label in app_labels } if conflicts and not self.merge: name_str = "; ".join("%s in %s" % (", ".join(names), app) for app, names in conflicts.items()) raise CommandError( "Conflicting migrations detected; multiple leaf nodes in the " "migration graph: (%s).\nTo fix them run " "'python manage.py makemigrations --merge'" % name_str) # If they want to merge and there's nothing to merge, then politely exit if self.merge and not conflicts: self.stdout.write("No conflicts detected to merge.") return # If they want to merge and there is something to merge, then # divert into the merge code if self.merge and conflicts: return self.handle_merge(loader, conflicts) if self.interactive: questioner = InteractiveMigrationQuestioner( specified_apps=app_labels, dry_run=self.dry_run) else: questioner = NonInteractiveMigrationQuestioner( specified_apps=app_labels, dry_run=self.dry_run) # Set up autodetector autodetector = MigrationAutodetector( loader.project_state(), ProjectState.from_apps(apps), questioner, ) # If they want to make an empty migration, make one for each app if self.empty: if not app_labels: raise CommandError( "You must supply at least one app label when using --empty." ) # Make a fake changes() result we can pass to arrange_for_graph changes = {app: [Migration("custom", app)] for app in app_labels} changes = autodetector.arrange_for_graph( changes=changes, graph=loader.graph, migration_name=self.migration_name, ) self.write_migration_files(changes) return # Detect changes changes = autodetector.changes( graph=loader.graph, trim_to_apps=app_labels or None, convert_apps=app_labels or None, migration_name=self.migration_name, ) if not changes: # No changes? Tell them. if self.verbosity >= 1: if app_labels: if len(app_labels) == 1: self.stdout.write("No changes detected in app '%s'" % app_labels.pop()) else: self.stdout.write("No changes detected in apps '%s'" % ("', '".join(app_labels))) else: self.stdout.write("No changes detected") else: self.write_migration_files(changes) if check_changes: sys.exit(1)
def handle(self, *app_labels, **options): format = options['format'] indent = options['indent'] using = options['database'] excludes = options['exclude'] output = options['output'] show_traceback = options['traceback'] use_natural_foreign_keys = options['use_natural_foreign_keys'] use_natural_primary_keys = options['use_natural_primary_keys'] use_base_manager = options['use_base_manager'] pks = options['primary_keys'] if pks: primary_keys = [pk.strip() for pk in pks.split(',')] else: primary_keys = [] excluded_models, excluded_apps = parse_apps_and_model_labels(excludes) if not app_labels: if primary_keys: raise CommandError( "You can only use --pks option with one model") app_list = OrderedDict.fromkeys( app_config for app_config in apps.get_app_configs() if app_config.models_module is not None and app_config not in excluded_apps) else: if len(app_labels) > 1 and primary_keys: raise CommandError( "You can only use --pks option with one model") app_list = OrderedDict() for label in app_labels: try: app_label, model_label = label.split('.') try: app_config = apps.get_app_config(app_label) except LookupError as e: raise CommandError(str(e)) if app_config.models_module is None or app_config in excluded_apps: continue try: model = app_config.get_model(model_label) except LookupError: raise CommandError("Unknown model: %s.%s" % (app_label, model_label)) app_list_value = app_list.setdefault(app_config, []) # We may have previously seen a "all-models" request for # this app (no model qualifier was given). In this case # there is no need adding specific models to the list. if app_list_value is not None: if model not in app_list_value: app_list_value.append(model) except ValueError: if primary_keys: raise CommandError( "You can only use --pks option with one model") # This is just an app - no model qualifier app_label = label try: app_config = apps.get_app_config(app_label) except LookupError as e: raise CommandError(str(e)) if app_config.models_module is None or app_config in excluded_apps: continue app_list[app_config] = None # Check that the serialization format exists; this is a shortcut to # avoid collating all the objects and _then_ failing. if format not in serializers.get_public_serializer_formats(): try: serializers.get_serializer(format) except serializers.SerializerDoesNotExist: pass raise CommandError("Unknown serialization format: %s" % format) def get_objects(count_only=False): """ Collate the objects to be serialized. If count_only is True, just count the number of objects to be serialized. """ models = serializers.sort_dependencies(app_list.items()) for model in models: if model in excluded_models: continue if model._meta.proxy and model._meta.proxy_for_model not in models: warnings.warn( "%s is a proxy model and won't be serialized." % model._meta.label, category=ProxyModelWarning, ) if not model._meta.proxy and router.allow_migrate_model( using, model): if use_base_manager: objects = model._base_manager else: objects = model._default_manager queryset = objects.using(using).order_by( model._meta.pk.name) if primary_keys: queryset = queryset.filter(pk__in=primary_keys) if count_only: yield queryset.order_by().count() else: yield from queryset.iterator() try: self.stdout.ending = None progress_output = None object_count = 0 # If dumpdata is outputting to stdout, there is no way to display progress if output and self.stdout.isatty() and options['verbosity'] > 0: progress_output = self.stdout object_count = sum(get_objects(count_only=True)) stream = open(output, 'w') if output else None try: serializers.serialize( format, get_objects(), indent=indent, use_natural_foreign_keys=use_natural_foreign_keys, use_natural_primary_keys=use_natural_primary_keys, stream=stream or self.stdout, progress_output=progress_output, object_count=object_count, ) finally: if stream: stream.close() except Exception as e: if show_traceback: raise raise CommandError("Unable to serialize database: %s" % e)