0

I'm trying to build a form to save Names and Email Adresses to my database. However, it doesn't save... I've used an Inclusion Tag because I want to use the same form in different templates. This is my models.py:

class Contact(models.Model):
    FRAU = 'FR'
    HERR= 'HR'
    GENDER_CHOICES = (
        (FRAU, 'Frau'),
        (HERR, 'Herr'),
    )
    gender = models.CharField(max_length=2, choices=GENDER_CHOICES, default=FRAU)
    first_name = models.CharField(max_length=100)
    last_name = models.CharField(max_length=200)
    email = models.EmailField()

    def __unicode__(self):
        return "%s %s" %(self.first_name, self.last_name)

This is my forms.py:

class FragenContactForm(ModelForm):
    class Meta:
        model = Contact
        fields = ['gender', 'first_name', 'last_name', 'email']

This is my custom tags module:

from django import template
from django.http import HttpResponseRedirect
from django.core.urlresolvers import reverse
from fragen.forms import FragenContactForm


register = template.Library()

@register.inclusion_tag('fragen/askforoffer.html', takes_context=True)
    def askforoffer(context):
    form = FragenContactForm(context['request'].POST or None)
    if context['request'].method=='POST':
        if form.is_valid():
            form.save()
        return HttpResponseRedirect(reverse('fragen/thanks.html'))
    else:
        messages.error(context['request'], "Error")
    return {'form': FragenContactForm()}

After I fill in and submit the form, I see nothing in my database. Am I missing something? Thanks!

bokdi
  • 3
  • 1
  • Is the indentation failure just in your question or in your code? Beside that: Are you sure, your `form.is_valid()` returns `True`? – Mischback Jun 28 '15 at 17:40
  • After reading about inclusion tags: Can you please provide your actual view-function and the templates? – Mischback Jun 28 '15 at 17:48
  • 1
    Handling your form in an inclusion tag is... very unusual. You can put it in a separate function that you call from your views if you want, but I'd highly recommend not to put it in an inclusion tag or anything called from your template. A template is for presentation logic and presentation logic only, not to execute arbitrary Python code. – knbk Jun 28 '15 at 19:50

3 Answers3

0

Post is a method of server request which is handled by views.

Inclusion tag is rendered along with the page (that is during server response). Thus page context can not get request.POST - of cause, if you don't send POST deliberately as a context variable to the page (but it won't be request.POST - just some_variable). It looks a bit weird..

igolkotek
  • 1,687
  • 18
  • 16
0

You have to handle form-processing in a view function.

from django.shortcuts import redirect, render
from fragen.forms import FragenContactForm

def askforoffer(request):
    form = FragenContactForm(request.POST or None)
    if form.is_valid():
        form.save()
        return redirect('specify_thank_url_here')

    return render(request, 'fragen/askforoffer.html',
                  { 'form': form })

I've never seen any form processing in an inclusion tag and I doubt this will work. Above view-function may point you in the right direction.

Mischback
  • 843
  • 5
  • 18
0

I've used an Inclusion Tag because I want to use the same form in different templates.

You can simply reuse the form - or as your form in this case is very simple, you can use the CreateView generic class based view and reduce your code even further.

Your view would contain just the following:

class OfferForm(CreateView):
    template_name = 'fragen/askforoffer.html'
    model = Contact
    fields = ['gender', 'first_name', 'last_name', 'email']
    success_url = 'fragen/thanks.html'

Django will automatically create the ModelForm, and handle the error redirection and saving of the fields for you.

In your fragen/askforoffer.html template, you need just this:

<form action="" method="post">{% csrf_token %}
    {{ form.as_p }}
    <input type="submit" value="Create" />
</form>

Finally, in your urls.py:

url(r'^submit-offer/$', OfferForm.as_view(), name='offer-form')

To display the same form in multiple places, just map it to a URL:

url(r'^another-form/$', OfferForm.as_view(), name='another-form')

Finally, __unicode__ method should return a unicode object; so in your model:

def __unicode__(self):
    return u"{} {}".format(self.first_name, self.last_name)

The way you are trying to do it will not work because the template tag code will be executed before the template is rendered; so by the time the user sees the form, your tag code is already finished. There is no way to "trigger" it again; which is why you need a traditional view method which will accept the data entered into the form.

Burhan Khalid
  • 169,990
  • 18
  • 245
  • 284