Skip to content

Commit

Permalink
Merge pull request j4mie#13 from ericmoritz/related_name
Browse files Browse the repository at this point in the history
Added related_name to ModelField and ModelCollectionField
  • Loading branch information
ericmoritz committed Aug 2, 2012
2 parents c9127d2 + 2b2f52a commit f895245
Show file tree
Hide file tree
Showing 4 changed files with 80 additions and 5 deletions.
23 changes: 22 additions & 1 deletion README.md
Expand Up @@ -208,9 +208,28 @@ Then you can access the data as follows:
>>> m.second_item.nested_item
u'Some nested value'

`ModelField` takes an optional `related_name` argument. The
`related_name` is the name to use for the related model to refer back
to the outer model:

class Person(Model):
name = CharField()
car = ModelField(Car, related_name="owner")

class Car(Model):
make = CharField()
model = CharField()

>>> person = Person.from_dict(some_data)
>>> person.car.owner == person
True

#### ModelCollectionField

Use this field when your source data dictionary contains a list of dictionaries. It takes a single required argument, which is the name of the nested class that each item in the list should be converted to. For example:
Use this field when your source data dictionary contains a list of
dictionaries. It takes a single required argument, which is the name
of the nested class that each item in the list should be converted
to. For example:

some_data = {
'list': [
Expand All @@ -236,6 +255,8 @@ Use this field when your source data dictionary contains a list of dictionaries.
>>> [item.value for item in m.list]
[u'First value', u'Second value', u'Third value']

`ModelCollectionField` takes an optional `related_name` argument which
serves the same purpose as it does with `ModelField`.

## (Un)license

Expand Down
24 changes: 20 additions & 4 deletions micromodels/fields.py
Expand Up @@ -157,8 +157,11 @@ def to_python(self):
class WrappedObjectField(BaseField):
"""Superclass for any fields that wrap an object"""

def __init__(self, wrapped_class, **kwargs):
def __init__(self, wrapped_class, related_name=None, **kwargs):
self._wrapped_class = wrapped_class
self._related_name = related_name
self._related_obj = None

BaseField.__init__(self, **kwargs)


Expand Down Expand Up @@ -199,9 +202,15 @@ class MyMainModel(micromodels.Model):
"""
def to_python(self):
if isinstance(self.data, self._wrapped_class):
return self.data
obj = self.data
else:
return self._wrapped_class.from_dict(self.data or {})
obj = self._wrapped_class.from_dict(self.data or {})

# Set the related object to the related field
if self._related_name is not None:
setattr(obj, self._related_name, self._related_obj)

return obj

def to_serial(self, model_instance):
return model_instance.to_dict(serial=True)
Expand Down Expand Up @@ -241,7 +250,14 @@ class MyMainModel(micromodels.Model):
"""
def to_python(self):
return [self._wrapped_class.from_dict(item) for item in self.data]
object_list = []
for item in self.data:
obj = self._wrapped_class.from_dict(item)
if self._related_name is not None:
setattr(obj, self._related_name, self._related_obj)
object_list.append(obj)

return object_list

def to_serial(self, model_instances):
return [instance.to_dict(serial=True) for instance in model_instances]
Expand Down
1 change: 1 addition & 0 deletions micromodels/models.py
Expand Up @@ -96,6 +96,7 @@ def __setattr__(self, key, value):
if key in self._fields:
field = self._fields[key]
field.populate(value)
field._related_obj = self
super(Model, self).__setattr__(key, field.to_python())
else:
super(Model, self).__setattr__(key, value)
Expand Down
37 changes: 37 additions & 0 deletions tests.py
Expand Up @@ -315,6 +315,19 @@ class Post(micromodels.Model):
post = Post.from_dict(data)
self.assertEqual(post.to_dict(serial=True), data)

def test_related_name(self):
class User(micromodels.Model):
name = micromodels.CharField()

class Post(micromodels.Model):
title = micromodels.CharField()
author = micromodels.ModelField(User, related_name="post")

data = {'title': 'Test Post', 'author': {'name': 'Eric Martin'}}
post = Post.from_dict(data)
self.assertEqual(post.author.post, post)
self.assertEqual(post.to_dict(serial=True), data)

def test_failing_modelfield(self):
class SomethingExceptional(Exception):
pass
Expand Down Expand Up @@ -383,6 +396,30 @@ class User(micromodels.Model):
processed = eric.to_dict(serial=True)
self.assertEqual(processed, data)

def test_related_name(self):
class Post(micromodels.Model):
title = micromodels.CharField()

class User(micromodels.Model):
name = micromodels.CharField()
posts = micromodels.ModelCollectionField(Post, related_name="author")

data = {
'name': 'Eric Martin',
'posts': [
{'title': 'Post #1'},
{'title': 'Post #2'}
]
}

eric = User.from_dict(data)
processed = eric.to_dict(serial=True)
for post in eric.posts:
self.assertEqual(post.author, eric)

self.assertEqual(processed, data)


class FieldCollectionFieldTestCase(unittest.TestCase):

def test_field_collection_field_creation(self):
Expand Down

0 comments on commit f895245

Please sign in to comment.