Получение значений из внешнего ключа модели Python

Допустим, у меня есть такие модели/классы:

class User(models.Model):
    id = models.AutoField. . .
    group = models.ForeignKey(
        Group,
        . . .
    )
    . . .

class Group(models.Model):
    id = models.AutoField. . .
    name = models.CharField. . .
    . . .

В пользовательской функции журналирования, вызываемой, когда происходит изменение, я делаю следующее:

obj = # object/model being updated; in this case: User
old_values = {}
new_values = {}
for i in range(len(form.changed_data)):
    vname = obj._meta.get_field(form.changed_data[i]).verbose_name

    old_values.update(
        { vname: form[form.changed_data[i]].initial }
    )
    new_values.update(
        { vname: form.cleaned_data[form.changed_data[i]] }
    )

Это приводит к такому выводу:

old_values = {'Group': 2}

new_values = {'Group': <Group: New Group Name>}

Похоже, что form.initial использует id, а form.cleaned_data использует какой-то неприглядный формат имени объекта.

Ни то, ни другое нежелательно. Я хочу, чтобы вывод выглядел следующим образом:

old_values = {'Group': 'Old Group Name'}

new_values = {'Group': 'New Group Name'}

Как мне это сделать? Я не могу явно импортировать имя модели и использовать ее. User и Group - это всего лишь две из десятков моделей, которые должны обрабатываться неявно в этой общей функции протоколирования.

Я пробовал apps.get_model(), get_object_or_404() и другие методы, но пока ничего не помогает.

Значением внешнего ключа в форме по умолчанию является PK модели.

# old_values = {'Group': 2}
group = Group.objects.get(pk=old_values['Group'])
new_values = {'Group': group.name}

Я все еще не знаю, как сделать то, что я пробовал выше, но я решил свою проблему другим способом.

Для начала каждый объект имеет метапеременную, которая ссылается на его класс объекта. Используя ее, мы можем получить список полей для любого данного объекта.

for field in obj._meta.get_fields():
    value = getattr(obj, field.name, None)

Вы можете проверить каждое поле на любые спецификации, которые у вас есть, например, должны ли они игнорироваться, как поля ID, должны ли быть цензурированы, как поля пароля, или являются полями ManyToManyField и т.д.

if isinstance(field, ManyToManyField):
    values = []
    for obj in value.all():
        values.append(str(obj))

В зависимости от значения, вы можете захотеть repr(value), str(value), str(object) или просто value.

Что я сделал, так это создал функцию get_values(object), которая использовала вышеописанное для возврата стандартного списка. Отправка этой функции объектов во время процесса протоколирования работала просто замечательно.

Вернуться на верх