从数据库中获取Django查询[初学者]

我会整理在Django中使用filter方法和get方法从数据库中获取数据的写法,因为我经常忘记。

这次,我将为初学者编写如何获取查询(Query)的方法,并附上简单的例子作为参考。

:heavy_check_mark:

过去的文章:从数据库中获取并渲染。

 

image.png

环境

    • Python 3.8.5

 

    Django 3.1

我们根据附录中所述的数据模型创建了环境并进行了实验。

获取:获取一个数据。

get和filter有一些相似之处,但也有一些不同之处。我在补充说明中也提到了这一点。

    • 単体のオブジェクト取得

 

    • 1件も取得できないと例外発生

 

    即座にDBから取得

根据条件输入获取模型名为”モデル名”的对象。

Customer.objects.get(id=1)

如果要使用主键(如id),可以使用pk。
可以用模型名.objects.get(pk=’條件輸入’)。

Customer.objects.get(pk=1)

可以得到的结果是相同的。

如果有人不太明白的话,
那就是在确保始终能取得一份数据的情况下使用。

和QuerySet不同的是,它不需要一个一个地像列表一样提取数据就可以使用。

customer = Customer.objects.get(pk=customer_id)
if(customer.age < 20):
    pass

只需要记住大概的也许就可以了。

可以顺便将filter和get结合使用。如果filter只返回一个数据,可以使用get()方法。

2. 查询集合:获取多条数据

get和filter有所不同。我也在附注中写了这一点。

    • 複数のオブジェクト取得

 

    • 0件取得でもエラー出ない。カラのデータということになる

 

    即座に取得しない。for, printなどなどデータ見ないと処理できないような特定の処理されたときにDBに問い合わせる。>> # 慣れてきたら知っておくといいこと

嗯,對於不太理解的人,暫時來說,
「QuerySet是類似於列表的東西,可以用來檢索和獲取數據」
「不同於.get(),即使無法獲取數據也不會產生錯誤。有時候這非常方便」

也许可以随便记一下。

2.1 全部:获取所有的数据

当想要获取表中的所有数据时。

customers = Customer.objects.all()

会在多个对象(QuerySet)中进行获取。
类似于 SQL 中的 SELECT * FROM oooo; 的操作。在实际开发中可能不常使用。

2.2 数据检索总结-使用QuerySet的filter方法查询数据

当我们想要获取多个对象(QuerySet)并附加条件时,经常使用该方法。

完全相同

根据条件输入获取模型名.objects.filter(field=’条件输入’)
例如:获取name为Sato的数据

customers = Customer.objects.filter(name='Sato')

获取与姓名为Sato匹配的数据

2.2.1 AND条件的意思是两个条件同时满足

使用多个条件进行筛选。只需用逗号将其连接起来.
使用模型名.objects.filter(field1=’条件输入1′, field2=’条件输入2′)。

取得名字为Sato,年龄为50的数据。

customers = Customer.objects.filter(name='Sato', age=50)

2.2.2 或条件

导入了django.db.models模块之后,使用Q来表示或操作会稍微有些复杂。

获取满足名称为Sato或年龄为50的数据。

from django.db.models import Q 

customers = Customer.objects.filter(Q(name='Sato') | Q(age=50))

2.2.3 在哪里 (IN Sentence)

有一种方法是给筛选器添加条件,但是通过将条件传递给列表,可以很聪明地编写代码,以获取与条件匹配的数据。

模型名.objects.filter(field__in=[列表数据])

如果name是Sato、Takahashi或Tanaka之一,就获取它。

customers = Customer.objects.filter(name__in=['Sato', 'Takahashi', 'Tanaka'])

只需准备并提供一个清单就可以制作。非常方便。

2.2.4 使用不等符号的条件 (“>”, “<“, “>=”, “<=”)

使用不等号来构建条件。

意味gt(greater than) 超gte(greater than equal) 以上lt(less than) 未満lte(less than equal) 以下

超过

如下所示,用中文进行本地化的改写,仅提供一种选项:
使用两个下划线和gt(greater than的缩写)进行筛选,例如:
模型名称.objects.filter(field__gt=’条件’)。
例如:如果是”年龄大于20″(age > 20)。

customers = Customer.objects.filter(age__gt=20)

大于等于

模型名.objects.filter(field__gte=’条件’)
用两个下划线和gte(大于等于的缩写)。
例:“年龄大于等于20”(age >= 20)则

customers = Customer.objects.filter(age__gte=20)

不到

模型名.objects.filter(field__lt=’条件’)
_(下划线)两个和lt(小于的缩写)。
例:如果 “年龄小于10” (age < 10)

customers = Customer.objects.filter(age__lt=10)

以下(不超过)

假设模型名.objects.filter(字段__lte=’条件’),其中有两个下划线和lte(表示小于等于)。
例如:如果是”年龄小于等于10″(age <= 10),可以这样写。

customers = Customer.objects.filter(age__lte=10)

2.2.5 BETWEEN句:范围句

模型名.objects.filter(field__range=(start, end))
_(底线)重复两次,并且指定了range数值的范围或日期时间范围为start和end。

查询对象 Sample 中字段 field 值在 start 和 end 之间的数据。

在SQL中,age BETWEEN 0 AND 20,即表示0 ≤ age 且 age ≤ 20。

customers = Customer.objects.filter(age__range=(0, 20))

2.2.6 LIKE Clause:
2.2.6 LIKE子句

没有”LIKE”这个词,只需用两个下划线和文字填充。

某些事物相似

注意,因为有大小写的区别。

有大小写的区别。

模型名.objects.filter(字段__contains=’条件’)

如果名字中包含字母组合“sa”,则获取。

customers = Customer.objects.filter(name__contains='sa')

大写和小写字母无区别

模型名.objects.filter(字段__icontains=’条件’)

如果名字包含Sa、SA或sa,都可以获取。

customers = Customer.objects.filter(name__contains='sa')

一致的方向往前方看去

文字大小有区别

有大小写区别。

(Note: This translation assumes that “大小写” refers to “capitalization,” which is commonly used in Chinese to describe the distinction between uppercase and lowercase letters.)

取得以字母’T’开头的名字的模型名称。例如:
ModelName.objects.filter(name__startswith=’T’)

customers = Customer.objects.filter(name__startwith='T')

大小写不区分

获取以字母T开头的名字,例如TA、ta、Ta、tA。

customers = Customer.objects.filter(name__istartwith='Ta')

后方保持统一

区分大小写文字

大小写有区别

获取以字母a结尾的名称:モデル名.objects.filter(name__endwith=’a’) 的一个示例。

customers = Customer.objects.filter(name__endwith='a')

大小写无区别。

从模型中获取以KA、ka、Ka或kA结尾的名称。

customers = Customer.objects.filter(name__iendswith='ka')

完全一致(不区分大小写)

有两个下划线以及iexact

使用模型名.objects.filter(field__iexact=’条件’)进行过滤。

只要名称匹配,无论是Sato、SATO还是sato都可以获取。

customers = Customer.objects.filter(neme__iexact='sato')

2.2.7 搜索 NULL (IS NULL)、排除 (IS NOT NULL)

模型名.objects.filter(field__isnull=True) 中的“__isnull=True”表示字段为空。

用这种方法获取NULL。

模型名称.objects.filter(field__contains=’_’)

现在,将NULL排除掉。

获取age为NULL的数据

customers = Customer.objects.filter(age__isnull=True)

2.2.8 排序: 数据排序

可以将数据连接到queryset的数据并进行排序。我认为它可以像SQL中的order_by一样使用,因此很容易理解。

Customer.objects.all().order_by('id') # idカラム昇順で並べ替え
Customer.objects.all().order_by('-id') # idカラム降順で並べ替え
Customer.objects.all().order_by('id', 'age')  # idを並べ替えた後にageでも

默认是升序排列,加上“-”可以改为降序排列。
如果写多个,则按顺序排列。
要进行更详细的排序,请参考官方页面。

请点击以下链接查看关于 Django 模型查询集 `order_by` 方法的官方文档:https://docs.djangoproject.com/ja/3.2/ref/models/querysets/#django.db.models.query.QuerySet.order_by

2.2.9 计数:获取数据数量

可以获取数据的数量。
在不使用如下内置函数count()的情况下,请使用Queryset的count来实现。

customers = Customer.objects.all()
count = count(customers)

只需要一种选项:
我们不要再用这个了。

count = Customer.objects.all().count()

2.2.10 的存在:是存在的吗?(可以用 True 或 False 回答)

在某些情况下,使用if条件非常方便。 如果没有数据,可以将其判定为“没有数据”的显示,非常方便。

如果存在10岁以下的数据,则为真,因此在条件中进行处理。

if Customer.objects.filter(age__lte=10).exists()
    pass

2.2.11 排除:获取时排除条件

不包括。也就是说,与筛选相反,即条件反转。

只获取10岁以下的数据

customers = Customer.objects.exclude(age__lte=10)

2.2.12首先:获取查询集的第一条数据

用十岁以下的数据获取第一个数据。

customers = Customer.objects.filter(age__lte=10).order_by('created_at').first()

请以中文同义短语表达以下内容,仅需要一种选择:

customers = Customer.objects.filter(age__lte=10).order_by('created_at')[0]

2.2.13 最后:获取查询集的最后一条数据

这是与”first”相反的情况。

customers = Customer.objects.filter(age__lte=10).order_by('created_at').last()

以下相同意。只是order_by的顺序变了。

customers = Customer.objects.filter(age__lte=10).order_by('-created_at')[0]

2.2.14 限制:指定获取的数量

モデル名.objects.all()[:5] # 5件取得(Limit 5)
モデル名.objects.all()[5:10] # 5~10件を取得(OFFSET 5 LIMIT 5)

可以叠加各种条件

在使用count和exists等连接字时,可以将搜索条件和排序等拼接在一起。

Customer.objects.all().order_by('id') # idカラム昇順で並べ替え
Customer.objects.all().order_by('-id') # idカラム降順で並べ替え
Customer.objects.all().filter(name='Sato').reverse() # 佐藤さん取得。Querysetデータを逆にして取得
Customer.objects.all().filter(name='Sato').count() # 佐藤さんの数カウント
Customer.objects.values('email').distinct() # emailカラムの重複データは除去

可以将queryset放入变量中并进行拼接。

queryset = Customer.objects.filter(name='Sato')
queryset = queryset.filter(age__lte=10)

如果使用”if”等条件语句,可以动态地添加条件。

将获取的数据进行处理并转换为其他格式。

想要获取值:使用字典(辞書型)获取。

从数据库获取数据时,以字典形式进行获取更便于处理等方面存在的好处。

请参考链接:https://docs.djangoproject.com/ja/3.1/ref/models/querysets/#values

>>> Blog.objects.filter(name__startswith='Beatles').values()
<QuerySet [{'id': 1, 'name': 'Beatles Blog', 'tagline': 'All the latest Beatles news.'}]>

如果以常规方式获取,需要用for循环遍历QuerySet来提取数据,但是由于返回的是一个字典,所以很难进行加工。但是如果按照上述方式添加value,就可以将记录的内容以字典的形式获取并使用。

如果键值对不必要的话,可以通过元组获取values_list。

values_list与values相似,但仅返回值。

请参考这个链接:https://docs.djangoproject.com/ja/3.1/ref/models/querysets/#values-list

当需要进行分析、将数据写入CSV文件、或者在使用库时需要以列表方式传递数据,以及存在键值对可能会造成干扰的情况时。

>>> Entry.objects.values_list('id', 'headline')
<QuerySet [(1, 'First entry'), ...]>
>>> from django.db.models.functions import Lower
>>> Entry.objects.values_list('id', Lower('headline'))
<QuerySet [(1, 'first entry'), ...]>

在希望取得符合条件的ID(主键)数字的列表时,指定flat=True会很方便。
如果希望将其转换为简单的列表而非QuerySet,可以使用list()函数。

>>> Entry.objects.all().values_list('pk', flat=True))
<QuerySet [1, 2, ...]>
# リストにする all()をfilter()にすれば条件絞り込み可能
>>> list(Entry.objects.all().values_list('pk', flat=True)))
[1, 2, ...]

填补缺编

以下是附加说明。如果你想练习从数据库获取数据,可以试试这个功能。

如果要在Django中进行CRUD操作,可以尝试在shell中进行确认。

由于每次都要确认页面上的显示很麻烦,所以我们尝试使用shell。

我顺便提一下,如果你安装了一个叫做shell_plus的东西,会很方便,所以你可以使用它。

准备

这次使用的模型是这个样子的。
应用名称是accounts。

class Customer(models.Model):
    name = models.CharField(max_length=100)
    phone = models.CharField(max_length=20)
    email = models.CharField(max_length=255)
    age = models.IntegerField()
    created_at = models.DateTimeField(auto_now_add=True)

制作练习用的应用程序并添加数据的方法。

这次是为了应付而制作的。
※manage.py中记录了各种功能。使用manage.py时,请先切换到目录再使用。

$ django-admin startproject django_docker
$ cd django_docker
$ python manage.py startapp accounts

编辑settings.py文件

将应用程序添加到项目中。

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',

    'accounts', # 追加
]

刚才写的models.py的代码

$ python manage.py makemigrations
$ python manage.py migrate

如果已经有数据,就继续下一步。
如果没有数据,

 

有人认为可以像fixture一样添加初始数据,或者通过管理页面进行注册。

$ python manage.py createsuperuser

创建管理界面时,随意填写用户信息并将其设为超级用户。若不在admin.py中注册,将无法显示。

from django.contrib import admin
from .models import Customer

admin.site.register(Customer)
スクリーンショット 2020-09-21 0.35.07.png

你可以通过「添加客户」进行添加。

在shell中获取Django的数据并进行测试。

$ python manage.py shell

请导入(import)模型,否则无法使用。

>>> from accounts.models import *
>>> customer = Customer.objects.all()
>>> customer
<QuerySet [<Customer: Sato>, <Customer: Tanaka>]>

你可以以这种方式获取。

获取和筛选

如果使用get()函数无法获取数据,将会返回DoesNotExist错误。
如果使用filter()函数无法获取数据,将会返回空的查询集(Queryset)。

我来看一个例子。

>>> customer_filter = Customer.objects.filter(id=1)
>>> customer_filter
<QuerySet [<Customer: Sato>]>
>>> customer_get = Customer.objects.get(id=1)
>>> customer_get
<Customer: Sato>

当我们使用 QuerySet 时,可以认为它是一组数组、一组记录,或者说是一组数据模型的集合。
通过 filter 方法获取的 QuerySet 需要通过 for 循环逐个取出。

如果使用customer_filter.name,就会出现错误。
而customer_get.name会正确处理。简单来说,QuerySet是一种将可以用get获取的数据整合在一起的方式,它包含了很多个数据。
所以,我们可以使用for循环逐个提取,以相同的方式进行处理。

>>> customer_filter = Customer.objects.filter(id=1)
>>> customer_filter.name

Traceback (most recent call last):
  File "<console>", line 1, in <module>
AttributeError: 'QuerySet' object has no attribute 'name'

>>> customer_filter = Customer.objects.filter(id=1)
>>> for c in customer_filter:
...     c.name
... 
'Sato'

get的DoesNotExist

当你能够获取到确实的数据时,如果希望处理情况异常(DoesNotExist)时出现异常,请使用get。

try:
    user = User.objects.get(pk=id)
    # ここに何か書く
except User.DoesNotExist:
     pass

当你逐渐熟悉之后,知道这些事情就会很有帮助。

如果只是创建查询集,没有访问数据库。

>>> q = accounts.objects.filter(name__startswith="T")
>>> q = q.filter(created_at__lte=datetime.date.today())
>>> q = q.exclude(age__gte=30)
>>> print(q)

看起来好像有3次访问数据库,但实际上只有最后的print(q)进行了一次。
尽管在开发规模较小的情况下可能会被忽视,但由于多次向数据库发送重复的繁重处理,仍然引起了我的关注,所以我写了这段话。

如果在filter中只有一条数据,可以使用get()。

在下面的条件下,可以肯定的是只能获取一个结果。将其提取出来,这样做有点冗长。

customer = Customer.objects.filter(id=1)
print(customer[0])

使用get()。其优点包括

    • 1行でスッキリ一つのデータ取り出せる

 

    • データが2つ存在したらエラー出してくれる

 

    なかったらエラー出してくれる
customer = Customer.objects.filter(id=1).get()
print(customer)

# データ二つなのでエラー出る
customer = Customer.objects.filter(id__in=[1,2]).get()
apps.customers.models.Contract.MultipleObjectsReturned: get() returned more than one Contract -- it returned 2!

请提供更多上下文,以便我可以准确地在中文中进行阐述。

下面是一个链接,其中包含有关Django数据库查询的指南:
https://docs.djangoproject.com/ja/3.1/topics/db/queries/

这是另一个链接,提供有关Django模型查询集的参考文档:
https://docs.djangoproject.com/ja/3.1/ref/models/querysets/

将来我会随时添加更多内容。

继续:关系

[Django查询数据库] #2 获取一对多和多对多的数据

广告
将在 10 秒后关闭
bannerAds