4

I have the following model : Objects C, contained by objects B, contained by object A

I a have a dynamic form in a template, and using jQuery functions, I can add dynamically several fields to this form, each group of fields representing Objects (B or C)

When submitted by a post action, I'd like to create my object tree. My objective is to create an object tree when validating this template.

Currently it works, but I guess my solution is really dirty:

  • Creating lists using js/jquery, according how many elements I have in my form
  • Passing theses lists using $.post as data arguments
  • Using the lists in request, creating objects in django data model in a view

I'm quite sure there's a really better solution :p

  • Use multiple post to create Objects through different views (distinct for A, B and C) ? (But sync problems..)
  • Use json to represent objects directly on js/jquery side ?
  • Another solution ?

Many Thanks - edited for clarity

EDIT:

Note : My data model here is different (I'd simplified before) So : Session is former "object A" Exercise is "object B" Repetition is "object C" -Sorry for that, I hope It'll be clear enough (I'll correct in final post)

Some progress here, with your help guys :) I've played a little bit with Form and FormSet. Obviously, its powerfull :)

So now I have the following view:

class RepetitionForm(forms.Form):
    weight = forms.CharField()
    count = forms.CharField()

def workoutForm(request):
    RepetitionFormSet = formset_factory(RepetitionForm, extra=1)

    if request.method == 'POST':
        repetitionFormSet = RepetitionFormSet(request.POST)

        user = get_object_or_404(User, pk=1)
        session = Session(date=datetime.date.today(), user=user)
        session.save()

        exerciseTypeRef = get_object_or_404(ExerciseTypeRef, pk=1)  
        exercise = Exercise(session = session, exerciseTypeRef = exerciseTypeRef)
        exercise.save()

        if repetitionFormSet.is_valid():
            for repetitionForm in repetitionFormSet.cleaned_data:
                if(repetitionForm.is_valid()):
                    weight = repetitionForm.data['weight']
                    count = repetitionForm.data['count']
        return HttpResponse("ok")
    else:
        repetitionFormSet = RepetitionFormSet()

    return render_to_response('workoutForm.html', {'formSet': repetitionFormSet}, context_instance=RequestContext(request))

Template side is like :

{% csrf_token %}
{{ formSet.management_form }}
<ul id="idUlFormSet">
{% for item in formSet %}
    <li>
    {{ item }}
    </li>
{% endfor %}

(More code is used in template to add dynamically form instances, as this clever post describes it Django - Javascript dynamic inline FormSet with autocomplete, i wont explain it here)

Currently, when submitting form, I received this error from view :

"Key 'weight' not found in

If I'm trying a

repetitionItem.isValid()

"RepetitionForm' object has no attribute 'isValid"

The same problem appears if I'm using forms.ModelForm instead of forms.Form

I'm quite stuck :p

My Models

class User(models.Model):
name = models.CharField(max_length=100)
mail = models.CharField(max_length=100)
dateCreated = models.DateTimeField('User creation date')
def __unicode__(self):
    return self.name


class Session(models.Model):
date = models.DateField('Session Date')
user = models.ForeignKey(User)
def __unicode__(self):
    return self.date.strftime("%Y/%m/%d")


class ExerciseTypeRef(models.Model):
name = models.CharField(max_length=100)
desc = models.CharField(max_length=300)
def __unicode__(self):
    return self.name


class Exercise(models.Model):
session = models.ForeignKey(Session)
exerciseTypeRef = models.ForeignKey(ExerciseTypeRef)
def __unicode__(self):
    return self.exerciseTypeRef.name

class Repetition(models.Model):
exercise = models.ForeignKey(Exercise)
count = models.IntegerField()
weight = models.IntegerField()
6
  • 1
    when you say objects "contained" by another object - you mean Foreign Keyed correct? Commented Dec 3, 2012 at 14:48
  • Yep, sorry, C has a B fk, B a A fk. Am I clear ? Commented Dec 3, 2012 at 15:15
  • Good question. I wish you a good experience with Django. You did the right choice :) Commented Dec 3, 2012 at 17:46
  • did you ever end up having any luck? Commented Dec 4, 2012 at 14:31
  • I was playing with forms last night. I'm a beginner with dj, so.. Have to practice a bit ! ;) And because I need to add form parts from the form itself, using ajax, i'll need to complete your example on the template side. Anyway, many thanks to answer me, i'll keep you updated in the few days Commented Dec 5, 2012 at 15:57

2 Answers 2

2

Make a Model Form for your "A" model like so.

class FormA(forms.ModelForm) :
    """Signup Form"""        
    class Meta :
        model = ObjectA

in your view:

from django.forms.models import modelformset_factory
def form(request) :
    # Use Modelformset_factory and exclude the FK fields
    FormBSet = modelformset_factory(ObjectB, exclude=('objecta',))
    FormCSet = modelformset_factory(ObjectC, exclude=('objectb',))

    if request.method == "POST" :
        forma = FormA(request.POST, prefix="forma")
        formbset = FormBSet(request.POST, prefix="formbset")
        formcset = FormCSet(request.POST, prefix="formcset")
        if forma.is_valid() and formbset.is_valid() and formcset.is_valid() :
            # save a
            a = forma.save()

            # save a into b
            for formb in formbset:
                b = formb.save(commit=False)
                b.objecta = a
                b.save()

            # save b into c
            for formc in formcset:
                c = formc.save(commit=False)
                c.objectb = b
                c.save()

        ...
  1. when initializing your modelForms in the view give them a prefix
  2. commit = False so that you can save the resulting object from the previous save operation
  3. Use Formsets (https://docs.djangoproject.com/en/dev/topics/forms/formsets/#formsets) to manage n* instances of B's and C's

EDIT

use from django.forms.models import modelformset_factory NOT formset_factory, also, note the exclude paramater.

see: https://docs.djangoproject.com/en/dev/topics/forms/modelforms/#model-formsets

Sign up to request clarification or add additional context in comments.

5 Comments

I'm not really sure to understand. (Surely because I'm not very used to modelForms) In your view example you receive one of each form, representing one A, one B and one C. My problem is that each submit should create one A, nB and nC So I'm not sure this can be a solution
I misunderstood the n* requirement. give me a sec to update my answer
All right, I think I'm understanding what you are doing. I'll test some form / formset. I'll be back soon :) (I'm a pretty beginner in django, need some time to experiment) Thanks a lot for replying
for the front end / jquery part you may want to try out code.google.com/p/django-dynamic-formset. I've never used it, but it might could give you an idea on how formsets + jquery tie together
I just edited my answer, I made a pretty big mistake in my original answer regarding formset vs modelformset that may be holding you up from understanding.
0

Works now!

Was making several mistakes :

RepetitionFormSet = formset_factory(RepetitionForm, extra=1)
if request.method == 'POST':
    repetitionFormSet = repetitionFormSet(request.POST)
    #should be
    repetitionFormSet = RepetitionFormSet(request.POST)

is_valid IS CRUCIAL (objects are not filled instead!), and I was trying to call

repetitionForm.isValid()

Which should be a Java function, but not exists on django form objects ! (stupid me)

And, finally, sometimes I tested my code without filling fields, throwing a KeyError exception. I'm not sure if this thing is normal, I'll have to deal with this now

Thanks a lot to Francis !

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.