【问题标题】:How to extract JSON value from a list and render it in a django model form?如何从列表中提取 JSON 值并以 django 模型形式呈现?
【发布时间】:2020-12-16 06:32:27
【问题描述】:

我正在尝试使用以下模型呈现 Django 模型表单。问题是模型字段之一是 JSONField。这是一个长度为 1 的列表,其中包含一些 JSON 数据。当我渲染模型表单时,number 字段会毫无问题地渲染列表。但我想从列表中的 JSON 中提取 phone 值并渲染它。我尝试在模板中提取它,但它没有按预期工作。

如何从 JSON 中提取 phone 值并将其呈现在表单中?例如,当我使用视图呈现 id 1 的数据时,我应该在名称字段中看到“Client_1”,在数字字段中看到“1234567890”。

我正在使用 Django 3.1 并使用 Django Crispy Forms 来呈现模型表单。

在 db 中看到客户端表的数据:

id  name        number
1   Client_1    [{'type': 'mobile', 'phone': '1234567890'}]
2   Client_2    [{'type': 'mobile', 'phone': '3334445555'}]
3   Client_3    [{'type': 'mobile', 'phone': '9876543210'}]

models.py:

class Client(models.Model):
    name = models.TextField()
    number = models.JSONField(blank=True, null=True)

forms.py:

from .models import Client

class ClientForm(forms.ModelForm):
    class Meta:
        model = Client
        fields = '__all__'

clients.html 模板:

{% load crispy_forms_tags %}

<form method="POST">
    <div class="form-row">
        <div class="form-group col-md-6">
            {{ form.name | as_crispy_field }}
        </div>
        <div class="form-group col-md-6">
            {% for item in form.number %}
                {{ item.0.phone | as_crispy_field }}
            {% endfor %}
        </div>
    </div>
</form>

views.py:

def clients(request, pk):
    instance = Client.objects.get(pk=pk)

    if request.method == 'POST':
        form = ClientForm(request.POST, instance=instance)
        if form.is_valid():
            form.save()
    else:
        form = ClientForm(instance=instance)

    return render(request, 'clients.html', {'form': form})

【问题讨论】:

    标签: django django-forms django-templates


    【解决方案1】:

    您需要在表单中动态添加字段,这是一个工作示例:

    class ClientForm(forms.ModelForm):
    
        def __init__(self, *args, instance=None, **kwargs):
            super(ClientForm, self).__init__(*args, instance=instance, **kwargs)
            if instance:
                for index, obj in enumerate(instance.number):
                    self.fields[f'phone_{index}'] = forms.CharField(initial=obj.get('phone', ''))
    
        def save(self, commit=True):
            for index, obj in enumerate(self.instance.number):
                obj['phone'] = self.cleaned_data.get(f'phone_{index}', '')
            return super(ClientForm, self).save(commit=commit)
    
        class Meta:
            model = Client
            fields = ['name']
    

    你的模板应该是:

    
    {% load crispy_forms_tags %}
    <form method="POST">
        <div class="form-row">
            <div class="form-group col-md-6">
                {{ form.name | as_crispy_field }}
            </div>
            <div class="form-group col-md-6">
                {{ form.phone_0 | as_crispy_field }}
            </div>
        </div>
    </form>
    

    注意:如果您总是将手机存储在列表中,则应为您的 JsonField 设置默认值:

    class Client(models.Model):
        name = models.TextField()
        number = models.JSONField(default=list)
    

    【讨论】:

    • 我尝试了上面的 init 并将方法保存在我的表单中。但它仍然显示我的问题中显示的列表。我不确定我是否做错了什么。
    • 我编辑了我的答案,你需要更新你的模板
    • 对不起,我赶上了工作。我会尽快更新我的答案。我只是好奇。 {{ form.phone_1 | as_crispy_field }} 是否适用于任何 ID?还是必须将form.phone_1 设为动态?
    • 我可以确认您的方法有效。我只需要在模板中做的一个小改动就是根据我收到的回溯错误将{{ form.phone_1 | as_crispy_field }} 更改为{{ form.phone_0 | as_crispy_field }}。进行此小更新后,它可以完美运行。非常感谢您对此进行调查。老实说,我不知道 init 方法在做什么.. :-)
    • 其实我发现了一个数字字段为空的场景。这导致了错误。所以为了克服这个问题,我稍微修改了你的 ini 函数:` if instance.number: for index, obj in enumerate(instance.number): self.fields[f'phone}'] = forms.CharField(initial=obj.get('phone', '')) else: self.fields[f'phone'] = forms.CharField(initial='') `
    猜你喜欢
    • 2018-01-09
    • 1970-01-01
    • 2012-03-30
    • 2019-03-15
    • 2019-07-29
    • 1970-01-01
    • 1970-01-01
    • 2014-11-16
    • 2018-10-13
    相关资源
    最近更新 更多