Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Some examples #11

Open
fceruti opened this issue Jun 12, 2012 · 20 comments
Open

Some examples #11

fceruti opened this issue Jun 12, 2012 · 20 comments

Comments

@fceruti
Copy link

fceruti commented Jun 12, 2012

I can't figure out how to make this work :(

I feel weird asking for more help, but hey, I'd gladly add an example folder with a working app if someone provides me with the "views.py" for a working example.

Thanks!

@jschrewe
Copy link
Owner

Are you referring to problems with uploaded files as on the mailing list? Or are there other problems?

@fceruti
Copy link
Author

fceruti commented Jun 12, 2012

I'm talking (here) about the continuation of the code in the readme file.

It says:
...
views.py
form = MessageForm(parent_document=some_document, ...)
And then:
In theory the documentation Django's modelform documentation should be all you need.

I've really tried, but I can't seem to make this work. Thats why a complete example would be very helpful for people like me :)

@jschrewe
Copy link
Owner

Okay, I'll give it a shot. Documentation isn't really my strength as you might have guessed :)

Perhaps you could be a little more precise what you actually can't get to work until then?

@fceruti
Copy link
Author

fceruti commented Jun 12, 2012

jejej ok, I'll try. What I want to do, are two things:

  1. Being able to use a EmbeddedDocumentForm successfully. i.e.

#models.py
class BlogPost(Document):
title = StringFile()
comments = ListField(EmbeddedDocumentField('Comment'))

class Comment(EmbeddedDocument):
content = StringField()

#forms.py
class AddCommentForm(EmbeddedDocumentForm):
class Meta:
document = Comment
embedded_field_name = 'comments'

#views.py
form = AddCommentForm(parent_document=a_blog_post)

  1. Have a working example of a file being uploaded and stored in the scope of a larger object i.e.:
    (question asked in https://groups.google.com/forum/?fromgroups#!topic/mongoengine-users/hkBZALpR7Ko)

#models.py
class PhotoWithComment(Document):
comment = StringField()
photo = FileField()

#forms.py
class AddPhotoWithCommentForm(DocumentForm):
class Meta:
document = PhotoWithComment

#views.py
form = AddPhotoWithCommentForm(parent_document=a_blog_post)
.... ?

@jschrewe
Copy link
Owner

Oh, right. I'm not sure how much about you know about Django, so first a link to the Django book about working with forms: http://www.djangobook.com/en/2.0/chapter07/

For the concrete example:

def upload_photo(request):
    if request.method == 'POST':
        # if you edit an existing file, get the edited model first and pass it in as first argument
        form = AddPhotoWithCommentForm(request.POST, request.FILES) 
        if form.is_valid():
            model = form.save() # the new model is already saved to the database
            return HttpResponse # -> Usually a redirect somewhere or do something else. Django docs help you here
   else:
       form = AddPhotoWithCommentForm()
   return render_to_response("some_template", {'tpl_form': form}) # -> Again, have a look at the Django docs for more options.

Hope that helps.

@fceruti
Copy link
Author

fceruti commented Jun 12, 2012

Awesome, when I make everything work, I'm going to pull-request an examples directory :)

@alessandrobokan
Copy link

Hi, sorry, I have a problem with the EmbeddedDocumentForm. I have:

models.py

class Interview(Document):
questions = ListField(EmbeddedDocumentField(Question))

class Question(EmbeddedDocument):
question = StringField(required=True)
answer = StringField(required=True)

forms.py

class QuestionForm(EmbeddedDocumentForm):
class Meta:
document = Question
embedded_field_name = 'questions'
fields = ['question', 'answer']

How must be the constructor form?. I tried:
a_interview = Interview()
QuestionForm(parent_document=a_interview)

...but , how to pass the "request.POST"?

Can you help me, please?
Thanks

@jschrewe
Copy link
Owner

The easiest way is not to use keyword arguments, but positional arguments:

QuestionForm(a_interview, request.POST, request.FILES)

or if you want to use keyword args:

QuestionForm(parent_document=a_interview, data=request.POST, files=request.FILES)

In fact every argument except for parent_document is just passed through to the BaseDocumentForm constructor, has the following arguments:

BaseDocumentForm(data=None, files=None, auto_id='id_%s', prefix=None,
             initial=None, error_class=ErrorList, label_suffix=':',
             empty_permitted=False, instance=None)

BaseDocumentForm should have the same interface as Django's ModelForm, so the Django docs should help you there.

Hope that helps.

@alessandrobokan
Copy link

The information was helpfuly, it's works!. Thank you very much

@alessandrobokan
Copy link

Hi, In the prevoius example I pass a single question in request.POST : question="how are you?", answer="fine", it's works, but, how I pass a LIST of questions??

Can you help me, please?
Thanks

@alessandrobokan
Copy link

Hi, again... I found a method called embeddedformset_factory...to do the previous question ^

InterviewFormSet = embeddedformset_factory(document=InterviewQuestion, parent_document=Interview)

data = {
'form-TOTAL_FORMS': u'2',
'form-INITIAL_FORMS': u'0',
'form-MAX_NUM_FORMS': u'',
'form-0-question': u'how are you 1',
'form-0-answer': u'fine 1',
'form-1-question': u'how are you 2',
'form-1-answer': u'fine 2',
}

formset = InterviewFormSet(data, instance=InterviewQuestion())

if formset.is_valid():
formset.save()

.... I tried to do similar "formset_factory". But this dosen't works!!, (either "formset.errors")

I hope you help me
Thanks

@jschrewe
Copy link
Owner

jschrewe commented Aug 6, 2012

Hey,

embeddedformset_factory is quite right.

To get the initial formset use:

formset = embeddedformset_factory(document=doc, parent_document=parent, form=an_optional_embedded_form)

To render use:

formset = formset(instance=object)

To save use:

formset = formset(parent_document=object, data=request.POST, files=request.FILES, instance=object)

if formset.is_valid():
    formset.save()

Hope that helps...

@nemith
Copy link

nemith commented Nov 13, 2013

Hmm. embeddedformset_factory returns a django.forms.FomSet type which does not have an instance kwarg.

I have the following:

models.py

class Page(me.EmbeddedDocument):
    title = me.StringField(max_length=255)
    help_text =  me.StringField()

class LegalDocument(me.Document):
    title = me.StringField(max_length=255)
    description =  me.StringField()
    pages = me.SortedListField(me.EmbeddedDocumentField(Page))

forms.py

from mongodbforms import DocumentForm, embeddedformset_factory
from .models import LegalDocument, Page

class LegalDocumentForm(DocumentForm):
    class Meta:
        document = LegalDocument


PageFormSet = embeddedformset_factory(Page, LegalDocument)

views.py

def document_edit(request, doc_id=None):
    if doc_id:
        doc = get_document_or_404(LegalDocument, id=doc_id)
    else:
        doc = LegalDocument()

    if request.POST:
        form = LegalDocumentForm(request.POST, instance=doc)
        if form.is_valid():
            form.save()
            return HttpResponseRedirect("/doc")  #FIXME
                #not even attempting to save the formset yet
    else:
        form = LegalDocumentForm(instance=doc)
        page_formset = PageFormSet(instance=doc) 

    return render(request, "doc/edit.html", dict(form=form, page_formset=page_formset))

And i get the following error

Traceback (most recent call last):
  File "/Users/bbennett/.virtualenvs/mlp/lib/python2.7/site-packages/django/core/handlers/base.py", line 115, in get_response
    response = callback(request, *callback_args, **callback_kwargs)
  File "/Users/bbennett/Google Drive/Devel/python/mlp/legaldoc/views.py", line 24, in document_edit
    page_formset = PageFormSet(instance=doc)
  File "/Users/bbennett/.virtualenvs/mlp/lib/python2.7/site-packages/mongodbforms/documents.py", line 918, in __init__
    super(EmbeddedDocumentFormSet, self).__init__(data, files, save_as_new, prefix, queryset, **kwargs)
  File "/Users/bbennett/.virtualenvs/mlp/lib/python2.7/site-packages/mongodbforms/documents.py", line 606, in __init__
    super(BaseDocumentFormSet, self).__init__(**defaults)
TypeError: __init__() got an unexpected keyword argument 'instance'

Am I missing something here?

@jschrewe
Copy link
Owner

Yep, you are missing something. The argument to the embedded formset for the parent document is now called parent_document. See here for more details.

@nemith
Copy link

nemith commented Nov 14, 2013

So i assume you mean changing

PageFormSet(instance=doc)

to

page_formset = PageFormSet(parent_document=doc) 

After that I get an error that

Internal Server Error: /doc/edit/5268c36fd1172c6cd8ae4cac
Traceback (most recent call last):
  File "/Users/bbennett/.virtualenvs/mlp/lib/python2.7/site-packages/django/core/handlers/base.py", line 115, in get_response
    response = callback(request, *callback_args, **callback_kwargs)
  File "/Users/bbennett/Google Drive/Devel/python/mlp/legaldoc/views.py", line 24, in document_edit
    page_formset = PageFormSet(parent_document=doc)
  File "/Users/bbennett/.virtualenvs/mlp/lib/python2.7/site-packages/mongodbforms/documents.py", line 918, in __init__
    super(EmbeddedDocumentFormSet, self).__init__(data, files, save_as_new, prefix, queryset, **kwargs)
  File "/Users/bbennett/.virtualenvs/mlp/lib/python2.7/site-packages/mongodbforms/documents.py", line 606, in __init__
    super(BaseDocumentFormSet, self).__init__(**defaults)
  File "/Users/bbennett/.virtualenvs/mlp/lib/python2.7/site-packages/django/forms/formsets.py", line 56, in __init__
    self._construct_forms()
  File "/Users/bbennett/.virtualenvs/mlp/lib/python2.7/site-packages/django/forms/formsets.py", line 124, in _construct_forms
    self.forms.append(self._construct_form(i))
  File "/Users/bbennett/.virtualenvs/mlp/lib/python2.7/site-packages/mongodbforms/documents.py", line 925, in _construct_form
    emb_list = getattr(self.parent_document, self.form._meta.embedded_field)
TypeError: getattr(): attribute name must be string

Where do you set the embedded_field for a EmbeddedDocumentFormSet form. It right now is set to None.

@jschrewe
Copy link
Owner

At the moment that can only be done with formset.form._meta.embedded_field = 'name_of_embedded_field'. Which is a bit of a mistake now that I think about it.

I admit that the only place I have used the embeddedformset factory is in the admin, so the whole API sucks in parts. Uhm, I think I'll get around to writing a patch tomorrow.

@jschrewe
Copy link
Owner

Okay, the embeddedformset_factory does now behave more like inlineformset_factory. It will figure out the correct field on the parent document that holds the embedded document as long as there is only one field referencing it. If you use more then one field you can pass the parameter embedded_name for the correct field to the factory (Django's name for the parameter is fk_name. They do the same thing though).

So far this seems to work for me, but a bit more testing never hurts so let me know if there are any problems with the patch.

@aniketzamwar
Copy link

When we have CHOICES set for fields used inside the models in models.py, mongodb forms throws error.

If I remove CHOICES from sex field, then it works properly.
following is in models.py

 
SEX = ('Male', 'Female')
class UserInfo(User, DynamicDocument):
    address = EmbeddedDocumentField(Address)
    dob = DateTimeField(required = False)
    sex = StringField(choices = SEX) #
    primary_number = LongField(required = False)

It gives the following error:
File "/path/appforms.py" in

  1. class UserForm(DocumentForm):
    File "/usr/local/lib/python2.7/dist-packages/mongodbforms-0.3-py2.7.egg/mongodbforms/documents.py" in new
  2.     opts = new_class._meta = ModelFormOptions(getattr(new_class, 'Meta', None))
    
    File "/usr/local/lib/python2.7/dist-packages/mongodbforms-0.3-py2.7.egg/mongodbforms/documents.py" in init
  3.         self.document._meta = DocumentMetaWrapper(self.document)
    
    File "/usr/local/lib/python2.7/dist-packages/mongodbforms-0.3-py2.7.egg/mongodbforms/documentoptions.py" in init
  4.     self._setup_document_fields()
    
    File "/usr/local/lib/python2.7/dist-packages/mongodbforms-0.3-py2.7.egg/mongodbforms/documentoptions.py" in _setup_document_fields
  5.                 for choice, value in f.choices:
    

@jschrewe
Copy link
Owner

I think the choices need to look like described in the Django docs (that's at least what has been tested and works). See here https://docs.djangoproject.com/en/dev/ref/models/fields/#choices

Something like

SEX = (
   ('M', 'Male'),
   ('F', 'Female'),
)

Should work. Or 'Male' instead of 'M'.

@aniketzamwar
Copy link

Thanks. Got this working.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

5 participants