Giter Club home page Giter Club logo

Comments (4)

last-partizan avatar last-partizan commented on June 1, 2024

Hello, that's wonderful!

Post your patch, right now i don't have much time, but later i will apply it.

from django-mongoengine.

fmoro avatar fmoro commented on June 1, 2024

EmbeddedFields patch:

diff -rupN django-mongoengine.orig/django_mongoengine/forms/field_generator.py django-mongoengine/django_mongoengine/forms/field_generator.py
--- django-mongoengine.orig/django_mongoengine/forms/field_generator.py 2015-09-29 16:15:11.230067258 +0200
+++ django-mongoengine/django_mongoengine/forms/field_generator.py  2015-09-29 16:18:40.230067804 +0200
@@ -10,7 +10,7 @@ except ImportError:

 from mongoengine import ReferenceField as MongoReferenceField

-from fields import MongoCharField, ReferenceField, DocumentMultipleChoiceField, DictField
+from fields import MongoCharField, ReferenceField, DocumentMultipleChoiceField, DictField, EmbeddedDocumentField

 BLANK_CHOICE_DASH = [("", "---------")]

@@ -289,6 +289,18 @@ class MongoFormFieldGenerator(object):
         }
         return DictField(**defaults)

+    def generate_embeddeddocumentfield(self, field, **kwargs):
+        from documents import documentform_factory
+        defaults = {
+            'label': self.get_field_label(field),
+            'help_text': self.get_field_help_text(field),
+        }
+        form_class = EmbeddedDocumentField
+        defaults.update(kwargs)
+        form = form_class(documentform_factory(field.document_type), **defaults)
+        return form
+
+

 class MongoDefaultFormFieldGenerator(MongoFormFieldGenerator):
     """This class generates Django form-fields for mongoengine-fields."""
diff -rupN django-mongoengine.orig/django_mongoengine/forms/fields.py django-mongoengine/django_mongoengine/forms/fields.py
--- django-mongoengine.orig/django_mongoengine/forms/fields.py  2015-09-29 16:15:11.230067258 +0200
+++ django-mongoengine/django_mongoengine/forms/fields.py   2015-09-29 16:15:42.060067338 +0200
@@ -5,12 +5,11 @@ from django.utils.encoding import smart_
 from django.utils.translation import ugettext_lazy as _

 from django_mongoengine.utils import force_text
-from django_mongoengine.forms.widgets import Dictionary
+from django_mongoengine.forms.widgets import Dictionary, EmbeddedFieldWidget

 from bson.objectid import ObjectId
 from bson.errors import InvalidId

-
 class MongoChoiceIterator(object):
     def __init__(self, field):
         self.field = field
@@ -231,3 +230,34 @@ class DictField(forms.Field):
                     raise ValidationError(self.error_messages['illegal'] % self.illegal_characters)
             if isinstance(v, dict):
                 self.validate(v, depth + 1)
+
+class EmbeddedDocumentField(forms.MultiValueField):
+    def __init__(self, form, *args, **kwargs):
+        self.form = form()
+        # Set the widget and initial data
+        kwargs['widget'] = EmbeddedFieldWidget(self.form.fields)
+        kwargs['initial'] = [f.initial for f in self.form.fields.values()]
+        kwargs['require_all_fields'] = False
+        super(EmbeddedDocumentField, self).__init__(fields=tuple([f for f in self.form.fields.values()]), *args, **kwargs)
+
+    def bound_data(self, data, initial):
+        return data
+
+    def prepare_value(self, value):
+        return value
+    def compress(self, data_list):
+        data = {}
+        if data_list:
+            data = dict((f.name, data_list[i]) for i, f in enumerate(self.form))
+            f = self.form.__class__(data)
+            f.is_valid()
+            return f.cleaned_data
+        return data
+
+    def clean(self, value):
+        return self.to_python(super(EmbeddedDocumentField, self).clean(value))
+
+    def to_python(self, value):
+        obj = self.form._meta.model()
+        [ obj.__setattr__(k, value[k]) for k in value.keys() ]
+        return obj
diff -rupN django-mongoengine.orig/django_mongoengine/forms/widgets.py django-mongoengine/django_mongoengine/forms/widgets.py
--- django-mongoengine.orig/django_mongoengine/forms/widgets.py 2015-09-29 16:15:11.240067258 +0200
+++ django-mongoengine/django_mongoengine/forms/widgets.py  2015-09-29 16:15:42.060067338 +0200
@@ -370,3 +370,48 @@ class StaticSubDictionary(SubDictionary)
         return """
 <li><span class="static_key %(html_class)s">%(key)s</span> :  %(widgets)s</li>
 """ % params
+
+class EmbeddedFieldWidget(MultiWidget):
+    """
+    A widget that render each field found in the supplied form.
+    """
+    def __init__(self, fields, attrs=None):
+        self.fields = fields
+        super(EmbeddedFieldWidget, self).__init__([f.widget for f in self.fields.values()], attrs)
+
+    def decompress(self, value):
+        """
+        Retreieve each field value or provide the initial values
+        """
+        if value:
+            return [value.__getitem__(field) for field in self.fields.keys()]
+        return [field.field.initial for field in self.fields.values()]
+
+    def format_label(self, field, counter):
+        """
+        Format the label for each field
+        """
+        return '<label for="id_formfield_%s" %s>%s:</label>' % (
+            counter, field.required and 'class="required"', field.label)
+
+    def format_help_text(self, field, counter):
+        """
+        Format the help text for the bound field
+        """
+        if field.help_text != None:
+            return '(<em>%s</em>)' % field.help_text
+        return ''
+
+    def format_output(self, rendered_widgets):
+        """
+        This output will yeild all widgets grouped in a un-ordered list
+        """
+        ret = ['<ul class="formfield">']
+        for i, field in enumerate(self.fields):
+            label = self.format_label(self.fields[field], i)
+            help_text = self.format_help_text(self.fields[field], i)
+            ret.append('<li>%s %s %s</li>' % (
+                label, help_text, rendered_widgets[i]))
+
+        ret.append('</ul>')
+        return u''.join(ret)

It works with auto model form generator and defining a form with a formfield. In example:

models

class ContactInfo(fields.EmbeddedDocument):
    web = fields.URLField(help_text=_("""List of languages for your application (the first one will be the default language)"""))
    email = fields.EmailField(verbose_name=_('e-mail address'))
    phone = fields.StringField(verbose_name=_('phone number'))

class Application(Document):
    name = fields.StringField(max_length=255, required=True)
    contact = fields.EmbeddedDocumentField(ContactInfo)
    LOCALES = (('es', 'Spanish'), ('en', 'English'), ('de', 'German'), ('fr', 'French'), ('it', 'Italian'), ('ru', 'Russian'))
    locales = fields.ListField(fields.StringField(choices=LOCALES), help_text=_("""List of languages for your application (the first one will be the default language)"""))

forms

class ContactInfoForm(DocumentForm):
    class Meta:
        document = ContactInfo
        widgets = {
            'web': URLInput(attrs={'class': 'form-control'}),
            'email': EmailInput(attrs={'class': 'form-control'}),
            'phone': TextInput(attrs={'class': 'form-control'})
        }

class ApplicationForm(DocumentForm):
    contact = forms.fields.EmbeddedDocumentField(ContactInfoForm)
    class Meta:
        document = Application
        fields = ('name', 'locales', 'contact')
        widgets = {
            'name': TextInput(attrs={'class': 'form-control', 'required': 'required'}),
            'locales':  SelectMultiple(attrs={'class': 'form-control chosen-select', 'required': 'required'})
        }

Of course, it also works with embedded documents inside embedded documents... :P

The next feature I would like to implement is a wrapper for the model fields generator that could handle the widget attr.

from django-mongoengine.

fmoro avatar fmoro commented on June 1, 2024

Well, it seems that it works fine, but I can not save files inside embedded fields, do you know how could we do it?

from django-mongoengine.

last-partizan avatar last-partizan commented on June 1, 2024

I have no idea.

from django-mongoengine.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.