Ensure all lazy (i.e. string) model references have been resolved. Lazy references are used in various places throughout Django, primarily in related fields and model signals. Identify those common cases and provide more helpful error messages for them. The ignore parameter is
(apps, ignore=None)
| 91 | |
| 92 | |
| 93 | def _check_lazy_references(apps, ignore=None): |
| 94 | """ |
| 95 | Ensure all lazy (i.e. string) model references have been resolved. |
| 96 | |
| 97 | Lazy references are used in various places throughout Django, primarily in |
| 98 | related fields and model signals. Identify those common cases and provide |
| 99 | more helpful error messages for them. |
| 100 | |
| 101 | The ignore parameter is used by StateApps to exclude swappable models from |
| 102 | this check. |
| 103 | """ |
| 104 | pending_models = set(apps._pending_operations) - (ignore or set()) |
| 105 | |
| 106 | # Short circuit if there aren't any errors. |
| 107 | if not pending_models: |
| 108 | return [] |
| 109 | |
| 110 | from django.db.models import signals |
| 111 | |
| 112 | model_signals = { |
| 113 | signal: name |
| 114 | for name, signal in vars(signals).items() |
| 115 | if isinstance(signal, signals.ModelSignal) |
| 116 | } |
| 117 | |
| 118 | def extract_operation(obj): |
| 119 | """ |
| 120 | Take a callable found in Apps._pending_operations and identify the |
| 121 | original callable passed to Apps.lazy_model_operation(). If that |
| 122 | callable was a partial, return the inner, non-partial function and |
| 123 | any arguments and keyword arguments that were supplied with it. |
| 124 | |
| 125 | obj is a callback defined locally in Apps.lazy_model_operation() and |
| 126 | annotated there with a `func` attribute so as to imitate a partial. |
| 127 | """ |
| 128 | operation, args, keywords = obj, [], {} |
| 129 | while hasattr(operation, "func"): |
| 130 | args.extend(getattr(operation, "args", [])) |
| 131 | keywords.update(getattr(operation, "keywords", {})) |
| 132 | operation = operation.func |
| 133 | return operation, args, keywords |
| 134 | |
| 135 | def app_model_error(model_key): |
| 136 | try: |
| 137 | apps.get_app_config(model_key[0]) |
| 138 | model_error = "app '%s' doesn't provide model '%s'" % model_key |
| 139 | except LookupError: |
| 140 | model_error = "app '%s' isn't installed" % model_key[0] |
| 141 | return model_error |
| 142 | |
| 143 | # Here are several functions which return CheckMessage instances for the |
| 144 | # most common usages of lazy operations throughout Django. These functions |
| 145 | # take the model that was being waited on as an (app_label, modelname) |
| 146 | # pair, the original lazy function, and its positional and keyword args as |
| 147 | # determined by extract_operation(). |
| 148 | |
| 149 | def field_error(model_key, func, args, keywords): |
| 150 | error_msg = ( |