Skip to content

Commit 4e4afd1

Browse files
authored
Merge pull request #84 from graphql-python/feat-support-file-field
Feat support file field
2 parents 4b2db8a + 5f8ed1f commit 4e4afd1

File tree

12 files changed

+187
-76
lines changed

12 files changed

+187
-76
lines changed

graphene_mongo/advanced_types.py

Lines changed: 39 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,49 @@
1+
import base64
12
import graphene
23

34

4-
__all__ = [
5-
'PointFieldType',
6-
'MultiPolygonFieldType'
7-
]
8-
9-
105
def _resolve_type_coordinates(self, info):
116
return self['coordinates']
127

138

9+
def _resolve_fs_field(field, name, default_value=None):
10+
v = getattr(field.instance, field.key)
11+
return getattr(v, name, default_value)
12+
13+
14+
def _resolve_content_type(self, info):
15+
return _resolve_fs_field(self, 'content_type')
16+
17+
18+
def _resolve_md5(self, info):
19+
return _resolve_fs_field(self, 'md5')
20+
21+
22+
def _resolve_chunk_size(self, info):
23+
return _resolve_fs_field(self, 'chunk_size', 0)
24+
25+
26+
def _resolve_length(self, info):
27+
return _resolve_fs_field(self, 'length', 0)
28+
29+
30+
def _resolve_data(self, info):
31+
v = getattr(self.instance, self.key)
32+
data = v.read()
33+
if data is not None:
34+
return base64.b64encode(data)
35+
return None
36+
37+
38+
class FileFieldType(graphene.ObjectType):
39+
40+
content_type = graphene.String(resolver=_resolve_content_type)
41+
md5 = graphene.String(resolver=_resolve_md5)
42+
chunk_size = graphene.Int(resolver=_resolve_chunk_size)
43+
length = graphene.Int(resolver=_resolve_length)
44+
data = graphene.String(resolver=_resolve_data)
45+
46+
1447
class _TypeField(graphene.ObjectType):
1548

1649
type = graphene.String()

graphene_mongo/converter.py

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -66,19 +66,24 @@ def convert_field_to_float(field, registry=None):
6666
return Float(description=get_field_description(field, registry), required=field.required)
6767

6868

69+
@convert_mongoengine_field.register(mongoengine.DateTimeField)
70+
def convert_field_to_datetime(field, registry=None):
71+
return DateTime(description=get_field_description(field, registry), required=field.required)
72+
73+
6974
@convert_mongoengine_field.register(mongoengine.DictField)
7075
@convert_mongoengine_field.register(mongoengine.MapField)
71-
def convert_dict_to_jsonstring(field, registry=None):
76+
def convert_field_to_jsonstring(field, registry=None):
7277
return JSONString(description=get_field_description(field, registry), required=field.required)
7378

7479

7580
@convert_mongoengine_field.register(mongoengine.PointField)
76-
def convert_point_to_field(field, register=None):
81+
def convert_point_to_field(field, registry=None):
7782
return Field(advanced_types.PointFieldType)
7883

7984

8085
@convert_mongoengine_field.register(mongoengine.PolygonField)
81-
def convert_polygon_to_field(field, register=None):
86+
def convert_polygon_to_field(field, registry=None):
8287
return Field(advanced_types.PolygonFieldType)
8388

8489

@@ -87,9 +92,9 @@ def convert_multipolygon_to_field(field, register=None):
8792
return Field(advanced_types.MultiPolygonFieldType)
8893

8994

90-
@convert_mongoengine_field.register(mongoengine.DateTimeField)
91-
def convert_field_to_datetime(field, registry=None):
92-
return DateTime(description=get_field_description(field, registry), required=field.required)
95+
@convert_mongoengine_field.register(mongoengine.FileField)
96+
def convert_file_to_field(field, registry=None):
97+
return Field(advanced_types.FileFieldType)
9398

9499

95100
@convert_mongoengine_field.register(mongoengine.ListField)

graphene_mongo/fields.py

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,9 @@
1111
from graphene.types.structures import Structure
1212
from graphql_relay.connection.arrayconnection import connection_from_list_slice
1313

14-
from .advanced_types import PointFieldType, MultiPolygonFieldType
14+
from .advanced_types import (
15+
FileFieldType, PointFieldType, MultiPolygonFieldType
16+
)
1517
from .converter import convert_mongoengine_field, MongoEngineConversionError
1618
from .registry import get_global_registry
1719
from .utils import get_model_reference_fields, get_node_from_global_id
@@ -64,6 +66,7 @@ def args(self, args):
6466
self._base_args = args
6567

6668
def _field_args(self, items):
69+
6770
def is_filterable(k):
6871
"""
6972
Args:
@@ -85,7 +88,7 @@ def is_filterable(k):
8588
if callable(getattr(converted, 'type', None)) \
8689
and isinstance(
8790
converted.type(),
88-
(PointFieldType, MultiPolygonFieldType, graphene.Union)):
91+
(FileFieldType, PointFieldType, MultiPolygonFieldType, graphene.Union)):
8992
return False
9093
return True
9194

@@ -102,6 +105,7 @@ def field_args(self):
102105

103106
@property
104107
def reference_args(self):
108+
105109
def get_reference_field(r, kv):
106110
field = kv[1]
107111
mongo_field = getattr(self.model, kv[0], None)
@@ -111,7 +115,7 @@ def get_reference_field(r, kv):
111115
_type = field.get_type()
112116
if _type:
113117
node = _type._type._meta
114-
if 'id' in node.fields and not issubclass(node.model, mongoengine.EmbeddedDocument):
118+
if 'id' in node.fields and not issubclass(node.model, (mongoengine.EmbeddedDocument,)):
115119
r.update({kv[0]: node.fields['id']._type.of_type()})
116120
return r
117121

45.8 KB
Loading

graphene_mongo/tests/models.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,10 @@
11
import mongoengine
22
from datetime import datetime
3+
from mongomock import gridfs
34

5+
gridfs.enable_gridfs_integration()
46
mongoengine.connect('graphene-mongo-test', host='mongomock://localhost', alias='default')
7+
# mongoengine.connect('graphene-mongo-test', host='mongodb://192.168.15.91/graphene-mongo-dev')
58

69

710
class Publisher(mongoengine.Document):
@@ -28,6 +31,7 @@ class Editor(mongoengine.Document):
2831
last_name = mongoengine.StringField(required=True, help_text="Editor's last name.")
2932
metadata = mongoengine.MapField(field=mongoengine.StringField(), help_text="Arbitrary metadata.")
3033
company = mongoengine.LazyReferenceField(Publisher)
34+
avatar = mongoengine.FileField()
3135

3236

3337
class Article(mongoengine.Document):

graphene_mongo/tests/setup.py

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import os
12
import pytest
23

34
from datetime import datetime
@@ -8,6 +9,13 @@
89
ParentWithRelationship, CellTower,
910
Publisher)
1011

12+
current_dirname = os.path.dirname(os.path.abspath(__file__))
13+
14+
15+
@pytest.fixture()
16+
def fixtures_dirname():
17+
return os.path.join(current_dirname, 'fixtures')
18+
1119

1220
@pytest.fixture(scope='module')
1321
def fixtures():
@@ -23,7 +31,12 @@ def fixtures():
2331
metadata={'age': '20', 'nickname': '$1'},
2432
company=publisher1
2533
)
34+
image_filename = os.path.join(
35+
current_dirname, 'fixtures', 'image.jpg')
36+
with open(image_filename, 'rb') as f:
37+
editor1.avatar.put(f, content_type='image/jpeg')
2638
editor1.save()
39+
2740
editor2 = Editor(
2841
id='2',
2942
first_name='Grant',

graphene_mongo/tests/test_converter.py

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
Article, Editor, EmbeddedArticle, Player, Reporter,
77
ProfessorMetadata, ProfessorVector, Publisher)
88
from .. import registry
9+
from .. import advanced_types
910
from ..converter import convert_mongoengine_field
1011
from ..fields import MongoengineConnectionField
1112
from ..types import MongoengineObjectType
@@ -80,24 +81,33 @@ def test_should_map_convert_json():
8081
def test_should_point_convert_field():
8182
graphene_type = convert_mongoengine_field(mongoengine.PointField())
8283
assert isinstance(graphene_type, graphene.Field)
84+
assert graphene_type.type == advanced_types.PointFieldType
8385
assert isinstance(graphene_type.type.type, graphene.String)
8486
assert isinstance(graphene_type.type.coordinates, graphene.List)
8587

8688

8789
def test_should_polygon_covert_field():
8890
graphene_type = convert_mongoengine_field(mongoengine.PolygonField())
8991
assert isinstance(graphene_type, graphene.Field)
92+
assert graphene_type.type == advanced_types.PolygonFieldType
9093
assert isinstance(graphene_type.type.type, graphene.String)
9194
assert isinstance(graphene_type.type.coordinates, graphene.List)
9295

9396

9497
def test_should_multipolygon_convert_field():
9598
graphene_type = convert_mongoengine_field(mongoengine.MultiPolygonField())
9699
assert isinstance(graphene_type, graphene.Field)
100+
assert graphene_type.type == advanced_types.MultiPolygonFieldType
97101
assert isinstance(graphene_type.type.type, graphene.String)
98102
assert isinstance(graphene_type.type.coordinates, graphene.List)
99103

100104

105+
def test_should_file_convert_field():
106+
graphene_type = convert_mongoengine_field(mongoengine.FileField())
107+
assert isinstance(graphene_type, graphene.Field)
108+
assert graphene_type.type == advanced_types.FileFieldType
109+
110+
101111
def test_should_field_convert_list():
102112
assert_conversion(mongoengine.ListField, graphene.List, field=mongoengine.StringField())
103113

@@ -297,8 +307,6 @@ class Meta:
297307

298308

299309
def test_should_generic_reference_convert_union():
300-
pass
301-
"""
302310
class A(MongoengineObjectType):
303311

304312
class Meta:
@@ -318,4 +326,3 @@ class Meta:
318326
Reporter._fields['generic_reference'], registry.get_global_registry())
319327
assert isinstance(generic_reference_field, graphene.Field)
320328
assert isinstance(generic_reference_field.type(), graphene.Union)
321-
"""

graphene_mongo/tests/test_fields.py

Lines changed: 16 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -6,22 +6,29 @@
66
def test_article_field_args():
77
field = MongoengineConnectionField(nodes.ArticleNode)
88

9-
field_args = ['id', 'headline', 'pub_date']
10-
assert set(field.field_args.keys()) == set(field_args)
9+
field_args = {'id', 'headline', 'pub_date'}
10+
assert set(field.field_args.keys()) == field_args
1111

12-
reference_args = ['editor', 'reporter']
13-
assert set(field.reference_args.keys()) == set(reference_args)
12+
reference_args = {'editor', 'reporter'}
13+
assert set(field.reference_args.keys()) == reference_args
1414

15-
default_args = ['after', 'last', 'first', 'before']
16-
args = field_args + reference_args + default_args
17-
assert set(field.args) == set(args)
15+
default_args = {'after', 'last', 'first', 'before'}
16+
args = field_args | reference_args | default_args
17+
assert set(field.args) == args
1818

1919

2020
def test_reporter_field_args():
2121
field = MongoengineConnectionField(nodes.ReporterNode)
2222

23-
field_args = ['id', 'first_name', 'last_name', 'email', 'awards']
24-
assert set(field.field_args.keys()) == set(field_args)
23+
field_args = {'id', 'first_name', 'last_name', 'email', 'awards'}
24+
assert set(field.field_args.keys()) == field_args
25+
26+
27+
def test_editor_field_args():
28+
field = MongoengineConnectionField(nodes.EditorNode)
29+
30+
field_args = {'id', 'first_name', 'last_name', 'metadata'}
31+
assert set(field.field_args.keys()) == field_args
2532

2633

2734
def test_field_args_with_property():

0 commit comments

Comments
 (0)