mirror of
				https://github.com/django/django.git
				synced 2025-10-31 09:41:08 +00:00 
			
		
		
		
	Refs #28643 -- Added MD5 database function.
Thanks Tim Graham, Nick Pope and Simon Charette for reviews.
This commit is contained in:
		| @@ -4,6 +4,7 @@ SQLite backend for the sqlite3 module in the standard library. | ||||
| import datetime | ||||
| import decimal | ||||
| import functools | ||||
| import hashlib | ||||
| import math | ||||
| import operator | ||||
| import re | ||||
| @@ -217,6 +218,7 @@ class DatabaseWrapper(BaseDatabaseWrapper): | ||||
|         conn.create_function('LN', 1, none_guard(math.log)) | ||||
|         conn.create_function('LOG', 2, none_guard(lambda x, y: math.log(y, x))) | ||||
|         conn.create_function('LPAD', 3, _sqlite_lpad) | ||||
|         conn.create_function('MD5', 1, none_guard(lambda x: hashlib.md5(x.encode()).hexdigest())) | ||||
|         conn.create_function('MOD', 2, none_guard(math.fmod)) | ||||
|         conn.create_function('PI', 0, lambda: math.pi) | ||||
|         conn.create_function('POWER', 2, none_guard(operator.pow)) | ||||
|   | ||||
| @@ -10,8 +10,9 @@ from .math import ( | ||||
|     Mod, Pi, Power, Radians, Round, Sin, Sqrt, Tan, | ||||
| ) | ||||
| from .text import ( | ||||
|     Chr, Concat, ConcatPair, Left, Length, Lower, LPad, LTrim, Ord, Repeat, | ||||
|     Replace, Reverse, Right, RPad, RTrim, StrIndex, Substr, Trim, Upper, | ||||
|     MD5, Chr, Concat, ConcatPair, Left, Length, Lower, LPad, LTrim, Ord, | ||||
|     Repeat, Replace, Reverse, Right, RPad, RTrim, StrIndex, Substr, Trim, | ||||
|     Upper, | ||||
| ) | ||||
| from .window import ( | ||||
|     CumeDist, DenseRank, FirstValue, Lag, LastValue, Lead, NthValue, Ntile, | ||||
| @@ -33,8 +34,8 @@ __all__ = [ | ||||
|     'Exp', 'Floor', 'Ln', 'Log', 'Mod', 'Pi', 'Power', 'Radians', 'Round', | ||||
|     'Sin', 'Sqrt', 'Tan', | ||||
|     # text | ||||
|     'Chr', 'Concat', 'ConcatPair', 'Left', 'Length', 'Lower', 'LPad', 'LTrim', | ||||
|     'Ord', 'Repeat', 'Replace', 'Reverse', 'Right', 'RPad', 'RTrim', | ||||
|     'MD5', 'Chr', 'Concat', 'ConcatPair', 'Left', 'Length', 'Lower', 'LPad', | ||||
|     'LTrim', 'Ord', 'Repeat', 'Replace', 'Reverse', 'Right', 'RPad', 'RTrim', | ||||
|     'StrIndex', 'Substr', 'Trim', 'Upper', | ||||
|     # window | ||||
|     'CumeDist', 'DenseRank', 'FirstValue', 'Lag', 'LastValue', 'Lead', | ||||
|   | ||||
| @@ -150,6 +150,22 @@ class LTrim(Transform): | ||||
|     lookup_name = 'ltrim' | ||||
|  | ||||
|  | ||||
| class MD5(Transform): | ||||
|     function = 'MD5' | ||||
|     lookup_name = 'md5' | ||||
|  | ||||
|     def as_oracle(self, compiler, connection, **extra_context): | ||||
|         return super().as_sql( | ||||
|             compiler, | ||||
|             connection, | ||||
|             template=( | ||||
|                 "LOWER(RAWTOHEX(STANDARD_HASH(UTL_I18N.STRING_TO_RAW(" | ||||
|                 "%(expressions)s, 'AL32UTF8'), '%(function)s')))" | ||||
|             ), | ||||
|             **extra_context, | ||||
|         ) | ||||
|  | ||||
|  | ||||
| class Ord(Transform): | ||||
|     function = 'ASCII' | ||||
|     lookup_name = 'ord' | ||||
|   | ||||
| @@ -1303,6 +1303,26 @@ Usage example:: | ||||
| Similar to :class:`~django.db.models.functions.Trim`, but removes only leading | ||||
| spaces. | ||||
|  | ||||
| ``MD5`` | ||||
| ------- | ||||
|  | ||||
| .. class:: MD5(expression, **extra) | ||||
|  | ||||
| .. versionadded:: 3.0 | ||||
|  | ||||
| Accepts a single text field or expression and returns the MD5 hash of the | ||||
| string. | ||||
|  | ||||
| It can also be registered as a transform as described in :class:`Length`. | ||||
|  | ||||
| Usage example:: | ||||
|  | ||||
|     >>> from django.db.models.functions import MD5 | ||||
|     >>> Author.objects.create(name='Margaret Smith') | ||||
|     >>> author = Author.objects.annotate(name_md5=MD5('name')).get() | ||||
|     >>> print(author.name_md5) | ||||
|     749fb689816b2db85f5b169c2055b247 | ||||
|  | ||||
| ``Ord`` | ||||
| ------- | ||||
|  | ||||
|   | ||||
| @@ -162,7 +162,7 @@ Migrations | ||||
| Models | ||||
| ~~~~~~ | ||||
|  | ||||
| * ... | ||||
| * Added the :class:`~django.db.models.functions.MD5` database function. | ||||
|  | ||||
| Requests and Responses | ||||
| ~~~~~~~~~~~~~~~~~~~~~~ | ||||
|   | ||||
							
								
								
									
										41
									
								
								tests/db_functions/text/test_md5.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										41
									
								
								tests/db_functions/text/test_md5.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,41 @@ | ||||
| from django.db import connection | ||||
| from django.db.models import CharField | ||||
| from django.db.models.functions import MD5 | ||||
| from django.test import TestCase | ||||
| from django.test.utils import register_lookup | ||||
|  | ||||
| from ..models import Author | ||||
|  | ||||
|  | ||||
| class MD5Tests(TestCase): | ||||
|     @classmethod | ||||
|     def setUpTestData(cls): | ||||
|         Author.objects.bulk_create([ | ||||
|             Author(alias='John Smith'), | ||||
|             Author(alias='Jordan Élena'), | ||||
|             Author(alias='皇帝'), | ||||
|             Author(alias=''), | ||||
|             Author(alias=None), | ||||
|         ]) | ||||
|  | ||||
|     def test_basic(self): | ||||
|         authors = Author.objects.annotate( | ||||
|             md5_alias=MD5('alias'), | ||||
|         ).values_list('md5_alias', flat=True).order_by('pk') | ||||
|         self.assertSequenceEqual( | ||||
|             authors, | ||||
|             [ | ||||
|                 '6117323d2cabbc17d44c2b44587f682c', | ||||
|                 'ca6d48f6772000141e66591aee49d56c', | ||||
|                 'bf2c13bc1154e3d2e7df848cbc8be73d', | ||||
|                 'd41d8cd98f00b204e9800998ecf8427e', | ||||
|                 'd41d8cd98f00b204e9800998ecf8427e' if connection.features.interprets_empty_strings_as_nulls else None, | ||||
|             ], | ||||
|         ) | ||||
|  | ||||
|     def test_transform(self): | ||||
|         with register_lookup(CharField, MD5): | ||||
|             authors = Author.objects.filter( | ||||
|                 alias__md5='6117323d2cabbc17d44c2b44587f682c', | ||||
|             ).values_list('alias', flat=True) | ||||
|             self.assertSequenceEqual(authors, ['John Smith']) | ||||
		Reference in New Issue
	
	Block a user