ReferenceField ignores its ordering

Inside a Plone 4.0 AT content-type we have the following sorted ReferenceField

ReferenceField('documents',
               keepReferencesOnCopy=1,
               required=False,
               relationship='useForReiter',
               multiValued=True,
               allowed_types=('Document', 'ContactInfoReferences'),
               widget = ReferenceBrowserWidget(
                    allow_search = True,
                    allow_browse = True,
                    show_indexes = False,
                    allow_sorting=True,
                    force_close_on_insert = False,
                    label = _(u'label_documents', default=u'Documents'),
                    description = '',
                    visible = {'edit' : 'visible', 'view' : 'visible' }
                    )

Now we are migrating to Plone 4.3.3 and we see that after the migration the sorting of the references is completely random.

With some debugging it seems that calling the mutator method is doing something similar.

Example

obj.getDocuments() return:

[<ATDocument at /isesite/en/copy_of_service-units/testlab-solar-thermal-systems-1/further-information>, <ATDocument at /isesite/en/copy_of_service-units/testlab-solar-thermal-systems-1/testlab-solar-thermal-systems>, <ATDocument at /isesite/en/copy_of_service-units/testlab-solar-thermal-systems-1/services>, <ATDocument at /isesite/en/copy_of_service-units/testlab-solar-thermal-systems-1/contacts-1>]

the original object ordering was:

[<ATDocument at /isesite/en/copy_of_service-units/testlab-solar-thermal-systems-1/testlab-solar-thermal-systems>, <ATDocument at /isesite/en/copy_of_service-units/testlab-solar-thermal-systems-1/services>, <ATDocument at /isesite/en/copy_of_service-units/testlab-solar-thermal-systems-1/contacts-1>, <ATDocument at /isesite/en/copy_of_service-units/testlab-solar-thermal-systems-1/further-information>]

We pass the original objects with their ordering to obj.setDocuments() and call

obj.getDocuments() again:

[<ATDocument at /isesite/en/copy_of_service-units/testlab-solar-thermal-systems-1/further-information>, <ATDocument at /isesite/en/copy_of_service-units/testlab-solar-thermal-systems-1/testlab-solar-thermal-systems>, <ATDocument at /isesite/en/copy_of_service-units/testlab-solar-thermal-systems-1/services>, <ATDocument at /isesite/en/copy_of_service-units/testlab-solar-thermal-systems-1/contacts-1>]

So obj.getDocument() returns the same ordering before and after calling obj.setObject()....

Is this a known issue?

-aj

From what I remember, yes, this is a known issue.

This is a snippet from an old project but it might help you:

from AccessControl import ClassSecurityInfo
from Products.Archetypes.Registry import registerField
from Products.Archetypes.public import ReferenceField
from Products.Archetypes.Field import LinesField, ObjectField, encode, config

class OrderedReferenceField(ReferenceField):
"""
use everything as is... Just store order of fields also.
"""

security = ClassSecurityInfo()

def __init__(self, *args, **kwargs):
    super(OrderedReferenceField, self).__init__(*args, **kwargs)

@property
def order_attr_name(self):
    return '_' + self.getName() + '_order'

def order(self, instance, results, compare=lambda x, y: x == y):
    new = []
    ordered = getattr(instance, self.order_attr_name, [])
    for uid in ordered:
        for index in range(len(results)):
            if compare(results[index], uid):
                new.append(results.pop(index))
                break
    # just append anything that is left ot the end...
    new.extend(results)

    return new

def find_ref(self, value, refs):
    for ref in refs:
        if ref.UID() == value:
            return ref
    return None

security.declarePrivate('get')
def get(self, instance, aslist=False, **kwargs):
    results = list(super(OrderedReferenceField, self).get(
        instance, aslist, **kwargs))
    return self.order(instance, results, lambda x, y: x.UID() == y)

security.declarePrivate('set')
def set(self, instance, value, **kwargs):
    super(OrderedReferenceField, self).set(instance, value, **kwargs)
    results = list(super(OrderedReferenceField, self).getRaw(instance))
    setattr(instance, self.order_attr_name, results)
security.declarePrivate('getRaw')
def getRaw(self, instance, aslist=False, **kwargs):
    res = super(OrderedReferenceField, self).getRaw(instance,
        aslist, **kwargs)
    return self.order(instance, res)

Thanks, this seems to work fine. So the 'allow_sorting=True' parameter appears completely broken and useless.

-aj

Please file a bug report.
Bitching doesn't fix shit.

Don't know if there differences between Plone 4.0 and 4.3, but on 4.3.4 referenced items sorting is also broken.

What I found is a lot simpler: the JavaScript of the referencebrowserwidget was broken due to refactoring.
This fixed my problem: https://github.com/plone/archetypes.referencebrowserwidget/pull/20

Sorry for revive this old topic but i'm experiencing some troubles even with @vangheem code.
It works fine the first time you save, but after that you cannot change the order anymore.

Looking trough Natham's code i noticed that in the "set" method of the class "OrderedReferenceField" the param "value" have the correct order. But if i print the variable "results" (and that it suppose to be the REAL value saved) have still the old value.

security.declarePrivate('set') def set(self, instance, value, **kwargs): super(OrderedReferenceField, self).set(instance, value, **kwargs) results = list(super(OrderedReferenceField, self).getRaw(instance)) print "====== Results" print results # Still have the old values print "======= Value" print value # Have the correct updated values setattr(instance, self.order_attr_name, results)

Any idea/suggestion to resolve this issue?

Here are my Plone specs:

Plone 4.3.7 (4311)
CMF 2.2.9
Zope 2.13.23
Python 2.7.9 (default, Mar 1 2015, 12:57:24) [GCC 4.9.2]
PIL 2.9.0 (Pillow)

The normal ReferenceField should work if you add the following line to it:
referencesSortable = True