GVKun编程网logo

Django原始SQL查询-遍历结果,它为每次迭代执行一个查询(django 原生sql)

13

最近很多小伙伴都在问Django原始SQL查询-遍历结果,它为每次迭代执行一个查询和django原生sql这两个问题,那么本篇文章就来给大家详细解答一下,同时本文还将给你拓展c#–存储库和使用原始sq

最近很多小伙伴都在问Django原始SQL查询-遍历结果,它为每次迭代执行一个查询django 原生sql这两个问题,那么本篇文章就来给大家详细解答一下,同时本文还将给你拓展c# – 存储库和使用原始sql查询?、django 1.8 官方文档翻译: 2-5-2 进行原始的sql查询、Django Rest API,它接受SQL查询并从数据库中返回执行查询的结果、Django 如何返回 object.filter 查询结果,这样我就不必遍历它们等相关知识,下面开始了哦!

本文目录一览:

Django原始SQL查询-遍历结果,它为每次迭代执行一个查询(django 原生sql)

Django原始SQL查询-遍历结果,它为每次迭代执行一个查询(django 原生sql)

在注意到Django的某些内置查询效率低下之后,一直在编写一些原始SQL查询。我试图遍历QuerySet结果并将其分组(我知道regroup模板标签,这对我不起作用-
我需要能够独立访问单独的组)。这是我的代码:

m = Media.objects.raw(''SELECT * FROM table'') # query simplified for sake of examplemedia_items = {''aim-icons'' : [], ''banners'' : [], ''hi-res-photos'' : [], ''photos'' : [], ''print-ads'' : [], ''videos'' : [], ''wallpapers'' : [] }for item in m:    media_items[item.type_slug].append(item)

这给了我我想要的东西(例如,我可以访问的列表media_items[''wallpapers'']),但是它为每次迭代运行一个数据库查询以获取type_slug字段。我尝试m= list(m)在循环之前添加,没有效果。

有人可以帮我从这里出去吗?这似乎应该很简单。

谢谢,马特

答案1

小编典典

编辑:

这里的问题归结为Djangoraw()方法的工作方式。它返回模型实例(具有您正在访问的属性,从而导致额外的查询)。

这里的适当工具connection.cursor()cursor.execute()cursor.fetchall()。这是文档中的示例:

def my_custom_sql():    from django.db import connection, transaction    cursor = connection.cursor()    # Data modifying operation - commit required    cursor.execute("UPDATE bar SET foo = 1 WHERE baz = %s", [self.baz])    transaction.commit_unless_managed()    # Data retrieval operation - no commit required    cursor.execute("SELECT foo FROM bar WHERE baz = %s", [self.baz])    row = cursor.fetchone()    return row

http://docs.djangoproject.com/en/dev/topics/db/sql/#executing-custom-sql-
direct

c# – 存储库和使用原始sql查询?

c# – 存储库和使用原始sql查询?

我正在努力了解如何最好地查询存储库.

现在让我通过循环的三个因素是:

>返回数据类型
>要运行查询的列
>要返回的记录数

第1点

关于问题一:

我有许多方法的存储库返回实体和标量值的组合.这似乎导致“方法爆炸”.我应该总是返回一个Entity对象吗?我该如何查询只需要一列的对象?

第2点
在运行查询时,我是否应该包括表中的每一列,即使我只需要一列或两列?如果我为此创建特定查询,则会导致存储库中有更多方法

第3点
我该如何为查询提供条件?我读到了有关规范的内容,但我的理解是您循环返回的记录并过滤掉传入新集合的记录.这似乎不是一个明智的表现.现在我只是在Repo中创建一个新方法,如getNameById(),它封装了条件.

请注意,我没有使用ORM,我只是在我的存储库中有原始sql.

更新

第1点:
根据答案和更多的研究,这将是一个很好的实施?

现在我有一个大型存储库,它返回标量和实体类型对象的混合(所有相同的实体).我想如果我只使用GetUser(userId)方法并忘记编写只返回单列值的方法,我可以大大减少这个.

例如,如果我需要返回一个用户名,我可以调用GetUser(userId)方法来润滑User对象,然后在服务层中将其过滤到用户名.

另一种方法是使用某种我可以传递到Repository的QueryBuilder类,可以对其进行解析以生成正确的sql.

第2点

回顾这一点非常类似于第一点,我目前的解决方案是只获取所有表字段.这是性能和可维护性之间的权衡.

第3点

我需要提供某种where子句.我不确定这是否有意义通过规范或只是一个sql字符串.我目前的解决方案是为这些类型创建新的方法,但我想要一些更通用的存储库

总的来说,仍然在研究这个……我希望能够听到更多关于这方面的信息,或者链接到书籍或参考文献,将这一切联系在一起.

解决方法

I have Repositories with lot of methods that return a combination of both Entities and scalar values. This seems to lead to “method explosion”. Should I always return an Entity object? How should I query for objects where I only need one column?

你可以对抗存储库方法爆炸,类似于你如何对抗其他SRP违规.您可以为同一实体创建另一个存储库.请参阅此answer以查找类似问题.

When running a query should I include every column in the table even if I only need one,or two columns? If I create specific queries for this it leads to more methods in the Repository

这不是DDD问题.域驱动设计不处理“行和列”.为加载域对象而加载的数据总是存在一些冗余,但您必须衡量这是否真的会影响您的性能.如果这确实是性能瓶颈而不是可能是域模型不正确的症状.

How should I provide conditions for the query? I read about Specifications,but my understanding is that you loop through the returned records and filter out the ones that pass into a new collection. This doesn’t seem like a good idea performance wise. Right Now I just make a new method in the Repo like getNameById() which encapsulates the condition.

这又是一个数据访问问题. DDD中没有任何内容表明您的存储库无法将Specification转换为SQL查询.无论您是这样做还是迭代内存中的记录(只要存储库使用者只看到规范和存储库并且不知道实际的实现),由您决定.

关于’原始sql与DDD中的ORM’,您可能会发现answer很有趣.

django 1.8 官方文档翻译: 2-5-2 进行原始的sql查询

django 1.8 官方文档翻译: 2-5-2 进行原始的sql查询

Django 文档协作翻译小组人手紧缺,有兴趣的朋友可以加入我们,完全公益性质。

交流群:467338606

网站:http://python.usyiyi.cn/django/index.html

进行原始的sql查询

模型查询API不够用的情况下,你可以使用原始的sql语句。django提供两种方法使用原始sql进行查询:一种是使用Manager.raw()方法,进行原始查询并返回模型实例;另一种是完全避开模型层,直接执行自定义的sql语句

警告

编写原始的sql语句时,应该格外小心。每次使用的时候,都要确保转义了参数中的任何控制字符,以防受到sql注入攻击。更多信息请参阅防止sql注入

进行原始查询

raw()方法用于原始的sql查询,并返回模型的实例:

Manager.raw(raw_query, params=None, translations=None)

这个方法执行原始的sql查询之后,返回django.db.models.query.RawQuerySet的实例。RawQuerySet实例可以像一般的QuerySet那样,通过迭代来提供对象的实例。

这里最好通过例子展示一下,假设存在以下模型:

class Person(models.Model):
    first_name = models.CharField(...)
    last_name = models.CharField(...)
    birth_date = models.DateField(...)

你可以像这样执行自定义的sql语句:

>>> for p in Person.objects.raw(''SELECT * FROM myapp_person''):
...     print(p)
John Smith
Jane Jones

当然,这个例子不是特别有趣,和直接使用Person.objects.all()的结果一模一样。但是,raw()拥有其它更强大的使用方法。

模型表的名称

在上面的例子中,Person表的名称是从哪里得到的?

通常,Django通过将模型的名称和模型的“应用标签”(你在manage.py startapp中使用的名称)进行关联,用一条下划线连接他们,来组合表的名称。在这里我们假定Person模型存在于一个叫做myapp的应用中,所以表就应该叫做myapp_person

更多细节请查看db_table选项的文档,它也可以让你自定义表的名称。

警告

传递给raw()方法的sql语句并没有任何检查。django默认它会返回一个数据集,但这不是强制性的。如果查询的结果不是数据集,则会产生一个错误。

警告

如果你在mysql上执行查询,注意在类型不一致的时候,mysql的静默类型强制可能导致意想不到的结果发生。如果你在一个字符串类型的列上查询一个整数类型的值,mysql会在比较前强制把每个值的类型转成整数。例如,如果你的表中包含值''abc''''def'',你查询''where mycolumn=0'',那么两行都会匹配。要防止这种情况,在查询中使用值之前,要做好正确的类型转换。

警告

虽然RawQuerySet可以像普通的QuerySet一样迭代,RawQuerySet并没有实现可以在QuerySet上使用的所有方法。例如,__bool__()__len__()RawQuerySet中没有被定义,所以所有RawQuerySet转化为布尔值的结果都是TrueRawQuerySet中没有实现他们的原因是,在没有内部缓存的情况下会导致性能下降,而且增加内部缓存不向后兼容。

将查询字段映射到模型字段

raw()方法自动将查询字段映射到模型字段。

字段的顺序并不重要。换句话说,下面两种查询的作用相同:

>>> Person.objects.raw(''SELECT id, first_name, last_name, birth_date FROM myapp_person'')
...
>>> Person.objects.raw(''SELECT last_name, birth_date, first_name, id FROM myapp_person'')
...

Django会根据名字进行匹配。这意味着你可以使用sql的as子句来映射二者。所以如果在其他的表中有一些Person数据,你可以很容易地把它们映射成Person实例。

>>> Person.objects.raw(''''''SELECT first AS first_name,
...                              last AS last_name,
...                              bd AS birth_date,
...                              pk AS id,
...                       FROM some_other_table'''''')

只要名字能对应上,模型的实例就会被正确创建。
又或者,你可以在raw()方法中使用翻译参数。翻译参数是一个字典,将表中的字段名称映射为模型中的字段名称、例如,上面的查询可以写成这样:

>>> name_map = {''first'': ''first_name'', ''last'': ''last_name'', ''bd'': ''birth_date'', ''pk'': ''id''}
>>> Person.objects.raw(''SELECT * FROM some_other_table'', translations=name_map)

索引访问

raw()方法支持索引访问,所以如果只需要第一条记录,可以这样写:

>>> first_person = Person.objects.raw(''SELECT * FROM myapp_person'')[0]

然而,索引和切片并不在数据库层面上进行操作。如果数据库中有很多的Person对象,更加高效的方法是在sql层面限制查询中结果的数量:

>>> first_person = Person.objects.raw(''SELECT * FROM myapp_person LIMIT 1'')[0]

延迟加载模型字段

字段也可以被省略:

>>> people = Person.objects.raw(''SELECT id, first_name FROM myapp_person'')

查询返回的Person对象是一个延迟的模型实例(请见 defer())。这意味着被省略的字段,在访问时才被加载。例如:

>>> for p in Person.objects.raw(''SELECT id, first_name FROM myapp_person''):
...     print(p.first_name, # This will be retrieved by the original query
...           p.last_name) # This will be retrieved on demand
...
John Smith
Jane Jones

从表面上来看,看起来这个查询获取了first_namelast_name。然而,这个例子实际上执行了3次查询。只有first_name字段在raw()查询中获取,last_name字符按在执行打印命令时才被获取。

只有一种字段不可以被省略,就是主键。Django 使用主键来识别模型的实例,所以它在每次原始查询中都必须包含。如果你忘记包含主键的话,会抛出一个InvalidQuery异常。

增加注解

你也可以在查询中包含模型中没有定义的字段。例如,我们可以使用PostgreSQL的age()函数来获得一群人的列表,带有数据库计算出的年龄。

>>> people = Person.objects.raw(''SELECT *, age(birth_date) AS age FROM myapp_person'')
>>> for p in people:
...     print("%s is %s." % (p.first_name, p.age))
John is 37.
Jane is 42.
...

raw() 方法中传递参数

如果你需要参数化的查询,可以向raw() 方法传递params参数。

>>> lname = ''Doe''
>>> Person.objects.raw(''SELECT * FROM myapp_person WHERE last_name = %s'', [lname])

params是存放参数的列表或字典。你可以在查询语句中使用%s占位符,或者对于字典使用%(key)占位符(key会被替换成字典中键为key的值),无论你的数据库引擎是什么。这样的占位符会被替换成参数表中正确的参数。

注意

SQLite后端不支持字典,你必须以列表的形式传递参数。

警告

不要在原始查询中使用字符串格式化!

它类似于这种样子:

>>> query = ''SELECT * FROM myapp_person WHERE last_name = %s'' % lname
>>> Person.objects.raw(query)

使用参数化查询可以完全防止sql注入,一种普遍的漏洞使攻击者可以向你的数据库中注入任何sql语句。如果你使用字符串格式化,早晚会受到sql输入的攻击。只要你记住默认使用参数化查询,就可以免于攻击。

直接执行自定义sql

有时Manager.raw()方法并不十分好用,你不需要将查询结果映射成模型,或者你需要执行UPDATEINSERT以及DELETE查询。

在这些情况下,你可以直接访问数据库,完全避开模型层。

django.db.connection对象提供了常规数据库连接的方式。为了使用数据库连接,调用connection.cursor()方法来获取一个游标对象之后,调用cursor.execute(sql, [params])来执行sql语句,调用cursor.fetchone()或者curser.fetchall()来返回结果行。

例如:

from django.db import connection

def my_custom_sql(self):
    cursor = connection.cursor()

    cursor.execute("UPDATE bar SET foo = 1 WHERE baz = %s", [self.baz])

    cursor.execute("SELECT foo FROM bar WHERE baz = %s", [self.baz])
    row = cursor.fetchone()

    return row

注意如果你的查询中包含百分号字符,你需要写成两个百分号字符,以便能正确传递参数:

cursor.execute("SELECT foo FROM bar WHERE baz = ''30%''")
cursor.execute("SELECT foo FROM bar WHERE baz = ''30%%'' AND id = %s", [self.id])

如果你使用了不止一个数据库,你可以使用django.db.connections来获取针对特定数据库的连接(以及游标)对象。django.db.connections是一个类似于字典的对象,允许你通过它的别名获取特定的连接

from django.db import connections
cursor = connections[''my_db_alias''].cursor()
# Your code here...

通常,Python DB API会返回不带字段的结果,这意味着你需要以一个列表结束,而不是一个字典。花费一点性能之后,你可以返回一个字典形式的结果,像这样:

def dictfetchall(cursor):
    "Returns all rows from a cursor as a dict"
    desc = cursor.description
    return [
        dict(zip([col[0] for col in desc], row))
        for row in cursor.fetchall()
    ]

下面是一个体现二者区别的例子:

>>> cursor.execute("SELECT id, parent_id FROM test LIMIT 2");
>>> cursor.fetchall()
((54360982L, None), (54360880L, None))

>>> cursor.execute("SELECT id, parent_id FROM test LIMIT 2");
>>> dictfetchall(cursor)
[{''parent_id'': None, ''id'': 54360982L}, {''parent_id'': None, ''id'': 54360880L}]

连接和游标

连接和游标主要实现PEP 249中描述的Python DB API标准,除非它涉及到事务处理。

如果你不熟悉Python DB-API,注意cursor.execute()中的sql语句使用占位符"%s",而不是直接在sql中添加参数。如果你使用它,下面的数据库会在必要时自动转义你的参数。

也要注意Django使用"%s"占位符,而不是SQLite Python绑定的"?"占位符。这是一致性和可用性的缘故。

Django 1.7中的改变。

PEP 249并没有说明游标是否可以作为上下文管理器使用。在python2.7之前,游标可以用作上下文管理器,由于魔术方法lookups中意想不到的行为(Python ticket #9220)。Django 1.7 显式添加了对允许游标作为上下文管理器使用的支持。

将游标作为上下文管理器使用:

with connection.cursor() as c:
    c.execute(...)

等价于:

c = connection.cursor()
try:
    c.execute(...)
finally:
    c.close()

Django Rest API,它接受SQL查询并从数据库中返回执行查询的结果

Django Rest API,它接受SQL查询并从数据库中返回执行查询的结果

哦,老实说,这听起来有点危险,希望您知道自己在做什么;)如果要允许人们将自己的查询写到您的数据库中,则必须考虑一下安全性。那。

但是我建议您阅读本文档here中有关执行原始SQL查询的信息。

Django 如何返回 object.filter 查询结果,这样我就不必遍历它们

Django 如何返回 object.filter 查询结果,这样我就不必遍历它们

如何解决Django 如何返回 object.filter 查询结果,这样我就不必遍历它们?

我试图从查询中只返回一个结果并将其作为对象返回,这样我就可以在模板中调用它的属性,而不必遍历它们。

基本上,我有一个登录页面,它迭代 table1 上的对象列表,并为每个对象创建一个链接,例如产品列表。当我单击一个链接时,它会在页面上显示来自该对象的数据。我还想显示 table2 上对象的数据,该对象具有我当前所在页面的对象的外键。

问题是我正在从 table2 返回一个可迭代的项目,所以为了呈现该数据,我必须运行一个 for 循环。它只返回一个项目,所以它不会对页面的外观产生影响,但我想在没有 for 循环的情况下完成同样的事情。

models.py

class Exercises(models.Model):
    exercise = models.CharField(max_length=45)
    evolution = models.CharField(max_length=8)
    start_date = models.DateTimeField(blank=True,null=True)
    end_date = models.DateTimeField(blank=True,null=True)
    logo = models.TextField(blank=True,null=True)

    class Meta:
        constraints = [
            models.UniqueConstraint(
                fields=[''exercise'',''evolution''],name=''exercise_evolution_UNIQUE'')
        ]

    def __str__(self):
        return f"Exercise: {self.exercise}\t Evolution: {self.evolution}"


class Units(models.Model):
    uic = models.CharField(max_length=10)
    unit_name = models.CharField(unique=True,max_length=45)
    mcc = models.CharField(max_length=5,blank=True,null=True)
    ruc = models.CharField(max_length=10,null=True)
    personnel = models.IntegerField(blank=True,null=True)

    class Meta:
        constraints = [
            models.UniqueConstraint(
                fields=[''uic'',''mcc'',''ruc''],name=''uic_mcc_ruc_UNIQUE'')
        ]

    def __str__(self):
        return f"UIC: {self.uic}\tName: {self.unit_name}"

class ExercisePersonnel(models.Model):
    exercise = models.ForeignKey(''Exercises'',models.CASCADE)
    unit = models.ForeignKey(''Units'',models.CASCADE)
    location = models.ForeignKey(''Locations'',models.RESTRICT)
    quantity = models.IntegerField()

我正在尝试将 ExercisePersonnel 属性传递到我的模板中

views.py

from django.shortcuts import get_object_or_404,render,redirect
from django.http import HttpResponse
from django.http import Http404
from django.template import loader
from django.contrib.auth.forms import UserCreationForm
from django.contrib import messages
from django.contrib.auth import authenticate,login,logout
from django.forms import ModelForm

from .models import Exercises,Units,ExerciseEdl,ExercisePersonnel,UnitEdl
from .forms import RegistrationForm,AccountAuthenticationForms,ExerciseForm,UnitForm,ExerciseEdlForm,ExercisePersonnelForm

def exercise_detail(request,pk,*args,**kwargs):
    print(request)
    ex_name = Exercises.objects.get(pk=pk)
    person = ExercisePersonnel.objects.filter(exercise=pk)
    print(person)
    print(ex_name)
    
    context = {
        ''ex_name'': ex_name,''person'': person,}
    return render(request,''exercise/exercise_detail.html'',context)

这些声明 打印(人) 打印(ex_name)

渲染练习对象“Iron Dong”的模板时产生此输出

]> web_1 |练习:铁东进化:21-1

对象''MEFEX''的这个输出

]> web_1 |练习:MEFEX 进化:21-2

这意味着 print(person) 正在返回一个字典对象,对吗?我如何让它以与 print(ex_name) 相同的方式返回对象?

我的模板

<div>
      <div>
        <h3>{{ ex_name.exercise }}</h3>
      </div>
      <div>
        <div>
          <div>
            <div>
              <a href="{% url ''exercise-edl'' ex_name.pk %}">
                <button>EDL</button>
              </a>
            </div>
            <div>
              <a href="{% url ''exercise-edit'' ex_name.pk %}">
                <button>Edit</button>
              </a>
            </div>
            <div>
              <a data-bs-toggle="modal" data-bs-target="#exampleModal">
                <button>Delete</button>
              </a>
              <!-- Modal -->
              <divid="exampleModal" tabindex="-1" aria-labelledby="exampleModalLabel" aria-hidden="true">
                <div>
                  <div>
                    <div>
                      <h5id="exampleModalLabel">Delete Exercise?</h5>
                      <button type="button"data-bs-dismiss="modal" aria-label="Close"></button>
                    </div>
                    <div>
                      Are you sure you want to delete this exercise
                    </div>
                    <div>
  
                      <formaction="{% url ''exercise-delete'' ex_name.pk %}" method="POST">
  
                        {% csrf_token %}
                        <buttontype="submit" value="Delete exercise">Delete Exercise</button>
                      </form>
                    </div>
                  </div>
                </div>
              </div>
            </div>
          </div>          
        </div>
        <div>
        </div>
      </div>    
    </div>
    <div>
      <h5>
        Evolution: {{ex_name.evolution}}
      </h5>
    </div>
    <div>
      <p5>
        Start Date: {{ex_name.start_date}}
      </p5>
    </div>
    <div>
      <p5>
        End Date: {{ex_name.end_date}}
      </p5>
    </div>
    <div>
      {% for p in person %}
      <p>
        {{p.quantity}}
      </p>
      {% endfor %}
    </div>

解决方法

暂无找到可以解决该程序问题的有效方法,小编努力寻找整理中!

如果你已经找到好的解决方法,欢迎将解决方案带上本链接一起发送给小编。

小编邮箱:dio#foxmail.com (将#修改为@)

今天关于Django原始SQL查询-遍历结果,它为每次迭代执行一个查询django 原生sql的介绍到此结束,谢谢您的阅读,有关c# – 存储库和使用原始sql查询?、django 1.8 官方文档翻译: 2-5-2 进行原始的sql查询、Django Rest API,它接受SQL查询并从数据库中返回执行查询的结果、Django 如何返回 object.filter 查询结果,这样我就不必遍历它们等更多相关知识的信息可以在本站进行查询。

本文标签:

上一篇远程连接到clearDB heroku数据库(连接远程数据库命令)

下一篇使用ng-bind-html和$ sce.trustAsHtml创建具有ng-model绑定的字符串(使用new创建对象之外,还可以用_________方法创建对象)