Gestion de contact et suivi de conversion pour les groupement d'agriculture biologique
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 

190 lines
6.7 KiB

# -*- coding: utf-8 -*-
#
# Ce fichier regroupe les classes et fonctions annexes utilisées dans les vues
# de l'application.
#
from django.conf import settings
from django.core import exceptions
import model_walk
REPR_MTX = {
'ManyRelatedManager': lambda x: ', '.join(
[str(elm) for elm in x.all()] # noqa: F821
),
'RelatedManager': lambda x: ', '.join(
[str(elm) for elm in x.all()] # noqa: F821
),
'bool': lambda x: x and 'VRAI' or 'FAUX',
'date': lambda x: x.strftime(settings.FORMAT_DATE_EXPORT),
'datetime': lambda x: x.strftime(settings.FORMAT_DATE_EXPORT),
'NoneType': lambda x: "",
}
def repr_obj(obj):
class_name = type(obj).__name__
return REPR_MTX.get(class_name, lambda x: x)(obj)
# ## ---------------------------------------------------------------------------
# Base pour l'export CSV
#
class ExportCSV(object):
"""
base class for building CSV file
- subclass must define 'attr_liste', list of composed_name
(name of attribute in a django fashion: 'attr1__attr2')
- output is generated to a file (that may be a StringIO)
"""
# separator character
SEP = ";"
# insert utf-8 BOM should help excel understand it is utf-8...
insert_bom = True
attr_liste = 'attrs_export'
def __init__(self, file, attr_liste=None):
"record output to self"
self.out = file
self.attr_liste = attr_liste or self.attr_liste
def _quote_csv(self, value):
'escape charater like "(double-quote) and \r\n (carriage return)'
if value.find('"'):
value = value.replace('"', '""')
# Excel termine la ligne lorsqu'une nouvelle ligne est présente
# dans un champ, même entre guillements. Tentative de contournement
# (non testée) en remplaçant \r\n par \n
# voir http://stackoverflow.com/questions/1241220/
# generating-csv-file-for-excel-how-to-have-a-newline-inside-a-value
if value.find('\r\n'):
value = value.replace('\r\n', '\r')
return '"%s"' % value
def _get_repr(self, obj, composed_name):
""" return a representation given "obj" and
"composed_name" with composed_name in django
fashion: 'attr1__func__attr2'
"""
cur_obj = obj
for attr_name in composed_name.split('__'):
cur_obj = getattr(cur_obj, attr_name, None)
if (
callable(cur_obj)
and type(cur_obj).__name__ != 'RelatedManager'
):
cur_obj = cur_obj()
if cur_obj is None:
break
return self._quote_csv(str(repr_obj(cur_obj))) # noqa: F821
def _ecrit_champs(self, objet):
"""
Écrit les champs de l'objet donné dans le fichier de sortie.
L'objet doit posséder un attribut (désigné par notre attribut
de classe attr_liste) qui donne la liste des champs à inclure
dans l'export.
"""
m2m_fields = model_walk.get_m2m_name_from_model(type(objet))
repre = []
if m2m_fields:
ligne = ""
for champ in self.attrs_export:
if isinstance(champ, (list, tuple)):
champ = champ[0]
if champ in m2m_fields:
ref = (
type(objet)
._meta.get_field(champ)
.related_model.objects.all()
)
ref = [str(field) for field in ref] # noqa: F821
champs = repr_obj(getattr(objet, champ))
for r in ref:
if r in champs:
repre.append('1')
else:
repre.append('')
else:
repre.append(self._get_repr(objet, champ))
ligne = self.SEP.join(repre)
else:
for champ in self.attrs_export:
if isinstance(champ, (list, tuple)):
champ = champ[0]
repre.append(self._get_repr(objet, champ))
ligne = self.SEP.join(repre)
self.out.write("{}\r\n".format(ligne))
def _get_verbose_names(self, model, list_name):
"""Return csv header given a class model (not a model intance)
and list of a tuple of composed_name composed_name is
separated by '__' in a django fashion: 'attr1__attr2__func'
"""
line1 = []
line2 = []
m2m_fields = model_walk.get_m2m_name_from_model(model)
if m2m_fields:
for name in list_name:
if isinstance(name, (list, tuple)):
repre = name[1]
name = name[0]
else:
repre = model_walk.label_for_composed_field(model, name)
if name not in m2m_fields:
line1.append(repre)
line2.append('')
else:
for elm in model._meta.get_field(
name
).related_model.objects.all():
line1.append(repre)
line2.append(str(elm)) # noqa: F821
line1 = self.SEP.join(line1) + "\r\n"
line2 = self.SEP.join(line2)
titres = line1 + line2
return titres
else:
for name in list_name:
if isinstance(name, (list, tuple)):
line1.append(name[1])
else:
line1.append(
model_walk.label_for_composed_field(model, name)
)
return self.SEP.join(line1)
def generer(self, object_list):
"""
Génère le fichier CSV à partir d'une liste d'objets.
.
Note: pour les structures, la liste des attributs à exporter
est systématiquement celle du modèle AgriculteurBio et les
champs non trouvés seront exportés vides (ceci permet
d'exporter en même temps tous les objets Structure,
Agriculteur, ou AgriculteurBio).
"""
if len(object_list) == 0:
return
bmodel = type(object_list[0])
try:
self.attrs_export = getattr(bmodel, self.attr_liste)
except AttributeError:
raise exceptions.ImproperlyConfigured(
"Le modèle %s ne possède pas l'attribut %s"
" fournissant la liste des champs à exporter"
% (bmodel, self.attr_liste)
)
titres = self._get_verbose_names(bmodel, self.attrs_export)
if self.insert_bom:
self.out.write('\ufeff')
self.out.write("{}\r\n".format(titres))
for obj in object_list:
self._ecrit_champs(obj)
# EOF
Map all the world