| 289 | |
| 290 | |
| 291 | def lookup_field(name, obj, model_admin=None): |
| 292 | opts = obj._meta |
| 293 | try: |
| 294 | f = _get_non_gfk_field(opts, name) |
| 295 | except (FieldDoesNotExist, FieldIsAForeignKeyColumnName): |
| 296 | # For non-regular field values, the value is either a method, |
| 297 | # property, related field, or returned via a callable. |
| 298 | f = None |
| 299 | if callable(name): |
| 300 | attr = name |
| 301 | value = attr(obj) |
| 302 | elif hasattr(model_admin, name) and name != "__str__": |
| 303 | attr = getattr(model_admin, name) |
| 304 | value = attr(obj) |
| 305 | else: |
| 306 | sentinel = object() |
| 307 | attr = getattr(obj, name, sentinel) |
| 308 | if callable(attr): |
| 309 | value = attr() |
| 310 | else: |
| 311 | if attr is sentinel: |
| 312 | attr = obj |
| 313 | for part in name.split(LOOKUP_SEP): |
| 314 | attr = getattr(attr, part, sentinel) |
| 315 | if attr is sentinel: |
| 316 | return None, None, None |
| 317 | # The final field is needed for displaying boolean icons. |
| 318 | if LOOKUP_SEP in name: |
| 319 | f = get_fields_from_path(opts.model, name)[-1] |
| 320 | value = attr |
| 321 | if hasattr(model_admin, "model") and hasattr(model_admin.model, name): |
| 322 | attr = getattr(model_admin.model, name) |
| 323 | else: |
| 324 | attr = None |
| 325 | value = getattr(obj, name) |
| 326 | return f, attr, value |
| 327 | |
| 328 | |
| 329 | def _get_non_gfk_field(opts, name): |