【问题标题】:Django: Update multiple objects with regexDjango:使用正则表达式更新多个对象
【发布时间】:2012-09-11 14:10:23
【问题描述】:

我想根据thisthis 文档从多个对象的slug 字段中删除'blog/' 子字符串:

>>> import re
>>> from django.db.models import F
>>> p = re.compile('blog/')
>>> Blog.objects.update(slug=p.sub('', F('slug')))
Traceback (most recent call last):
  File "<console>", line 1, in <module>
TypeError: expected string or buffer

我尝试将str() 添加到最后一个字符串,它通过而没有错误:

>>> Blog.objects.update(slug=p.sub('', str(F('slug'))))

但它会将(DEFAULT: ) 插入到所有对象的slug 字段中。

有什么建议吗?

【问题讨论】:

    标签: django django-queryset


    【解决方案1】:

    要在 Django 中使用正则表达式在查询集上一次更新多个对象,您可以使用 Func expression 访问数据库中的正则表达式函数:

    django.db.models import F, Func, Value
    
    
    pattern = Value(r'blog(/?)')  # the regex
    replacement = Value(r'new-blog-slug\1')  # replacement string
    flags = Value('g')  # regex flags
    
    Blog.objects.update(
        slug=Func(
            models.F('slug'),
            pattern, replacement, flags,
            function='REGEXP_REPLACE',
            output_field=models.TextField(),
        )
    )
    

    查看您的数据库供应商文档以获取详细信息和特定功能支持。

    patternreplacement 中使用原始字符串r'' 以避免转义反斜杠。

    使用\nn 从1 到9 引用replacement 中的匹配子字符串。

    您可以使用F 表达式从每个实例的字段中提供patternreplacementflags

    pattern = F('pattern_field')
    replacement = F('replacement_field')
    flags = F('flags_field')
    

    您还可以使用Func 表达式进行注释。

    目前有一个open pull request 在Django 中添加正则表达式数据库功能。合并后,您可能会在 django.db.models.functions 下拥有 RegexpReplaceRegexpStrIndexRegexpSubstr 函数表达式,以使您的代码更简洁,并在数据库供应商之间拥有一个统一的 API。

    【讨论】:

    • 没错。使用正则表达式在一个查询中更新 db 的唯一解决方案。
    【解决方案2】:

    你不能那样做。更新完全在数据库中完成,因此它必须是可转换为 SQL 的东西,而您的代码不能。您需要遍历和更新:

    for blog in Blog.objects.filter(slug__startswith='blog/'):
        blog.slug = blog.slug.replace('blog/', '')
        blog.save()
    

    【讨论】:

    • 感谢您的回答,它有效。但是你为什么说我做不到呢? update() method 直接转换为 SQL,它不运行 save() 方法或发出 post_save 信号 - 正是我需要的,因为我不希望 save() 和信号完成额外的工作。我测试了我的代码,直到我添加了re.sub()
    • 嗯,没错,re.sub() 是 Python,因此无法转换为 SQL。
    • 听到这个消息很难过。此代码迭代 13K 记录约 15 分钟。谢谢你的解释。
    • 可以在数据库级别进行正则表达式替换,我添加了一个带有进一步解释的答案。
    【解决方案3】:

    有点晚了,但对于那些今天需要解决方案的人来说 注意:Django 2.1 中的新功能。

    类替换

    来自Documentation的用法示例:

    >>> from django.db.models import Value
    >>> from django.db.models.functions import Replace
    >>> Author.objects.create(name='Margaret Johnson')
    >>> Author.objects.create(name='Margaret Smith')
    >>> Author.objects.update(name=Replace('name', Value('Margaret'), Value('Margareth')))
    2
    >>> Author.objects.values('name')
    <QuerySet [{'name': 'Margareth Johnson'}, {'name': 'Margareth Smith'}]>
    

    【讨论】:

    • 不错! 1.113 秒 18K 记录!选择这个作为接受的答案。
    • 使用Replace 很简单,适合问题中发布的示例,但答案并未完全涵盖问题,因为Replace 不支持正则表达式。我发布了一个答案,其中包含我找到的获得正则表达式支持的解决方案。
    • @LuisSolis 很遗憾您的回答被否决了,它为问题中发布的示例提供了解决方案,并包含指向正则表达式支持的参考。看来我无法恢复它,我很抱歉。
    猜你喜欢
    • 2011-08-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-12-24
    • 1970-01-01
    • 2011-01-31
    • 2017-10-08
    相关资源
    最近更新 更多