André
André

Reputation: 25584

Django - How to save() ModelForm's?

I'm trying to save a ModelForm, but I'm getting an error:

InternalError at /submeter/anuncio/
current transaction is aborted, commands ignored until end of transaction block

I will try to explain what I'm doing.

Ok, I have 5 Models that I need to save at once in one form. I'm testing to save on two models but as I said, I'm getting error on the save method. As a beginner I'm getting a little bit lost on the best way to achieve the task.

What I've done:

Template:

<form method="post" action="/submeter/anuncio/">{% csrf_token %}
    {{form_main}}
    {{form_bicyclead}}
    <input type="hidden" name="section" value="5" />
    <input type="submit">
</form>

Views.py:

def submit_data_entry_view(request):
    if request.method == 'GET': #first time rendering the form
    form_main      = MainForm()
    form_bicyclead = BicycleAdForm()

    return render_to_response('app_t/submit_data_entry.html', {'form_main': form_main, 'form_bicyclead': form_bicyclead}, context_instance=RequestContext(request))

def submit_ad_view(request):
    if request.method == 'POST':
        post_values = request.POST.copy()

        post_values['user'] = request.user.username

        post_values['bicycleadtype']      = 2
        post_values['bicycleaditemkind']  = 4
        post_values['bicycleadcondition'] = 2
        post_values['city']               = 4803854  

        form_main      = MainForm(post_values)
        form_bicyclead = BicycleAdForm(post_values)

    if form_main.is_valid() and form_bicyclead.is_valid():
        form_main.save()
        #form_bicyclead.save()

        resultado = 'valid'
    else:
        resultado = 'n_valid'
    pdb.set_trace()

    return render_to_response('app_t/submit_ad.html', {'resultado': resultado}, context_instance=RequestContext(request))

Forms.py:

class MainForm(forms.ModelForm):
    class Meta:
    model = Main
    exclude = ('user', 'section')

class BicycleAdForm(forms.ModelForm):
    class Meta:
    model = BicycleAd
    exclude = ('main', 'bicycleadtype', 'bicycleaditemkind', 'bicycleadcondition', 'city')

Models.py:

class Main(models.Model):
    section             = models.ForeignKey(Section)
    user                = models.ForeignKey(User)
    title               = models.CharField(max_length=250)
    date_inserted       = models.DateTimeField(auto_now_add=True)
    date_last_update    = models.DateTimeField(auto_now=True)

    def __unicode__(self):
    return self.title

    class Meta:
    ordering = ['date_inserted']

class BicycleAd(models.Model):
    main                = models.ForeignKey(Main)
    bicycleadtype       = models.ForeignKey(BicycleAdType)
    bicycleaditemkind   = models.ForeignKey(BicycleAdItemKind) # MPTT Model
    bicycleadcondition  = models.ForeignKey(BicycleAdCondition)
    country             = models.ForeignKey(GeonamesCountry)       
    city                = models.ForeignKey(GeonamesLocal) 
    date_inserted       = models.DateTimeField(auto_now_add=True)
    date_last_update    = models.DateTimeField(auto_now=True)

    class Meta:
    ordering = ['date_inserted']  

My question is: How can I "override" the form_main.save() in the views.py and tell them all the fields that I have in the model "section, user and title"? I think the error is because of the fields "section" and "user" that are not passing to the save method. How can I pass this values?

Another question: I'm doing this the right way or there are easier and simple ways to achieve what I'm trying to achieve?

Best Regards

Upvotes: 1

Views: 3641

Answers (2)

Aamir Rind
Aamir Rind

Reputation: 39709

Modify your model form as:

class MainForm(forms.ModelForm):
    def __init__(self, *args, **kw):
        self.user = kw.pop('user')
        self.section = kw.pop('section')
        super(MainForm).__init__(*args, **kw)

    class Meta:
        model = Main
        exclude = ('user', 'section')

    def save(self, *args, **kw):
        instance = super(MainForm).save(commit=False)
        instance.user = self.user
        instance.section = self.section
        instance.save()
        return instance

Now you need to pass the user and section when you are creating an intance of the form in your view:

form_main = MainForm(request.POST or None, user=request.user, section=section)

Upvotes: 3

dani herrera
dani herrera

Reputation: 51715

My approach is to replace this code:

def submit_ad_view(request):
    if request.method == 'POST':
        post_values = request.POST.copy()

        post_values['user'] = request.user.username

        post_values['bicycleadtype']      = 2
        post_values['bicycleaditemkind']  = 4
        post_values['bicycleadcondition'] = 2
        post_values['city']               = 4803854  

        form_main      = MainForm(post_values)

by:

def submit_ad_view(request):
    if request.method == 'POST':

        model = Main()  #if model exists get it!
                        #Notice, Main is the name of your model.

        model.user = request.user.username
        ...
        model.bicycleaditemkind = 4
        ...        
        form_main      = MainForm(request.POST, instance = model )

You can learn more on Creating forms from models django doc.

Upvotes: 2

Related Questions