On Mon, Mar 21, 2011 at 2:33 AM, Christophe Pettus <x...@thebuild.com> wrote:
> I'd like to make one more pitch for a slightly different implementation here. 
>  My concern with CompositeField isn't based on the fact that it doesn't map 
> one-to-one with a field in the table; it's that it doesn't have any of the 
> semantics that are associated with a field.  In particular, it can't be:
>
> - Assigned to.
> - Iterated over.
> - Or even have a value.

Obviously there's no code here yet, so we don't know exactly. I'd also
be -1 on an implementation of a CompositeField that didn't have those
values. However, it's reasonably easy to come up with a CompositeField
that is assignable, iterable, and has values. Here's the basics::

    class CompositeField(object):
        def __init__(self, *fields):
            self.fields = fields

        def contribute_to_class(self, cls, name):
            nt_name = "%s_%s" % (cls.__name__, name)
            nt_fields = " ".join(f.name for f in self.fields)
            self.nt = collections.namedtuple(nt_name, nt_fields)
            setattr(cls, name, self)

        def __get__(self, instance, owner):
            if instance:
                return self.nt._make(getattr(instance, f, None) for f
in self.nt._fields)
            raise AttributeError("Composite fields only work on instances.")

        def __set__(self, instance, value):
            for (field, val) in zip(self.nt._fields, value):
                setattr(instance, field, val)

It works, too::

    class Person(models.Model):
        first_name = models.CharField(max_length=100)
        last_name = models.CharField(max_length=100)
        name = CompositeField(first_name, last_name)

    # ...

    >>> p = Person(first_name="Jacob", last_name="KM")

    >>> p.name
      : Person_name(first_name='Jacob', last_name='KM')

    >>> p.name.last_name
      : 'KM'

    >>> p.name = ("John", "Doe")

    >>> p.last_name
      : 'Doe'

    >>> for f in p.name:
    ..:     print f
    ..:
    ..:
    John
    Doe

Fields even sorta get saved correctly to the DB with just these few
lines of code. Of course there's a lot missing here to correctly
handle actual composite keys -- this tiny example won't work in
querysets, for example -- but the basics of the Python-side behavior's
right there.

> My suggestion is to create an Index type that can be included in a class just 
> like a field can.

I think we're talking slightly different concerns here: I'm mostly
interested in the Python-side API, and to my eyes a composite field
matches more closely what's happening on the Python side of things.
Python's not generating an index, after all, so using something called
"index" for compositing multiple attributes together seems weird to
me. But at the DB level, "index" makes perfect sense. Thing is, we've
always tried to make Django's APIs behave well in Python *first*, and
then think about the DB concerns. And again, to me "composite field"
matches more closely the behavior we want out of the Python side of
things.

All that said, there's a lot to like about your Index proposal.
Perhaps there's a way we can merge these two things together somehow?

Jacob

-- 
You received this message because you are subscribed to the Google Groups 
"Django developers" group.
To post to this group, send email to django-developers@googlegroups.com.
To unsubscribe from this group, send email to 
django-developers+unsubscr...@googlegroups.com.
For more options, visit this group at 
http://groups.google.com/group/django-developers?hl=en.

Reply via email to