3

I'm trying to get the field object from a filter like string in Django.

For example,

Sale.objects.filter(product__category__name='shoes')

Given model Sale and the string "product__category__name", is it possible to get the field object for Category.name? (or to be more specific, the verbose_name of that field).

UPDATE

This is what i eventually came up with

from django.db.models.fields import FieldDoesNotExist

def find_field(model, lookup):
    lookups = list(reversed(lookup.split("__")))
    field = None

    while model and lookups:
        current = lookups.pop()
        field = model._meta.get_field(current)
        model = field.related_model
        if lookups and model is None:
            raise FieldDoesNotExist(lookup)
    return field
2
  • Fine solution. Could you add it as one of the answers and accept so question will be marked as resoled? Commented Jan 17, 2019 at 12:05
  • Also does this work fine with m2m/genericrelations? Commented Jan 17, 2019 at 12:06

3 Answers 3

1

To get a verbose_name you should call object._meta.get_field('field').verbose_name

category._meta.get_field('name').verbose_name
Sign up to request clarification or add additional context in comments.

2 Comments

The point is getting to the category model from the lookup string.
Which objects do you have? Sale class and "product__category__name" string? Or something else?
1

You could try something along these lines

def get_verbose_name_from_query_string(query_string):
    query_string = query_string.split('__')[-1].split('_')
    model_name = query_string[0]
    field_name = query_string[1]
    model = apps.get_model('app_name', model_name)
    return model._meta.get_field(field_name).verbose_name

query_string = 'product__category_name'    
get_verbose_name_from_query_string(query_string)

This would return Name

If you have multiple apps this can get harder as you need to know the app name too, but maybe this can be passed in as an argument.

Comments

0

Here is a full solution on how to find the field from a lookup spanning relationships. This is based on the great answer that OP gave in the question, but with some improvements and bug fixes.

from django.core.exceptions import FieldDoesNotExist
from django.db import models


def find_field_from_lookup(model_class: models.Model, lookup: str) -> models.Field:
    """Find field object from a lookup, which can span relationships.

    Example: `"book__author__name"` would return the `name` field of the `Author` model.

    Raises `FieldDoesNotExist` when the lookup is not valid.
    """
    field_names = list(reversed(lookup.split("__")))
    if not field_names or not model_class:
        raise FieldDoesNotExist(lookup)
    while model_class and field_names:
        field_name = field_names.pop()
        field = model_class._meta.get_field(field_name)
        model_class = field.related_model
        if field_names and not model_class:
            raise FieldDoesNotExist(lookup)
    return field

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.