david / django-portablecontacts (http://portablecontacts.net/)
Support for PortableContacts in Django.
$ hg clone http://code.welldev.org/django-portablecontacts
| commit 1: | 102195ccdbf9 |
| parent 0: | 679eb8567412 |
| branch: | default |
21 months ago
Changed (Δ7.5 KB):
portablecontacts/serializers/__init__.py (13 lines added, 0 lines removed)
portablecontacts/serializers/python.py (13 lines added, 19 lines removed)
portablecontacts/serializers/xml_serializer.py (87 lines added, 7 lines removed)
portablecontacts/tests.py (93 lines added, 2 lines removed)
portablecontacts_example/manage.py (1 lines added, 1 lines removed)
Up to file-list portablecontacts/serializers/__init__.py:
1 |
||
2 |
convert_classname_to_name = { |
|
3 |
'portablecontacts:contactemail': 'emails', |
|
4 |
'portablecontacts:contacturl': 'urls', |
|
5 |
'portablecontacts:contactphonenumber': 'phoneNumbers', |
|
6 |
'portablecontacts:contactim': 'ims', |
|
7 |
'portablecontacts:contactphoto': 'photos', |
|
8 |
'portablecontacts:contacttag': 'tags', |
|
9 |
'portablecontacts:contactrelationship': 'relationships', |
|
10 |
'portablecontacts:contactaddress': 'addresses', |
|
11 |
'portablecontacts:contactorganization': 'organizations', |
|
12 |
'portablecontacts:contactaccount': 'accounts', |
|
13 |
} |
Up to file-list portablecontacts/serializers/python.py:
| … | … | @@ -4,32 +4,28 @@ from django.utils.encoding import smart_ |
4 |
4 |
from django.core.serializers.python import Serializer as DjangoPythonSerializer |
5 |
5 |
|
6 |
6 |
from portablecontacts.models import contact_model |
7 |
from portablecontacts.serializers import convert_classname_to_name |
|
7 |
8 |
|
8 |
convert_classname_to_name = { |
|
9 |
'portablecontacts:contactemail': 'emails', |
|
10 |
'portablecontacts:contacturl': 'urls', |
|
11 |
'portablecontacts:contactphonenumber': 'phoneNumbers', |
|
12 |
'portablecontacts:contactim': 'ims', |
|
13 |
'portablecontacts:contactphoto': 'photos', |
|
14 |
'portablecontacts:contacttag': 'tags', |
|
15 |
'portablecontacts:contactrelationship': 'relationships', |
|
16 |
'portablecontacts:contactaddress': 'addresses', |
|
17 |
'portablecontacts:contactorganization': 'organizations', |
|
18 |
'portablecontacts:contactaccount': 'accounts', |
|
19 |
} |
|
20 |
9 |
|
21 |
10 |
class Serializer(DjangoPythonSerializer): |
22 |
11 |
""" |
23 |
12 |
Serializes a QuerySet to basic Python objects. |
24 |
13 |
""" |
14 |
def start_object(self, obj): |
|
15 |
""" |
|
16 |
Called as each object is handled. |
|
17 |
""" |
|
18 |
self._current = {} |
|
19 |
if isinstance(obj, contact_model): |
|
20 |
self._current.update({ |
|
21 |
"id": smart_unicode(obj._get_pk_val(), strings_only=True), |
|
22 |
}) |
|
23 |
||
25 |
24 |
def end_object(self, obj): |
26 |
25 |
""" |
27 |
26 |
Called after handling all fields for an object. |
28 |
27 |
""" |
29 |
28 |
if isinstance(obj, contact_model): |
30 |
self._current.update({ |
|
31 |
"id": smart_unicode(obj._get_pk_val(), strings_only=True), |
|
32 |
}) |
|
33 |
29 |
for rel_object in obj._meta.get_all_related_objects(): |
34 |
30 |
objects = rel_object.model.objects.filter(contact=obj) |
35 |
31 |
if objects: |
| … | … | @@ -93,10 +89,8 @@ class Serializer(DjangoPythonSerializer) |
93 |
89 |
return |
94 |
90 |
|
95 |
91 |
if field_name == 'type': |
96 |
type_display = getattr(obj, 'get_%s_display' % field_name)() |
|
97 |
self._current_reverse[field_name] = smart_unicode(type_display, strings_only=True) |
|
98 |
else: |
|
99 |
self._current_reverse[field_name] = smart_unicode(field_content, strings_only=True) |
|
92 |
field_content = getattr(obj, 'get_%s_display' % field_name)() |
|
93 |
self._current_reverse[field_name] = smart_unicode(field_content, strings_only=True) |
|
100 |
94 |
|
101 |
95 |
def handle_fk_field(self, obj, field): |
102 |
96 |
""" |
Up to file-list portablecontacts/serializers/xml_serializer.py:
| … | … | @@ -3,6 +3,9 @@ from django.core.serializers.xml_seriali |
3 |
3 |
from django.utils.xmlutils import SimplerXMLGenerator |
4 |
4 |
from django.utils.encoding import smart_unicode |
5 |
5 |
|
6 |
from portablecontacts.models import contact_model |
|
7 |
from portablecontacts.serializers import convert_classname_to_name |
|
8 |
||
6 |
9 |
class Serializer(DjangoXMLSerializer): |
7 |
10 |
""" |
8 |
11 |
Convert a queryset to XML. |
| … | … | @@ -16,6 +19,14 @@ class Serializer(DjangoXMLSerializer): |
16 |
19 |
self.xml = SimplerXMLGenerator(self.stream, self.options.get("encoding", settings.DEFAULT_CHARSET)) |
17 |
20 |
self.xml.startDocument() |
18 |
21 |
self.xml.startElement("response", {}) |
22 |
||
23 |
if not self.options.get('unique', False): |
|
24 |
self.indent(1) |
|
25 |
self.xml.addQuickElement("startIndex", self.options.get('startIndex', '0')) |
|
26 |
self.indent(1) |
|
27 |
self.xml.addQuickElement("itemsPerPage", self.options.get('itemsPerPage', '0')) |
|
28 |
self.indent(1) |
|
29 |
self.xml.addQuickElement("totalResults", self.options.get('totalResults', '0')) |
|
19 |
30 |
|
20 |
31 |
def end_serialization(self): |
21 |
32 |
""" |
| … | … | @@ -31,11 +42,28 @@ class Serializer(DjangoXMLSerializer): |
31 |
42 |
""" |
32 |
43 |
self.indent(1) |
33 |
44 |
self.xml.startElement("entry", {}) |
45 |
self.indent(2) |
|
46 |
self.xml.addQuickElement('id', smart_unicode(obj.id)) |
|
47 |
||
48 |
self.has_name = False |
|
49 |
self.has_displayName = False |
|
34 |
50 |
|
35 |
51 |
def end_object(self, obj): |
36 |
52 |
""" |
37 |
53 |
Called after handling all fields for an object. |
38 |
54 |
""" |
55 |
if isinstance(obj, contact_model): |
|
56 |
for rel_object in obj._meta.get_all_related_objects(): |
|
57 |
objects = rel_object.model.objects.filter(contact=obj) |
|
58 |
if objects: |
|
59 |
name = convert_classname_to_name[rel_object.name] |
|
60 |
self.handle_reverse_fk_fields(objects, name) |
|
61 |
||
62 |
#if 'tags' in self._current: |
|
63 |
# self._current['tags'] = [tag['value'] for tag in self._current['tags']] |
|
64 |
#if 'relationships' in self._current: |
|
65 |
# self._current['relationships'] = [relationship['value'] \ |
|
66 |
# for relationship in self._current['relationships']] |
|
39 |
67 |
self.indent(1) |
40 |
68 |
self.xml.endElement("entry") |
41 |
69 |
|
| … | … | @@ -46,13 +74,35 @@ class Serializer(DjangoXMLSerializer): |
46 |
74 |
""" |
47 |
75 |
# Get a "string version" of the object's data (this is handled by the |
48 |
76 |
# serializer base class). |
49 |
field_content = getattr(obj, field.name) |
|
50 |
if not field_content or field.name in ('published', 'updated'): |
|
51 |
return |
|
52 |
||
53 |
self.indent(2) |
|
54 |
value = self.get_string_value(obj, field) |
|
55 |
|
|
77 |
field_name = field.name |
|
78 |
field_content = getattr(obj, field_name) |
|
79 |
||
80 |
if field_content: |
|
81 |
if field_name in ('userName', 'familyName', 'givenName', |
|
82 |
'middleName', 'honorificPrefix', 'honorificSuffix'): |
|
83 |
if not self.has_displayName: |
|
84 |
self.indent(2) |
|
85 |
self.xml.addQuickElement('displayName', smart_unicode(getattr(obj, 'displayName'), strings_only=True)) |
|
86 |
self.has_displayName = True |
|
87 |
if field_name in ('familyName', 'givenName', 'middleName', |
|
88 |
'honorificPrefix', 'honorificSuffix'): |
|
89 |
if not self.has_name: |
|
90 |
self.indent(2) |
|
91 |
self.xml.startElement("name", {}) |
|
92 |
for local_field_name in ('familyName', 'givenName', 'middleName', |
|
93 |
'honorificPrefix', 'honorificSuffix'): |
|
94 |
local_field_content = smart_unicode(getattr(obj, local_field_name), strings_only=True) |
|
95 |
if local_field_content: |
|
96 |
self.indent(3) |
|
97 |
self.xml.addQuickElement(local_field_name, local_field_content) |
|
98 |
self.indent(2) |
|
99 |
self.xml.endElement("name") |
|
100 |
self.has_name = True |
|
101 |
||
102 |
elif field_name not in ('published', 'updated'): |
|
103 |
self.indent(2) |
|
104 |
value = self.get_string_value(obj, field) |
|
105 |
self.xml.addQuickElement(field_name, value) |
|
56 |
106 |
|
57 |
107 |
def handle_fk_field(self, obj, field): |
58 |
108 |
""" |
| … | … | @@ -60,3 +110,33 @@ class Serializer(DjangoXMLSerializer): |
60 |
110 |
differently from regular fields). |
61 |
111 |
""" |
62 |
112 |
pass |
113 |
||
114 |
def handle_reverse_fk_fields(self, objs, name): |
|
115 |
""" |
|
116 |
Called to handle a models which have a ForeignKey to the current oject. |
|
117 |
""" |
|
118 |
objects = [] |
|
119 |
self._current_reverse = {} |
|
120 |
for obj in objs: |
|
121 |
self.indent(2) |
|
122 |
self.xml.startElement(name, {}) |
|
123 |
for field in obj._meta.local_fields: |
|
124 |
if field.serialize and field.rel is None \ |
|
125 |
and (self.selected_fields is None or field.attname in self.selected_fields): |
|
126 |
field_name = field.name |
|
127 |
field_content = getattr(obj, field_name) |
|
128 |
if not field_content or (field_name=='primary' and field_content==False): |
|
129 |
continue |
|
130 |
||
131 |
if field_content == False: |
|
132 |
field_content = 'false' |
|
133 |
elif field_content == True: |
|
134 |
field_content = 'true' |
|
135 |
||
136 |
self.indent(3) |
|
137 |
if field_name == 'type': |
|
138 |
field_content = getattr(obj, 'get_%s_display' % field_name)() |
|
139 |
self.xml.addQuickElement(field.name, smart_unicode(field_content, strings_only=True)) |
|
140 |
||
141 |
self.indent(2) |
|
142 |
self.xml.endElement(name) |
Up to file-list portablecontacts/tests.py:
| … | … | @@ -371,8 +371,98 @@ data: |
371 |
371 |
} |
372 |
372 |
} |
373 |
373 |
|
374 |
XML representation |
|
374 |
XML representations:: |
|
375 |
375 |
|
376 |
>>> response = c.get("/portablecontacts/@me/@all/", {'format': 'xml'}) |
|
377 |
>>> response.status_code |
|
378 |
200 |
|
379 |
>>> print response.content |
|
380 |
<?xml version="1.0" encoding="utf-8"?> |
|
381 |
<response> |
|
382 |
<startIndex>0</startIndex> |
|
383 |
<itemsPerPage>0</itemsPerPage> |
|
384 |
<totalResults>0</totalResults> |
|
385 |
<entry> |
|
386 |
<id>1</id> |
|
387 |
<displayName>Minimal Contact</displayName> |
|
388 |
</entry> |
|
389 |
<entry> |
|
390 |
<id>2</id> |
|
391 |
<displayName>Mork Hashimoto</displayName> |
|
392 |
<name> |
|
393 |
<familyName>Hashimoto</familyName> |
|
394 |
<givenName>Mork</givenName> |
|
395 |
</name> |
|
396 |
<emails> |
|
397 |
<value>mhashimoto-04@plaxo.com</value> |
|
398 |
<type>work</type> |
|
399 |
<primary>true</primary> |
|
400 |
</emails> |
|
401 |
<emails> |
|
402 |
<value>mhashimoto-04@plaxo.com</value> |
|
403 |
<type>home</type> |
|
404 |
</emails> |
|
405 |
<urls> |
|
406 |
<value>http://www.seeyellow.com</value> |
|
407 |
<type>work</type> |
|
408 |
</urls> |
|
409 |
<urls> |
|
410 |
<value>http://www.angryalien.com</value> |
|
411 |
<type>home</type> |
|
412 |
</urls> |
|
413 |
<phoneNumbers> |
|
414 |
<value>KLONDIKE5</value> |
|
415 |
<type>work</type> |
|
416 |
</phoneNumbers> |
|
417 |
<phoneNumbers> |
|
418 |
<value>650-123-4567</value> |
|
419 |
<type>mobile</type> |
|
420 |
</phoneNumbers> |
|
421 |
<ims> |
|
422 |
<value>plaxodev8</value> |
|
423 |
<type>aim</type> |
|
424 |
</ims> |
|
425 |
<photos> |
|
426 |
<value>http://sample.site.org/photos/12345.jpg</value> |
|
427 |
<type>thumbnail</type> |
|
428 |
</photos> |
|
429 |
<tags> |
|
430 |
<value>plaxo guy</value> |
|
431 |
</tags> |
|
432 |
<relationships> |
|
433 |
<value>friend</value> |
|
434 |
</relationships> |
|
435 |
<addresses> |
|
436 |
<formatted>742 Evergreen Terrace |
|
437 |
Suite 123 |
|
438 |
Springfield VT 12345 USA</formatted> |
|
439 |
<type>home</type> |
|
440 |
<streetAddress>742 Evergreen Terrace |
|
441 |
Suite 123</streetAddress> |
|
442 |
<locality>Springfield</locality> |
|
443 |
<region>VT</region> |
|
444 |
<postalCode>12345</postalCode> |
|
445 |
<country>USA</country> |
|
446 |
</addresses> |
|
447 |
<organizations> |
|
448 |
<name>Burns Worldwide</name> |
|
449 |
<title>Head Bee Guy</title> |
|
450 |
</organizations> |
|
451 |
<accounts> |
|
452 |
<domain>plaxo.com</domain> |
|
453 |
<userid>2706</userid> |
|
454 |
</accounts> |
|
455 |
</entry> |
|
456 |
<entry> |
|
457 |
<id>3</id> |
|
458 |
<displayName>David Larlet</displayName> |
|
459 |
<name> |
|
460 |
<familyName>Larlet</familyName> |
|
461 |
<givenName>David</givenName> |
|
462 |
</name> |
|
463 |
<preferredUsername>david</preferredUsername> |
|
464 |
</entry> |
|
465 |
</response> |
|
376 |
466 |
>>> response = c.get("/portablecontacts/@me/@all/1/", {'format': 'xml'}) |
377 |
467 |
>>> response.status_code |
378 |
468 |
200 |
| … | … | @@ -380,7 +470,8 @@ XML representation:: |
380 |
470 |
<?xml version="1.0" encoding="utf-8"?> |
381 |
471 |
<response> |
382 |
472 |
<entry> |
383 |
|
|
473 |
<id>1</id> |
|
474 |
<displayName>Minimal Contact</displayName> |
|
384 |
475 |
</entry> |
385 |
476 |
</response> |
386 |
477 |
