Login

XFN Form Field

Author:
jpwatts
Posted:
February 11, 2008
Language:
Python
Version:
.96
Score:
1 (after 1 ratings)

This is a newforms field for XFN relationships.

It normalizes input by removing excess whitespace, converting to lowercase and removing duplicates.

This field also validates the relationship according to the XFN profile: me can only appear by itself and, at most, one value from each of the family, friendship and geographical categories is allowed.

The XFN_* constants would probably be imported from somewhere else in practice, but are included here for simplicity.

 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
from django import newforms as forms


XFN_FAMILY_RELS = ('child', 'kin', 'parent', 'sibling', 'spouse')
XFN_FRIENDSHIP_RELS = ('acquaintance', 'contact', 'friend')
XFN_GEOGRAPHICAL_RELS = ('co-resident', 'neighbor')
XFN_IDENTITY_RELS = ('me',)
XFN_PHYSICAL_RELS = ('met',)
XFN_PROFESSIONAL_RELS = ('colleague', 'co-worker')
XFN_ROMANTIC_RELS = ('crush', 'date', 'muse', 'sweetheart')
XFN_RELS = (
    XFN_FAMILY_RELS + XFN_FRIENDSHIP_RELS + XFN_GEOGRAPHICAL_RELS
    + XFN_IDENTITY_RELS + XFN_PHYSICAL_RELS + XFN_PROFESSIONAL_RELS
    + XFN_ROMANTIC_RELS
)


xfn_family_rels = set(XFN_FAMILY_RELS)
xfn_friendship_rels = set(XFN_FRIENDSHIP_RELS)
xfn_geographical_rels = set(XFN_GEOGRAPHICAL_RELS)
xfn_rels = set(XFN_RELS)


class XFNField(forms.Field):
    """Field to normalize and validate an XFN relationship.

    Strips extra whitespace, converts to lowercase and removes duplicates.

    Enforces exclusivity for the ``me`` value and allows at most one value from
    each of the family, friendship and geographical categories.

    Sorts values alphabetically -- not required, but *feels* right.

    http://gmpg.org/xfn/11

    """
    default_error_messages = {
        'family': u'XFN allows only one family value.',
        'friendship': u'XFN allows only one friendship value.',
        'invalid': u'Enter a valid XFN relationship.',
        'geographical': u'XFN allows only one geographical value.',
        'me': u'The "me" relationship can\'t be used with other values.',
        'required': u'Enter an XFN relationship.'
    }

    def clean(self, value):
        value = super(XFNField, self).clean(value)

        if value in forms.fields.EMPTY_VALUES:
            return u''

        rels = set(value.strip().lower().split())
        if len(rels - xfn_rels):
            raise forms.ValidationError(self.error_messages['invalid'])
        if len(rels & xfn_family_rels) > 1:
            raise forms.ValidationError(self.error_messages['family'])
        if len(rels & xfn_friendship_rels) > 1:
            raise forms.ValidationError(self.error_messages['friendship'])
        if len(rels & xfn_geographical_rels) > 1:
            raise forms.ValidationError(self.error_messages['geographical'])
        if 'me' in rels and len(rels) > 1:
            raise forms.ValidationError(self.error_messages['me'])

        return u' '.join(sorted(rels))

    def widget_attrs(self, widget):
        return {'class': 'xfn'}

More like this

  1. Template tag - list punctuation for a list of items by shapiromatron 10 months, 4 weeks ago
  2. JSONRequestMiddleware adds a .json() method to your HttpRequests by cdcarter 11 months ago
  3. Serializer factory with Django Rest Framework by julio 1 year, 5 months ago
  4. Image compression before saving the new model / work with JPG, PNG by Schleidens 1 year, 6 months ago
  5. Help text hyperlinks by sa2812 1 year, 7 months ago

Comments

Please login first before commenting.