/
base_models.py
executable file
·131 lines (89 loc) · 2.88 KB
/
base_models.py
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
from django.db import models
from django.db.models import base
from django.template import defaultfilters
from python_utils import formatters
class ModelBaseMeta(base.ModelBase):
'''
Model base with more readable naming convention
Example:
Assuming the model is called `app.FooBarObject`
Default Django table name: `app_foobarobject`
Table name with this base: `app_foo_bar_object`
'''
def __new__(cls, name, bases, attrs):
module = attrs['__module__']
# Get or create Meta
if 'Meta' in attrs:
Meta = attrs['Meta']
else:
Meta = type(
'Meta', (object,), dict(
__module__=module,
)
)
attrs['Meta'] = Meta
# Override table name only if not explicitly defined
if not hasattr(Meta, 'db_table'): # pragma: no cover
module_name = formatters.camel_to_underscore(name)
app_label = module.split('.')[-2]
Meta.db_table = f'{app_label}_{module_name}'
return base.ModelBase.__new__(cls, name, bases, attrs)
class ModelBase(models.Model, metaclass=ModelBaseMeta):
class Meta:
abstract = True
class CreatedAtModelBase(ModelBase):
updated_at = models.DateTimeField(auto_now=True)
created_at = models.DateTimeField(auto_now_add=True)
class Meta:
abstract = True
class NameMixin(object):
'''Mixin to automatically get a unicode and repr string base on the name
>>> x = NameMixin()
>>> x.pk = 123
>>> x.name = 'test'
>>> repr(x)
'<NameMixin[123]: test>'
>>> str(x)
'test'
>>> str(str(x))
'test'
'''
def __unicode__(self):
return self.name
def __str__(self):
return self.__unicode__()
def __repr__(self):
return f'<{self.__class__.__name__}[{self.pk or -1:d}]: {self.name}>'
class SlugMixin(NameMixin):
'''Mixin to automatically slugify the name and add both a name and slug to
the model
>>> x = NameMixin()
>>> x.pk = 123
>>> x.name = 'test'
>>> repr(x)
'<NameMixin[123]: test>'
>>> str(x)
'test'
>>> str(str(x))
'test'
'''
def save(self, *args, **kwargs):
if not self.slug and self.name:
self.slug = defaultfilters.slugify(self.name)
super(NameMixin, self).save(*args, **kwargs)
class Meta(object):
unique_together = ('slug',)
class NameModelBase(NameMixin, ModelBase):
name = models.CharField(max_length=100)
class Meta:
abstract = True
class SlugModelBase(SlugMixin, NameModelBase):
slug = models.SlugField(max_length=50)
class Meta:
abstract = True
class NameCreatedAtModelBase(NameModelBase, CreatedAtModelBase):
class Meta:
abstract = True
class SlugCreatedAtModelBase(SlugModelBase, CreatedAtModelBase):
class Meta:
abstract = True