Skip to content

Commit 6121acc

Browse files
author
Jan Schrewe
committed
Removed mongotools dependency. Updated read me for pypi release. Small code cleanups.
1 parent 7d485e8 commit 6121acc

File tree

9 files changed

+578
-138
lines changed

9 files changed

+578
-138
lines changed

LICENSE.txt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
Copyright (c) Jan Schrewe.
1+
Copyright (c) 2010-2011, Jan Schrewe (jan@schafproductions.com)
22
All rights reserved.
33

44
Redistribution and use in source and binary forms, with or without modification,
@@ -11,7 +11,7 @@ are permitted provided that the following conditions are met:
1111
notice, this list of conditions and the following disclaimer in the
1212
documentation and/or other materials provided with the distribution.
1313

14-
3. Neither the name of django-mongoadmin nor the names of its contributors
14+
3. Neither the name of django-mongodbforms nor the names of its contributors
1515
may be used to endorse or promote products derived from this software
1616
without specific prior written permission.
1717

README.txt

Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
django mongodbforms
2+
===================
3+
4+
This is an implementation of django's model forms for mongoengine
5+
documents.
6+
7+
Requirements
8+
------------
9+
10+
- `mongoengine <http://mongoengine.org/>`_
11+
- `mongotools <https://github.com/wpjunior/django-mongotools>`_
12+
13+
Usage
14+
-----
15+
16+
mongodbforms supports forms for normal documents and embedded documents.
17+
18+
Normal documents
19+
~~~~~~~~~~~~~~~~
20+
21+
To use mongodbforms with normal documents replace djangos forms with
22+
mongodbform forms.
23+
24+
::
25+
26+
from mongodbforms import DocumentForm
27+
28+
class BlogForm(DocumentForm)
29+
...
30+
31+
Embedded documents
32+
~~~~~~~~~~~~~~~~~~
33+
34+
For embedded documents use ``EmbeddedDocumentForm``. The Meta-object of
35+
the form has to be provided with an embedded field name. The embedded
36+
object is appended to this. The form constructor takes an additional
37+
argument: The document the embedded document gets added to.
38+
39+
If the form is saved the new embedded object is automatically added to
40+
the provided parent document. If the embedded field is a list field the
41+
embedded document is appended to the list, if it is a plain embedded
42+
field the current object is overwritten. Note that the parent document
43+
is not saved.
44+
45+
::
46+
47+
# forms.py
48+
from mongodbforms import EmbeddedDocumentForm
49+
50+
class MessageForm(EmbeddedDocumentForm):
51+
class Meta:
52+
document = Message
53+
embedded_field_name = 'messages'
54+
55+
fields = ['subject', 'sender', 'message',]
56+
57+
# views.py
58+
form = MessageForm(parent_document=some_document, ...)
59+
60+
Documentation
61+
-------------
62+
63+
In theory the documentation `Django's
64+
modelform <https://docs.djangoproject.com/en/dev/topics/forms/modelforms/>`_
65+
documentation should be all you need (except for one exception; read
66+
on). If you find a discrepancy between something that mongodbforms does
67+
and what Django's documentation says, you have most likely found a bug.
68+
Please `report
69+
it <https://github.com/jschrewe/django-mongodbforms/issues>`_.
70+
71+
Form field generation
72+
~~~~~~~~~~~~~~~~~~~~~
73+
74+
Because the fields on mongoengine documents have no notion of form
75+
fields every mongodbform uses a generator class to generate the form
76+
field for a db field, which is not explicitly set.
77+
78+
If you want to use your own generator class you can use the
79+
``formfield_generator`` option on the form's Meta class.
80+
81+
::
82+
83+
# generator.py
84+
from mongodbforms.fieldgenerator import MongoFormFieldGenerator
85+
86+
class MyFieldGenerator(MongoFormFieldGenerator):
87+
...
88+
89+
# forms.py
90+
from mongodbforms import DocumentForm
91+
92+
from generator import MyFieldGenerator
93+
94+
class MessageForm(DocumentForm):
95+
class Meta:
96+
formfield_generator = MyFieldGenerator
97+

mongodbforms/documentoptions.py

Lines changed: 40 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,9 @@
11
import sys
22

33
from django.db.models.fields import FieldDoesNotExist
4-
from django.db.models.loading import app_cache_ready
54

65
from mongoengine.fields import ReferenceField
76

8-
#class PkWrapper(object):
9-
# """
10-
# Wraps an immutable class (like mongoengine's pk field) so that attributes can be added.
11-
# """
12-
# def __init__(self, baseObject):
13-
# self.__class__ = type(baseObject.__class__.__name__, (self.__class__, baseObject.__class__), {})
14-
# self.__dict__ = baseObject.__dict__
15-
167
class PkWrapper(object):
178
def __init__(self, wrapped):
189
self.obj = wrapped
@@ -27,33 +18,33 @@ def __setattr__(self, attr, value):
2718
setattr(self.obj, attr, value)
2819
super(PkWrapper, self).__setattr__(attr, value)
2920

30-
class AdminOptions(object):
21+
class DocumentMetaWrapper(object):
3122
"""
3223
Used to store mongoengine's _meta dict to make the document admin
3324
as compatible as possible to django's meta class on models.
3425
"""
26+
index_background = None
27+
collection = None
28+
queryset_class = None
29+
allow_inheritance = None
30+
max_size = None
31+
ordering = None
32+
id_field = None
33+
indexes = None
34+
index_drop_dups = None
35+
unique_indexes = None
36+
app_label = None
37+
max_documents = None
38+
module_name = None
39+
index_opts = None
40+
verbose_name = None
41+
verbose_name_plural = None
42+
has_auto_field = False
43+
proxy = []
44+
parents = {}
45+
many_to_many = []
46+
3547
def __init__(self, document):
36-
self.index_background = None
37-
self.collection = None
38-
self.queryset_class = None
39-
self.allow_inheritance = None
40-
self.max_size = None
41-
self.ordering = None
42-
self.id_field = None
43-
self.indexes = None
44-
self.index_drop_dups = None
45-
self.unique_indexes = None
46-
self.app_label = None
47-
self.max_documents = None
48-
self.module_name = None
49-
self.index_opts = None
50-
self.verbose_name = None
51-
self.verbose_name_plural = None
52-
self.has_auto_field = False
53-
self.proxy = []
54-
self.parents = {}
55-
self.many_to_many = []
56-
5748
self.document = document
5849
self.meta = document._meta
5950

@@ -100,22 +91,24 @@ def init_pk(self):
10091
10192
The function also adds a _get_pk_val method to the document.
10293
"""
103-
if self.id_field is not None:
104-
try:
105-
pk_field = getattr(self.document, self.id_field)
106-
self._pk = PkWrapper(pk_field)
107-
self._pk.name = self.id_field
108-
self._pk.attname = self.id_field
109-
self._pk_name = self.id_field
94+
if self.id_field is None:
95+
return
96+
97+
try:
98+
pk_field = getattr(self.document, self.id_field)
99+
self._pk = PkWrapper(pk_field)
100+
self._pk.name = self.id_field
101+
self._pk.attname = self.id_field
102+
self._pk_name = self.id_field
110103

111-
self.document._pk_val = getattr(self.document, self.pk_name)
112-
# avoid circular import
113-
from mongoadmin.util import patch_document
114-
def _get_pk_val(self):
115-
return self._pk_val
116-
patch_document(_get_pk_val, self.document)
117-
except AttributeError:
118-
return
104+
self.document._pk_val = getattr(self.document, self.pk_name)
105+
# avoid circular import
106+
from mongoadmin.util import patch_document
107+
def _get_pk_val(self):
108+
return self._pk_val
109+
patch_document(_get_pk_val, self.document)
110+
except AttributeError:
111+
return
119112

120113
def get_add_permission(self):
121114
return 'add_%s' % self.object_name.lower()
@@ -159,7 +152,7 @@ def _init_field_cache(self):
159152
for f in self.document._fields.itervalues():
160153
if isinstance(f, ReferenceField):
161154
model = f.document_type
162-
model._admin_opts = AdminOptions(model)
155+
model._admin_opts = DocumentMetaWrapper(model)
163156
self._field_cache[model._admin_opts.module_name] = (f, model, False, False)
164157
else:
165158
self._field_cache[f.name] = (f, None, True, False)

mongodbforms/documents.py

Lines changed: 10 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,8 @@
1717
from mongoengine.base import ValidationError
1818
from mongoengine.connection import _get_db
1919

20-
from util import MongoFormFieldGenerator
21-
from documentoptions import AdminOptions
20+
from fieldgenerator import MongoDefaultFormFieldGenerator
21+
from documentoptions import DocumentMetaWrapper
2222

2323

2424
def _get_unique_filename(name):
@@ -134,7 +134,7 @@ def document_to_dict(instance, fields=None, exclude=None):
134134
return data
135135

136136
def fields_for_document(document, fields=None, exclude=None, widgets=None, \
137-
formfield_callback=None, field_generator=MongoFormFieldGenerator):
137+
formfield_callback=None, field_generator=MongoDefaultFormFieldGenerator):
138138
"""
139139
Returns a ``SortedDict`` containing form fields for the given model.
140140
@@ -195,13 +195,15 @@ class ModelFormOptions(object):
195195
def __init__(self, options=None):
196196
self.document = getattr(options, 'document', None)
197197
self.model = self.document
198-
if self.model is not None and isinstance(self.model._meta, dict):
199-
self.model._admin_opts = AdminOptions(self.model)
200-
self.model._meta = self.model._admin_opts
198+
# set up the document meta wrapper if document meta is a dict
199+
if self.document is not None and isinstance(self.document._meta, dict):
200+
self.document._admin_opts = DocumentMetaWrapper(self.document)
201+
self.document._meta = self.document._admin_opts
201202
self.fields = getattr(options, 'fields', None)
202203
self.exclude = getattr(options, 'exclude', None)
203204
self.widgets = getattr(options, 'widgets', None)
204205
self.embedded_field = getattr(options, 'embedded_field_name', None)
206+
self.formfield_generator = getattr(options, 'formfield_generator', None)
205207

206208

207209
class DocumentFormMetaclass(type):
@@ -222,7 +224,7 @@ def __new__(cls, name, bases, attrs):
222224

223225
opts = new_class._meta = ModelFormOptions(getattr(new_class, 'Meta', None))
224226
if opts.document:
225-
formfield_generator = getattr(opts, 'formfield_generator', MongoFormFieldGenerator)
227+
formfield_generator = getattr(opts, 'formfield_generator', MongoDefaultFormFieldGenerator)
226228

227229
# If a model is defined, extract form fields from it.
228230
fields = fields_for_document(opts.document, opts.fields,
@@ -474,6 +476,7 @@ def save(self, commit=True):
474476
raise ValueError("The %s could not be saved because the data didn't"
475477
" validate." % self.instance.__class__.__name__)
476478

479+
477480
if commit:
478481
l = getattr(self.parent_document, self._meta.embedded_field)
479482
l.append(self.instance)
@@ -513,24 +516,6 @@ def initial_form_count(self):
513516
return len(self.get_queryset())
514517
return super(BaseDocumentFormSet, self).initial_form_count()
515518

516-
def _construct_form(self, i, **kwargs):
517-
#if self.is_bound and i < self.initial_form_count():
518-
# Import goes here instead of module-level because importing
519-
# django.db has side effects.
520-
#from django.db import connections
521-
# pk_key = "%s-%s" % (self.add_prefix(i), self.model._meta.pk.name)
522-
# pk = self.data[pk_key]
523-
# pk_field = self.model._meta.pk
524-
# pk = pk_field.get_db_prep_lookup('exact', pk,
525-
# connection=connections[self.get_queryset().db])
526-
# if isinstance(pk, list):
527-
# pk = pk[0]
528-
# kwargs['instance'] = self._existing_object(pk)
529-
#if i < self.initial_form_count() and not kwargs.get('instance'):
530-
# kwargs['instance'] = self.get_queryset()[i]
531-
form = super(BaseDocumentFormSet, self)._construct_form(i, **kwargs)
532-
return form
533-
534519
def get_queryset(self):
535520
return self._queryset
536521

@@ -582,37 +567,6 @@ def get_date_error_message(self, date_check):
582567
def get_form_error(self):
583568
return ugettext("Please correct the duplicate values below.")
584569

585-
def add_fields(self, form, index):
586-
# """Add a hidden field for the object's primary key."""
587-
# from django.db.models import AutoField, OneToOneField, ForeignKey
588-
# self._pk_field = pk = self.model._meta.pk
589-
# # If a pk isn't editable, then it won't be on the form, so we need to
590-
# # add it here so we can tell which object is which when we get the
591-
# # data back. Generally, pk.editable should be false, but for some
592-
# # reason, auto_created pk fields and AutoField's editable attribute is
593-
# # True, so check for that as well.
594-
# def pk_is_not_editable(pk):
595-
# return ((not pk.editable) or (pk.auto_created or isinstance(pk, AutoField))
596-
# or (pk.rel and pk.rel.parent_link and pk_is_not_editable(pk.rel.to._meta.pk)))
597-
# if pk_is_not_editable(pk) or pk.name not in form.fields:
598-
# if form.is_bound:
599-
# pk_value = form.instance.pk
600-
# else:
601-
# try:
602-
# if index is not None:
603-
# pk_value = self.get_queryset()[index].pk
604-
# else:
605-
# pk_value = None
606-
# except IndexError:
607-
# pk_value = None
608-
# if isinstance(pk, OneToOneField) or isinstance(pk, ForeignKey):
609-
# qs = pk.rel.to._default_manager.get_query_set()
610-
# else:
611-
# qs = self.model._default_manager.get_query_set()
612-
# qs = qs.using(form.instance._state.db)
613-
# #form.fields[self._pk_field.name] = ModelChoiceField(qs, initial=pk_value, required=False, widget=HiddenInput)
614-
super(BaseDocumentFormSet, self).add_fields(form, index)
615-
616570
def documentformset_factory(document, form=DocumentForm, formfield_callback=None,
617571
formset=BaseDocumentFormSet,
618572
extra=1, can_delete=False, can_order=False,

0 commit comments

Comments
 (0)