source: seguimiento_proyectos/sepai/adaptor/fields.py @ c4a52ed

desarrollo
Last change on this file since c4a52ed was 2e5b1d0, checked in by lhernandez <lhernandez@…>, 8 años ago

Levantada la plataforma para el desarrollo de la aplicacion SEPAI, realizado modelos de datos, vistas, login, adaptado templates para el proyecto

  • Propiedad mode establecida a 100644
File size: 10.0 KB
Línea 
1from datetime import datetime
2from decimal import Decimal
3from lxml import etree
4
5from django.db.models import Model as djangoModel
6from django.core.exceptions import ObjectDoesNotExist, MultipleObjectsReturned
7from adaptor import exceptions
8
9
10class AllChoices(object):
11    def __contains__(self, value):
12        return True
13
14
15class AlwaysValidValidator(object):
16    def validate(self, val):
17        return True
18
19
20class BaseField(object):
21    def __init__(self, kwargs):
22        self.transform = kwargs.pop('transform', lambda val:val)
23
24
25class Field(BaseField):
26    position = 0
27
28    def __init__(self, **kwargs):
29        super(Field, self).__init__(kwargs)
30        self.null = kwargs.pop("null", False)
31        self.default = kwargs.pop("default", None)
32        if self.default and not self.null:
33            raise exceptions.FieldError("You cannot provide a default without setting the field as nullable")
34        if 'row_num' in kwargs:
35            self.position = kwargs.pop('row_num')
36        else:
37            self.position = Field.position
38            Field.position += 1
39        if 'match' in kwargs:
40            self.match = kwargs.pop('match')
41        self.validator = kwargs.pop('validator', AlwaysValidValidator)
42        if 'multiple' in kwargs:
43            self.has_multiple = kwargs.pop('multiple')
44        self.prepare = kwargs.pop('prepare', lambda val:val)
45        if 'keys' in kwargs and isinstance(self, ComposedKeyField):
46            self.keys = kwargs.pop('keys')
47        self.choices= kwargs.pop('choices', AllChoices())
48        if len(kwargs) > 0:
49            raise ValueError("Arguments %s unexpected" % kwargs.keys())
50
51    def get_transform_method(self, instance):
52        """ Look for transform_<field_name>, else look for the transform parameter, else identity method """
53        transform_method = "transform_" + getattr(self, "fieldname", self.field_name)
54        transform = getattr(instance, transform_method, self.transform)
55        return transform
56
57    def get_prep_value(self, value, instance=None):
58        try:
59            value = self.prepare(value)
60            if not value and self.null:
61                value = self.default
62            else:
63                value = self.to_python(value)
64            if value not in self.choices:
65                if not self.null:
66                    raise exceptions.ChoiceError("Value \'%s\' does not belong to %s" % (value, self.choices))
67                value = None
68            transform = self.get_transform_method(instance)
69            value = transform(value)
70            if not self.validator().validate(value):
71                raise exceptions.FieldError(self.validator.validation_message)
72            return value
73        except exceptions.ChoiceError:
74            raise
75        except exceptions.FieldError:
76            raise
77        except ValueError:
78            self.raise_type_error(value)
79
80    def raise_type_error(self, value):
81        raise ValueError("Value \'%s\' in columns %d does not match the expected type %s" %
82                             (value, self.position + 1, self.__class__.field_name))
83
84
85class IntegerField(Field):
86    field_name = "Integer"
87
88    def to_python(self, value):
89        return int(value)
90
91
92class BooleanField(Field):
93    field_name = "Boolean"
94
95    def default_is_true_method(self, value):
96        return value.lower() == "true"
97
98    def __init__(self, *args, **kwargs):
99        if 'is_true' in kwargs:
100            self.is_true_method = kwargs.pop('is_true')
101        else:
102            self.is_true_method = self.default_is_true_method
103        super(BooleanField, self).__init__(*args, **kwargs)
104
105    def to_python(self, value):
106        return self.is_true_method(value)
107
108
109class CharField(Field):
110    field_name = "String"
111
112    def to_python(self, value):
113        return value
114
115
116class DateField(Field):
117    field_name = "Date"
118
119    def __init__(self, *args, **kwargs):
120        if 'format' in kwargs:
121            self.format = kwargs.pop('format')
122        else:
123            self.format = "%d/%m/%Y"
124        super(DateField, self).__init__(*args, **kwargs)
125
126    def to_python(self, value):
127        return datetime.strptime(value, self.format)
128
129
130class DecimalField(Field):
131    field_name = "A Decimal number"
132
133    def to_python(self, value):
134        return Decimal(value)
135
136
137class FloatField(Field):
138    field_name = "A float number"
139
140    def to_python(self, value):
141        return float(value)
142
143
144class IgnoredField(Field):
145    field_name = "Ignore the value"
146
147
148class DjangoModelField(Field):
149    field_name = "not defined"
150
151    def __init__(self, *args, **kwargs):
152        self.pk = kwargs.pop('pk', 'pk')
153        if len(args) < 1:
154            raise ValueError("You should provide a Model as the first argument.")
155        self.model = args[0]
156        try:
157            if not issubclass(self.model, djangoModel):
158                raise TypeError("The first argument should be a django model class.")
159        except TypeError:
160            raise TypeError("The first argument should be a django model class.")
161        super(DjangoModelField, self).__init__(**kwargs)
162
163    def to_python(self, value):
164        try:
165            return self.model.objects.get(**{self.pk: value})
166        except ObjectDoesNotExist:
167            raise exceptions.ForeignKeyFieldError("No match found for %s" % self.model.__name__, self.model.__name__, value)
168        except MultipleObjectsReturned:
169            raise exceptions.ForeignKeyFieldError("Multiple match found for %s" % self.model.__name__, self.model.__name__, value)
170
171
172class ForeignKey(Field):
173     def __init__(self,*args,**kwargs):
174         self.pk = kwargs.pop('pk','pk')
175         if len(args)<1:
176             raise ValueError("You should provide a Model as the first argument.")
177         self.model = args[0]
178         try:
179             if not issubclass(self.model,djangoModel):
180                 raise TypeError("The first argument should be a django model class.")
181         except TypeError:
182             raise TypeError("The first argument should be a django model class.")
183         super(ForeignKey,self).__init__(**kwargs)
184
185     def to_python(self,value):
186         return self.model.objects.get(**{self.pk:value})
187
188
189class ComposedKeyField(DjangoModelField):
190    def to_python(self, value):
191        try:
192            return self.model.objects.get(**value)
193        except ObjectDoesNotExist:
194            raise exceptions.ForeignKeyFieldError("No match found for %s" % self.model.__name__, self.model.__name__, value)
195
196
197class XMLField(Field):
198    type_field_class = None
199
200    def __init__(self, *args, **kwargs):
201        self.path = kwargs.pop("path")
202        self.root = kwargs.pop("root", None)
203        self.attribute = kwargs.pop("attribute", None)
204        self.namespaces = kwargs.pop("namespaces", None)
205        self.type_class = self._get_type_field()
206        if self.type_class:
207            self.type_class.__init__(self, *args, **kwargs)
208        else:
209            BaseField.__init__(self, kwargs)
210
211    def _get_type_field(self):
212        base_classes = self.__class__.__bases__
213        for base_class in base_classes:
214            if issubclass(base_class, Field) and not issubclass(base_class, XMLField):
215                return base_class
216
217    def get_prep_value(self, value, instance=None):
218        from lxml import etree
219        element = self.root if self.root is not None else etree.fromstring(value)
220        values = element.xpath(self.path, namespaces=self.namespaces)
221        if not values and self.null:
222            if self.default is not None:
223                parsed_value = self.default
224            else:
225                return None
226        else:
227            if not self.attribute:
228                parsed_value = element.xpath(self.path,
229                                             namespaces=self.namespaces)[0].text
230            else:
231                parsed_value = element.xpath(self.path,
232                                             namespaces=self.namespaces)[0]\
233                                      .get(self.attribute)
234        return self.type_class.get_prep_value(self, parsed_value, instance=instance)
235
236    def set_root(self, root):
237        self.root = root
238
239    def raise_type_error(self, value):
240        raise ValueError("Value \'%s\' does not match the expected type %s" %
241                             (value, self.__class__.field_name))
242
243
244class XMLRootField(XMLField):
245    def __init__(self, *args, **kwargs):
246        super(XMLRootField, self).__init__(*args, **kwargs)
247        kwargs['root'] = self
248
249    def get_prep_value(self, value, instance=None):
250        pass
251
252    def to_python(self, value):
253        pass
254
255    def get_root(self, value):
256        from lxml import etree
257        element = self.root if self.root is not None else etree.fromstring(value)
258        return element.xpath(self.path, namespaces=self.namespaces)
259
260
261class XMLEmbed(XMLRootField):
262    field_name = "not defined"
263
264    def __init__(self, embed_model):
265        self.embed_model = embed_model
266        super(XMLEmbed, self).__init__(path=self.embed_model.get_root_field()[1].path)
267
268    def get_prep_value(self, value, instance=None):
269        roots = self.get_root(self.root)
270        objects = []
271        for root in roots:
272            objects.append(self.embed_model(value, element=root))
273        transform = self.get_transform_method(instance)
274        objects = transform(objects)
275        return objects
276
277
278class XMLCharField(XMLField, CharField):
279    pass
280
281
282class XMLIntegerField(XMLField, IntegerField):
283    pass
284
285
286class XMLDecimalField(XMLField, DecimalField):
287    pass
288
289
290class XMLFloatField(XMLField, FloatField):
291    pass
292
293
294class XMLDjangoModelField(XMLField, DjangoModelField):
295    def __init__(self, *args, **kwargs):
296        self.nomatch = kwargs.pop("nomatch", False)
297        super(XMLDjangoModelField, self).__init__(*args, **kwargs)
298
299    def get_prep_value(self, value, instance=None):
300        try:
301            return super(XMLDjangoModelField, self).get_prep_value(value, instance=instance)
302        except exceptions.ForeignKeyFieldError as e:
303            if self.nomatch:
304                return None
305            else:
306                raise e
307
308
309class XMLBooleanField(XMLField, BooleanField):
310    pass
311
312
313class XMLDateField(XMLField, DateField):
314    pass
Nota: Vea TracBrowser para ayuda de uso del navegador del repositorio.