1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173
|
from datetime import datetime, date, timedelta
from decimal import Decimal
from itertools import chain
import random
import socket
import string
import struct
from warnings import warn
from django.core.exceptions import ImproperlyConfigured
try:
from django.utils.timezone import now
except ImportError:
now = datetime.now
try:
from django.contrib.gis.geos import *
except ImproperlyConfigured:
pass # environment without geo libs
except Exception:
pass # Avoid errors like GDALException
from django_dynamic_fixture.fixture_algorithms.sequential_fixture import AutoDataFiller
from django_dynamic_fixture.fixture_algorithms.default_fixture import BaseDataFixture, GeoDjangoFixtureMixin, PostgresFixtureMixin
class UniqueRandomDataFixture(BaseDataFixture, GeoDjangoFixtureMixin, PostgresFixtureMixin):
DEFAULT_LENGTH = 10
OBJECT_COUNT = 512
WARNING_MESSAGE_TMPL = (
'Maximum number of objects (%d) is exceeded in '
'unique_random_fixture. Uniqueness is not guaranteed.'
)
def __init__(self):
super().__init__()
self.filler = AutoDataFiller()
def get_counter(self, field, key):
result = self.filler.next(key)
if result > self.OBJECT_COUNT:
warn(self.WARNING_MESSAGE_TMPL % self.OBJECT_COUNT, RuntimeWarning)
return result
def random_string(self, field, key, n=None):
counter = str(self.get_counter(field, key))
length = n or self.DEFAULT_LENGTH
result = counter
result += ''.join(
random.choice(string.ascii_letters)
for _ in range(length - len(counter))
)
return result
def random_integer(self, field, key, signed=True):
counter = self.get_counter(field, key) - 1
counter %= self.OBJECT_COUNT
if not signed:
MAX_INT = 2 ** 16
multiplier = MAX_INT // self.OBJECT_COUNT
return random.randrange(
multiplier * counter + 1, multiplier * (counter + 1)
)
MAX_SIGNED_INT = 2 ** 15
multiplier = MAX_SIGNED_INT // self.OBJECT_COUNT
positive_range = range(
multiplier * counter + 1, multiplier * (counter + 1)
)
negative_range = range(
(-multiplier) * (counter + 1), (-multiplier) * counter
)
return random.choice(list(chain(positive_range, negative_range)))
# NUMBERS
def integerfield_config(self, field, key):
return self.random_integer(field, key)
def smallintegerfield_config(self, field, key):
return self.random_integer(field, key)
def bigintegerfield_config(self, field, key):
return self.random_integer(field, key)
def positiveintegerfield_config(self, field, key):
return self.random_integer(field, key, signed=False)
def positivesmallintegerfield_config(self, field, key):
return self.random_integer(field, key, signed=False)
def floatfield_config(self, field, key):
return float(self.random_integer(field, key)) + random.random()
def decimalfield_config(self, field, key):
number_of_digits = field.max_digits - field.decimal_places
max_value = 10 ** number_of_digits
value = self.random_integer(field, key) % max_value
value = float(value) + random.random()
return Decimal(str(value))
# STRINGS
def charfield_config(self, field, key):
return self.random_string(field, key, field.max_length)
def textfield_config(self, field, key):
return self.charfield_config(field, key)
def slugfield_config(self, field, key):
return self.charfield_config(field, key)
def commaseparatedintegerfield_config(self, field, key):
return self.charfield_config(field, key)
# BOOLEAN
def booleanfield_config(self, field, key):
counter = self.get_counter(field, key)
if counter == 1:
return True
elif counter == 2:
return False
return random.choice((True, False))
def nullbooleanfield_config(self, field, key):
counter = self.get_counter(field, key)
if counter == 1:
return None
elif counter == 2:
return True
elif counter == 3:
return False
return random.choice((None, True, False))
# DATE/TIME RELATED
def datefield_config(self, field, key):
integer = self.random_integer(field, key, signed=False)
return date.today() - timedelta(days=integer)
def timefield_config(self, field, key):
integer = self.random_integer(field, key, signed=False)
return (now() - timedelta(seconds=integer)).time()
def datetimefield_config(self, field, key):
integer = self.random_integer(field, key, signed=False)
return now() - timedelta(seconds=integer)
# FORMATTED STRINGS
def emailfield_config(self, field, key):
return f'a{self.random_string(field, key)}@dynamicfixture.com'
def urlfield_config(self, field, key):
return f'http://dynamicfixture{self.random_string(field, key)}.com'
# Deprecated in Django >= 1.7
def ipaddressfield_config(self, field, key):
MAX_IP = 2 ** 32 - 1
integer = self.random_integer(field, key, signed=False)
integer %= MAX_IP
return str(socket.inet_ntoa(struct.pack('!L', integer)))
def xmlfield_config(self, field, key):
return f'<a>{self.random_string(field, key)}</a>'
# FILES
def filepathfield_config(self, field, key):
return self.random_string(field, key)
def filefield_config(self, field, key):
return self.random_string(field, key)
def imagefield_config(self, field, key):
return self.random_string(field, key)
|