Skip to content

Commit 21fb038

Browse files
author
Jan Schrewe
committed
Make sure not to use LazyDocumentMetaWrapper as doc's meta for jschrewe#61
1 parent 703965c commit 21fb038

File tree

2 files changed

+47
-30
lines changed

2 files changed

+47
-30
lines changed

mongodbforms/documentoptions.py

Lines changed: 29 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,9 @@ def to(self, value):
4444

4545

4646
class PkWrapper(object):
47+
editable = False
48+
fake = False
49+
4750
def __init__(self, wrapped):
4851
self.obj = wrapped
4952

@@ -118,6 +121,8 @@ class DocumentMetaWrapper(MutableMapping):
118121
_meta = None
119122
concrete_model = None
120123
concrete_managers = []
124+
virtual_fields = []
125+
auto_created = False
121126

122127
def __init__(self, document, meta=None):
123128
super(DocumentMetaWrapper, self).__init__()
@@ -127,9 +132,10 @@ def __init__(self, document, meta=None):
127132
# here for now always the document
128133
self.concrete_model = document
129134
if meta is None:
130-
self._meta = getattr(document, '_meta', {})
131-
else:
132-
self._meta = meta
135+
meta = getattr(document, '_meta', {})
136+
if isinstance(meta, LazyDocumentMetaWrapper):
137+
meta = meta._meta
138+
self._meta = meta
133139

134140
try:
135141
self.object_name = self.document.__name__
@@ -143,9 +149,9 @@ def __init__(self, document, meta=None):
143149
self._setup_document_fields()
144150
# Setup self.pk if the document has an id_field in it's meta
145151
# if it doesn't have one it's an embedded document
146-
if 'id_field' in self._meta:
147-
self.pk_name = self._meta['id_field']
148-
self._init_pk()
152+
#if 'id_field' in self._meta:
153+
# self.pk_name = self._meta['id_field']
154+
self._init_pk()
149155

150156
def _setup_document_fields(self):
151157
for f in self.document._fields.values():
@@ -183,16 +189,27 @@ def _init_pk(self):
183189
184190
The function also adds a _get_pk_val method to the document.
185191
"""
186-
pk_field = getattr(self.document, self.pk_name)
192+
if 'id_field' in self._meta:
193+
self.pk_name = self._meta['id_field']
194+
pk_field = getattr(self.document, self.pk_name)
195+
else:
196+
pk_field = None
187197
self.pk = PkWrapper(pk_field)
188-
self.pk.name = self.pk_name
189-
self.pk.attname = self.pk_name
190-
191-
self.document._pk_val = pk_field
192198

193199
def _get_pk_val(self):
194200
return self._pk_val
195-
patch_document(_get_pk_val, self.document)
201+
202+
if pk_field is not None:
203+
self.pk.name = self.pk_name
204+
self.pk.attname = self.pk_name
205+
self.document._pk_val = pk_field
206+
patch_document(_get_pk_val, self.document)
207+
else:
208+
self.pk.fake = True
209+
# this is used in the admin and used to determine if the admin
210+
# needs to add a hidden pk field. It does not for embedded fields.
211+
# So we pretend to have an editable pk field and just ignore it otherwise
212+
self.pk.editable = True
196213

197214
@property
198215
def app_label(self):

mongodbforms/documents.py

Lines changed: 18 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -832,7 +832,13 @@ def inlineformset_factory(document, form=DocumentForm,
832832
class EmbeddedDocumentFormSet(BaseDocumentFormSet):
833833
def __init__(self, data=None, files=None, save_as_new=False,
834834
prefix=None, queryset=[], parent_document=None, **kwargs):
835-
self.parent_document = parent_document
835+
if parent_document is not None:
836+
self.parent_document = parent_document
837+
838+
if 'instance' in kwargs:
839+
instance = kwargs.pop('instance')
840+
if parent_document is None:
841+
self.parent_document = instance
836842

837843
queryset = getattr(self.parent_document,
838844
self.form._meta.embedded_field)
@@ -848,7 +854,8 @@ def _construct_form(self, i, **kwargs):
848854
# a huge amount of time iterating over the list field on form __init__
849855
emb_list = getattr(self.parent_document,
850856
self.form._meta.embedded_field)
851-
if emb_list is not None and len(emb_list) < i:
857+
858+
if emb_list is not None and len(emb_list) > i:
852859
defaults['position'] = i
853860
defaults.update(kwargs)
854861

@@ -878,22 +885,15 @@ def save(self, commit=True):
878885
objs = objs or []
879886

880887
if commit and self.parent_document is not None:
881-
# The thing about formsets is that the base use case is to edit
882-
# *all* of the associated objects on a model. As written, using
883-
# these FormSets this way will cause the existing embedded
884-
# documents to get saved along with a copy of themselves plus any
885-
# new ones you added.
886-
#
887-
# The only way you could do "updates" of existing embedded document
888-
# fields is if those embedded documents had ObjectIDs of their own,
889-
# which they don't by default in Mongoengine.
890-
#
891-
# In this case it makes the most sense to simply replace the
892-
# embedded field with the new values gathered form the formset,
893-
# rather than adding the new values to the existing values, because
894-
# the new values will almost always contain the old values (with
895-
# the default use case.)
896-
setattr(self.parent_document, self.form._meta.embedded_field, objs)
888+
field = self.parent_document._fields.get(self.form._meta.embedded_field, None)
889+
if isinstance(field, EmbeddedDocumentField):
890+
try:
891+
obj = objs[0]
892+
except IndexError:
893+
obj = None
894+
setattr(self.parent_document, self.form._meta.embedded_field, obj)
895+
else:
896+
setattr(self.parent_document, self.form._meta.embedded_field, objs)
897897
self.parent_document.save()
898898

899899
return objs

0 commit comments

Comments
 (0)