W dniu 29.05.2012 02:28, Russell Keith-Magee pisze:
> Hi Piotr;
>
> Apologies for the delay in responding to your updated API.
>
> On Tue, May 22, 2012 at 6:59 AM, Piotr Grabowski<
grabow...@gmail.com> wrote:
>> I do some changes to my previous API: (
https://gist.github.com/2597306<-
>> change are included)
>>
>> * which fields of object are default serialized. It's depend on
>> include_default_field but opposite to Tom Christie solution it's default
>> value is True so all fields (eventually specified in Meta.model_fields) are
>> present
> Field options:
> ~~~~~~~~~~
>
> * There's a complication here that doesn't make sense to me.
> Following your syntax, the following would appear to be legal:
>
> class FieldA(Field):
> def serialize(�):
> def deserialize(�):
>
> class FieldB(Field):
> to = FieldA()
>
> def serialize(�):
> def deserialize(�):
>
> class FieldC(Field):
> to = FieldB(attribute=True)
>
> def serialize(�):
> def deserialize(�):
>
> i.e., if Field allows declaration style definitions, and Field can be
> *used* in declaration style definitions, then it's possible to define
> them in a nested fashion -- at which point, it isn't clear to me what
> is going to be output.
>
> It seems to me that "attribute" shouldn't be an option on a field
> declaration; it should either be something that's encompassed in a
> similar way to serialise/deserialize (i.e., either additional
> input/output from the serialise methods, or a parallel pair of
> methods), or the use of a Field as a declarative definition implies
> that it is of type attribute, and prevents the use of field types that
> themselves have attributes.
In example that You present I thought about raising an exception when the FieldC is defined. Another option is to define class as being attribute:
class FieldB(Field):
to = FieldA()
def serialize(�):
def deserialize(�):
class Meta:
attribute=True
Then raise an exception when FieldB is defined because of 'to' field. Still one of my principle is to have one Serializer for all formats (or at least possibility to serialize Serializer in each format) and attribute is something really problematic.
About value returns by Field.serialize (Serializer.serialize in general) - now it is dict with key __attribute__, maybe better will be to return tuple (dict/field_value, attributes_dict) because of issues if there is no field_name and attributes are present.
>
> Field methods:
> ~~~~~~~~~~~
>
> * serialize_value(), deserialize_value(); this is bike shedding, but
> is there any reason to not use just "serialize() and deserialize()"?
I'm using serialize and deserialize in my code.
Serializer.serialize(...) returns native python datatype. It's matter
of naming but in my opinion serialize is method that should return
serialized Field/ObjectSerializer not only part of result
(serialized_value returns only part of data needed for Field serialization)
>
> ObjectSerializer methods:
>
> * Why does ObjectSerializer have options at all? How can it be "meta"
> operating on a generic object? Consider -- if you pass in an instance
> of an object, you'll need to use obj.field_name to access fields; if
> you pass in a dictionary, you'll need to use obj['field_name']. And if
> you're given a generic object what's the list of default fields to
> serialize?
>
> Like I said last time, ObjectSerializer should be completely
> definition based. Look at Django's Form base class - it has no "meta"
> concept -- it's fully declaration based. Then there's ModelForm, which
> has a meta class; but the output of the ModelForm could be completely
> manually generated using a base Form.
Ok, I think I get this idea finally. Before I think about class Meta
more like options for class where it is. ObjectSerializer now is more
like ModelForm than like Form. I have idea how to rewrite it and I will
notice You when it will be done.
> * I mentioned this last time -- why is class_name a meta option,
> rather than a method on the base class with a default implementation?
> Having it as an Meta attribute
I answered You last time, I should add this to proposal. Probably I
don't understand the issue.
get_class(self, data):
if self._meta.class_name is not None:
if isinstance(self._meta.class_name, str):
return object_from_string(data['self._meta.class_name'])
else:
return self._meta.class_name
raise Exception('No class for deserialization provided')
If someone wants more sophisticated class from data resolving then he
can override get_class.
When I rewrite ObjectSerializer it will be different than this but my
idea is to have class_name as short cut for writing method get_class.
>
> * I'm not wild about the way related_serializer seems to work,
> either. Again, like class_name, it seems like it should be a method,
> not an option. By making it an option, you're assuming that it will
> have a single obvious value, which definitely won't be true -- e.g., I
> have an object with relations to users, groups and permissions; I want
> to output users as a list of nested objects, permissions as a list of
> natural keys, and groups as a list of primary keys.
related_serialized is default way to serialized related field:
class MySerializer(Serializer):
users = NestedSerializer()
permissions = NaturalKeyField()
class Meta:
related_serializer=PkField()
In Your example where there are only 3 related fields is unnecessary but
if I have object with many related fields, each of them should be
serialized as pk and only few as for example natural keys?
related_serializer is quite useful in that case.
In Serializer it is actually method for getting field serializer. (Of
course it will be expanded)
def get_serializer_for_field(self, field_name): # for all fields that
has not defined serializers
return self.opts.field_serializer()
>
> * I'm not sure I see why include_default_fields is needed. Isn't this
> implied by the values for "fields" and "exclude"? i.e., if fields or
> exclude is defined, you're not including everything by default;
> otherwise you are. Why the additional setting? What's the interaction
> of include_default_fields with fields and exclude?
Yes, you right. I will change that.
>
> * I don't understand what follow_object is trying to do. Isn't the
> issue here whether you use a serializer that just outputs a primary
> key, or an object that outputs field values? And if it's the latter,
> the sub-serializer determines how deep things go?
Tom Christie asked me a question:
> In your dump data serializer, how do you distinguish that the 'fields'
> field is the entire object being serialized rather than the 'fields'
> attribute of the object being serialized?
It was related to:
class YJDumpDataSerializer(ModelSerializer):
pk = PkField(attribute=True)
model = ModelNameField(attribute=True)
fields = ModelFieldsSerializer()
I don't understand him and gave wrong answer.
Suppose YJDumpDataSerializer is serializing object X. The question is on
which object should ModelFieldSerializer work - on object returned by
X.fields or on X itself. Default it's X.fields. In this case
ModelFieldsSerialize should work on X. How can I tell
ModelFieldsSerializer that it should work on X itself?
follow_object=False is for that. Maybe it should be given in
instantiation: ModelFieldSerializer(follow_object=False) ?
> ModelSerializer options:
>
> * I'm really not a fan of model_fields. This seems like a short cut
> that will make the implementation a whole lot more complex, and
> ultimately is much less explicit than just naming the fields that you
> want to serialize.
>
I thought it will be useful short cut but now I can agree with you. I
will change that
>> I'm aware that there will be lot of small issues but I believe that ideas
>> are good.
> I'm still optimistic, but there's still some fundamental issues here
> -- in particular, the existence of Meta on ObjectSerializer, and the
> way that attributes on XML tags are being handled. I don't think we've
> hit any blockers, but we need to get these sorted out before you start
> producing too much code.
>
> Yours,
> Russ Magee %-)
>
--
Piotr Grabowski