【问题标题】:How to check two models ID whitout nested loop?如何在没有嵌套循环的情况下检查两个模型 ID?
【发布时间】:2019-11-19 07:28:57
【问题描述】:

我的问题是我的模板的嵌套循环...我用它来检查我的模型 sitio.id_sitio 是否具有与另一个模型 comprobante.id_sitio 具有外键的等效 ID,然后如果找到一个结果并打印 A B 如果没有

条件 if 工作正常,但我不希望嵌套循环打印多次。

如果找到一个结果,我想打破循环并只打印一次 HTML,例如 <a href=""> Checkouts </a> 否则如果结果在末尾的记录中不存在我想打印<p>No payments</p>

我不知道是否必须在 views.py 中编写查询,或者是否必须在模板中执行其他操作... 有正确的方法吗?


这是我的代码:

模型.py

class Comprobante(models.Model):
        id_sitio = models.ForeignKey('Sitio', models.DO_NOTHING, db_column='id_sitio', blank=True, null=True)

class Sitio(models.Model):
        id_sitio = models.IntegerField(primary_key=True)
        sitio = models.CharField(max_length=100, blank=True, null=True)

        def __str__(self):
            return self.sitio

Views.py

def topsitios(request):
    sitio = Sitio.objects.all()[0:100]
    comprobante = Comprobante.objects.all()[0:100]

    context = {'sitio': sitio, 'comprobante': comprobante}

    return render(request, "sitio_ptc/topsitios.html", context)

模板.html

{% block content %}

{% for s in sitio %}
<tr>
<th scope="row">  {{ forloop.counter }}</th>
<td> {{ s.sitio }} </td>

<td>
{% for c in comprobante %}
{% if s.id_sitio == c.id_sitio_id %}
<a href="">Checkouts</a>
{% else %}
<p>no payments</p>
{% endif %}
{% endfor %}
</td> 

</tr> 
{% endfor %}
{% endblock %}

【问题讨论】:

    标签: python django django-models django-templates django-views


    【解决方案1】:

    这样做的正确方法是使用 Django ORM 来访问模型的关系。在每个sitio的for循环中,可以通过{% if s.comprobante_set.all %}检查是否存在相关的comprobante

    为了获得更好的性能,您还需要通过Sitio.objects.prefetch_related('comprobante_set').all() 预取相关的comprobante 记录。这样您就不会遇到 N+1 查询问题。

    【讨论】:

    • 这对我有用,非常感谢!如果有人正在搜索有关 prefetch_related 的更多信息,这里有一个链接:link
    【解决方案2】:

    快速解决方案是:

    {% if c.id_sitio_id == s.id_sitio %}
    

    因为Comprobante.id_sitio是一个外键,和一个自定义主键的模型相关,所以c.id_sitio_id_id是Django添加的一个后缀,用来保持主键的值,一般是id-大多数情况下的字段)存储Sitio.id_sitio的值。

    但我会重构您的代码,使其更清晰、更灵活,如下所示:

    # models.py
    class Comprobante(models.Model):
        sitio = models.ForeignKey('Sitio', on_delete=models.SET_NULL, blank=True, null=True)
    
    class Sitio(models.Model):
        name = models.CharField(max_length=100, blank=True, null=True)
    
    # in the template
    ...
    {% if s.id == c.sitio_id %}
    ...
    

    【讨论】:

    • 我在发帖时输入错误,但我现在使用 c.id_sitio_id 进行编辑,循环问题现已解决,但无论如何感谢您让我的代码更清晰,我会修复它:)
    【解决方案3】:

    可以使用Comprobanteclass中的相关名称属性

    class Comprobante(models.Model):
        id_sitio = models.ForeignKey(
            'Sitio', 
            models.DO_NOTHING, 
            related_name='comprobantes',
            db_column='id_sitio', blank=True, null=True)
    

    一旦设置了related_name,您就可以在模板中检查它

    {% block content %}
        {% for s in sitio %}
        <tr>
            <th scope="row">  {{ forloop.counter }}</th>
            <td> {{ s.sitio }} </td>
            <td>
            {% if s.comprobantes %}
                {# Hay un comprobante para el sitio #}
                <a href="">Checkouts</a>
            {% else %}
                <p>no payments</p>
            {% endif %}
            </td> 
        </tr> 
        {% endfor %}
    {% endblock %}
    

    希望对你有帮助

    【讨论】:

    • 我试过了,但它没有用,它总是去结帐,即使数据库中的 id 为空。无论如何,Tianissimo 的回答对我很有用。谢谢你。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-04-21
    • 1970-01-01
    • 2022-01-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多