从数据库中获取Django查询[初学者]
我会整理在Django中使用filter方法和get方法从数据库中获取数据的写法,因为我经常忘记。
这次,我将为初学者编写如何获取查询(Query)的方法,并附上简单的例子作为参考。
过去的文章:从数据库中获取并渲染。
环境
-
- 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的缩写)进行筛选,例如:
模型名称.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)
你可以通过「添加客户」进行添加。
在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 获取一对多和多对多的数据