当前位置: 首页 > 后端技术 > Python

DjangoNote23条件表达式查找、更新等操作

时间:2023-03-26 12:23:06 Python

本篇笔记将介绍条件表达式,即在模型的使用中如何根据不同的条件过滤数据并返回。这个操作类似于数据库中ifelifelse的逻辑。以下是本篇笔记的目录:模型和数据准备WhenandCaseoperationsAddnewfields返回条件SearchconditionsUpdateconditionsAggregation1、模型和数据准备本篇笔记我们使用的模型是Client,放在blog/models中.py下面是Client的模型定义:classClient(models.Model):REGULAR='R'GOLD='G'PLATINUM='P'ACCOUNT_TYPE_CHOICES=[(REGULAR,'Regular'),(GOLD,'Gold'),(PLATINUM,'Platinum'),]name=models.CharField(max_length=50)registered_on=models.DateField()account_type=models.CharField(max_length=1,choices=ACCOUNT_TYPE_CHOICES,default=REGULAR,)其中choices的操作在前面的字段类型中有介绍,这里不再赘述。那么migrate相关的操作这里就不多说了。接下来,插入一些数据并在shell中执行:fromblog.modelsimportClientClient.objects.create(name="client_1",registered_on="2020-01-01",account_type="R")Client.objects.create(name="client_2",registered_on="2021-07-12",account_type="G")Client.objects.create(name="client_3",registered_on="2022-09-20",account_type="P")Client.objects.create(name="client_4",registered_on="2022-12-07",account_type="P")下面介绍一下我们操作的知识点。2、When和Case操作的新字段返回我们使用的条件表达式使用的When和Case的函数,实际上对应SQL中的CASE和WHEN函数。先说说要求吧。当我们获取Client数据时,我们想知道这个数据的registered_ondate字段所在的季节。例如,一月是春天,七月是秋天。如何处理?很简单,先获取Client数据,然后根据registered_on字段判断月份,比如1、2、3之间就是Spring。这个方法是可行的,但是如果我们有另外一个需求,比如我们要过滤掉所有季节的Spring数据(这个例子其实不合适,因为这个操作,我们可以直接通过filter(registered_on__month__in=[1,2,3])来过滤,但是这里我们被迫使用filter(season='Spring')的形式来操作)那么这时候就可以使用我们的WhenCase用法了。在下面的操作中,我们通过判断registered_on字段的月份间隔得到一个新的字段:registered_on__month__in=[1,2,3],then=Value("Spring"),当(registered_on__month__in=[4,5,6],then=Value("Summer")),当(registered_on__month__in=[7,8,9],then=Value("Autumn")),When(registered_on__month__in=[10,11,12],then=Value("Winter")),default=Value("Spring")))在上面的In在代码中,我们使用annotate()创建一个新的季节字段。该字段的值根据registered_on的月份范围赋给季节。Case()函数包含四种When的可能性,然后每一种When()函数中都会有一个默认的默认值,前面一个是表达式,可以是这种形式,也可以用Q()语句,then=表示如果满足前面的表达式,那么value的内容就是后面的value。在value的定义中,我们这里使用了Value()函数,Value()表示它的值是一个字符串。获取字段值如果字段的值是为了获取某个字段的内容,比如Client中的name字段,则不需要Value()函数进行操作,直接使用即可:When(registered_on__month__in=[1,2,3],then="name")或使用F()函数获取字段值:fromdjango.db.modelsimportFWhen(registered_on__month__in=[1,2,3],then=F("name"))在不需要修改字段内容的情况下运行,以上两个命令的作用是一样的。3.条件搜索还是之前的要求。我们需要过滤Client的数据,过滤出季节为Spring的数据,然后在上面的操作中进行过滤。():results=Client.objects.annotate(season=Case(When(registered_on__month__in=[1,2,3],then=Value("Spring")),When(registered_on__month__in=[4,5,6],然后=值(“夏季”),当(registered_on__month__in=[7,8,9],然后=值(“秋季”)),当(registered_on__month__in=[10,11,12],然后=值(“冬季”)),default=Value("Spring"))).filter(season="Spring")根据条件过滤。对于Client模型,我们要实现这样一个查找条件:如果account_type的值为Client.GOLD,那么registered_on字段查找一个月之前的数据,如果account_typeClient.PLATINUM的值,然后registered_on字段搜索一年前的数据。对于这个需求,我们之前是怎么做的呢?使用Q()语法连接:fromblog.modelsimportClientfromdatetimeimportdate,timedeltafromdjango.db.modelsimportQa_month_ago=date.today()-timedelta(days=30)a_year_ago=date.today()-timedelta(days=365)condition=(Q(account_type=Client.GOLD)&Q(registered_on__lte=a_month_ago))|\(Q(account_type=Client.PLATINUM)&Q(registered_on__lte=a_year_ago))Client.objects.filter(condition)在这里,也可以使用我们的Case和When函数:Client.objects.filter(registered_on__lte=Case(When(account_type=Client.GOLD,then=a_month_ago),When(account_type=Client.PLATINUM,then=a_year_ago)))一个例子我之前在工作中遇到这样的需求,假设有一个TestModel,字段为field_1,它的值是A、B、C或者其他值,但是其他我们并不关心,需要按照B、C、A的顺序返回数据,所以我们可以在这里使用Case和When处理方法。我们可以通过条件得到一个新的字段优先级,然后order_by("priority")可以这样处理:TestModel.objects.annotate(priority=Case(When(field_1="B",then=1),When(field_1="C",then=2),When(field_1="A",then=3),default=4)).order_by("priority")4.条件更新除了前面的条件数据过滤,我们还可以根据条件更新数据。假设当前需求是有条件地更新registered_on字段的year:year为2020的account_type字段的内容变为Client。PLATINUM年份为2021的account_type字段的内容变为Client。REGULAR那么对应的代码应该是这样的:Client.objects.update(account_type=Case(When(registered_on__year=2020,then=Value(Client.PLATINUM)),When(registered_on__year=2021,then=Value(Client.REGULAR)),default=Value(Client.GOLD)))需要注意的是,在上面的代码中,我们没有对数据进行filter()操作,所以使用的是全表的数据,除2020以外的其他数据而2021年也会更新,如果只想操作2020年和2021年的数据,可以加上filter()条件限制:Client.objects.filter(registered_on__year__in=[2020,2021]).update(account_type=Case(When(registered_on__year=2020,then=Value(Client.PLATINUM)),When(registered_on__year=2021,then=Value(Client.REGULAR)),default=Value(Client.GOLD)))5.条件聚合现在我们需要根据条件聚合数据,例如Client模型,我们有根据account_type进行分组,获取总数的代码如下:fromdjango.db.modelsimportCount,QClient.objects.aggregate(regular=Count('pk',filter=(Q(account_type=Client.REGULAR))),gold=Count('pk',filter=Q(account_type=Client.GOLD)),platinum=Count('pk',filter=Q(account_type=Client.PLATINUM)),)返回结果:{'regular':1,'gold':0,'platinum':3}这个操作对应MySQL中的语句如下:selectcount(CASEWHENaccount_type='R'THENidELSEnullend)asregular,count(CASEWHENaccount_type='G'THENidELSEnullend)asgold,count(CASEWHENaccount_type='P'THENidELSEnullend)asplatinumFROMblog_client;我们也可以按照另一种方法获取各自的总数据,但是返回的结构不同:Client.objects.values("account_type").annotate(count=Count("account_type"))返回结果格式为:以上就是本笔记中条件表达式的全部内容。在接下来的几篇笔记中,会介绍模型的数据库功能。大体内容会是比较转换函数、日期函数、数据公式、文本函数等等。