ryan
ryan

Reputation: 645

Posting data from a form into the database using Django

I am trying to have a user input a task from the frontend and have that data instantiate a new model and add this new field in the database associated with their account. I have tried the following;

Profile HTML

<form id="taskitem_form" method="post" action="/">
    {% csrf_token %}
    {% for hidden in form.hidden_fields %}
        {{ hidden }}
    {% endfor %}

    {% for field in form.visible_fields %}
        {{ field.errors }}
        {{ field.help_text }}
        {{ field }}
    {% endfor %}

    <input type="submit" name="submit" value="Add Task" class ="btn btn-primary" />
</form>

Model

class TaskItem(models.Model):
    taskn = models.CharField(max_length = 400)
    usern = models.ForeignKey(User)

    def __str__(self):
        return self.taskn

Views

  def add_task(request):
        # Get the context from the request.
        #context = RequestContext(request)

    # A HTTP POST?
    if request.method == 'POST':
        form = TaskItemForm(request.POST)

        # Have we been provided with a valid form?
        if form.is_valid():
            task = form.save(commit=False)
            task.usern = request.user
            task.save()
    # we should redirect after data modifying
            return redirect('/user/%s' %(request.user))
        else:
            # If the request was not a POST, display the form to enter details.
            return render(request, 'profile.html', {'form': form})

    # Bad form (or form details), no form supplied...
    # Render the form with error messages (if any).
    return render(request, 'profile.html', {'form': form})

Forms

from django import forms
from bkmks.models import TaskItem

class TaskItemForm(forms.ModelForm):
    taskn = forms.CharField(max_length = 300, help_text = "Please enter your task")

    # An inline class to provide additional information on the form.
    class Meta:
        fields = ('taskn', 'usern' )
        #This is the association between the model and the model form
        model = TaskItem

Upvotes: 0

Views: 9789

Answers (5)

markwalker_
markwalker_

Reputation: 12849

Why define a field called task in the form if you've already got a field in the model called taskn, wouldn't it be better to just use that? And like the guys have said, you need to specify a template to render (that's why you're not seeing anything).

It'd also be a good idea to pass the current user to the form's user field.

@login_required
def add_task(request):
    # Get the context from the request.
    context = {}

    # A HTTP POST?
    if request.method == 'POST':
        form = TaskItemForm(request.POST)

        # Have we been provided with a valid form?
        if form.is_valid():
            # Save the new category to the database.
            form.save()

            # Now call the index() view.
            # The user will be shown the homepage.
            return render_to_response(
                'profile.html',
                {'form': form},
                RequestContext(request, context)
            )
        else:
            # The supplied form contained errors - just print them to the terminal.
            print form.errors
    else:
        # If the request was not a POST, display the form to enter details.
        form = TaskItemForm(initial={'usern': request.user})

    # Bad form (or form details), no form supplied...
    # Render the form with error messages (if any).
    return render_to_response(
        'profile.html',
        {'form': form},
        RequestContext(
            request, context
        )
    )

Form;

from django import forms
from bkmks.models import TaskItem

class TaskItemForm(forms.ModelForm):
    taskn = forms.CharField(max_length = 300, help_text = "Please enter your task")

    # An inline class to provide additional information on the form.
    class Meta:
        fields = ('taskn', 'usern' )
        #This is the association between the model and the model form
        model = TaskItem

Upvotes: 0

Michael B
Michael B

Reputation: 5388

The below should do what you need. You really want to inherit 100% of everything from your model when you can. This insures all model validation trickles down to the form. I utilized verbose_name and help_text on the model to achieve this.

Models

from django.conf import settings

class TaskItem(models.Model):
    taskn = models.CharField(
        max_length=400,
        verbose_name="task",
        help_text="Please enter your task.",
    )
    usern = models.ForeignKey(
        to=settings.AUTH_USER_MODEL, 
        related_name="tasks",
    )

    def __str__(self):
        return self.taskn

For the forms, I have added a forms.HiddenInput widget to the user, assuming you want the user submitting the task to become the user.

Forms

from django import forms
from bkmks.models import TaskItem

class TaskItemForm(forms.ModelForm):
    widgets = {
        'user': forms.HiddenInput,
    }

    class Meta:
        model = TaskItem
        fields = ('taskn', 'usern')

I have used a CreateView to reduce code complexity, and overrode the form_valid to add the user instance to the form.

Views

from django.views.generic import CreateView
from bkmks.models import TaskItem
from bkmks.forms import TaskItemForm

class TaskCreateView(CreateView):
    model = TaskItem
    form_class = TaskItemForm
    template_name = "path/to/template.html"

    def form_valid(self, form):
        form.instance.user = self.request.user
        return super(TaskCreateView, self).form_valid(form)

Finally, in the template, we simply want to use {{ form }}. I see you are looking into bootstrap. I'll suggest django-crispy-forms for this, but that is beyond the scope of your question.

Template

<form id="taskitem_form" method="post" action="/">
    {% csrf_token %}
    {{ form }}
    <input type="submit" name="submit" value="Add Task" class ="btn btn-primary" />
</form>

Upvotes: 1

moonstruck
moonstruck

Reputation: 2784

Lot's of Changes needed to your code.

I'm posting a working version so that you can try.

Put profile.html file as bkmks/templates/bkmks/profile.html

Get it working. Customize later.

profile.html

<form id="taskitem_form" method="post" action="">

    {% csrf_token %}
    {{form}}

    <input type="submit" name="submit" value="Add Task" class ="btn btn-primary" />
</form>

model as it is.

views.py

from django.contrib.auth.decorators import login_required
from django.shortcuts import render_to_response, RequestContext, redirect
from .forms import TaskItemForm

@login_required
def add_task(request):
    # Get the context from the request.
    context = RequestContext(request)

    # A HTTP POST?
    if request.method == 'POST':
        form = TaskItemForm(request.POST)

        # Have we been provided with a valid form?
        if form.is_valid():
            # Save the new category to the database.
            task = form.save(commit=False)
            task.usern = request.user
            task.save()


            # Redirect to home (/)
            return redirect('/')
        else:
            # The supplied form contained errors - just print them to the terminal.
            print form.errors
    else:
        # If the request was not a POST, display the form to enter details.
        form = TaskItemForm()

    # Bad form (or form details), no form supplied...
    # Render the form with error messages (if any).
    return render_to_response('bkmks/profile.html', {'form': form}, context)

forms.py

class TaskItemForm(forms.ModelForm):
    # task is changed to taskn
    taskn = forms.CharField(max_length = 300, help_text = "Please enter your task")

    # An inline class to provide additional information on the form.
    class Meta:
        fields = ('taskn',)
        #This is the association between the model and the model form
        model = TaskItem

If you get any error or data is not getting saved post here.

Going through Django tutorial will be an wise decision.

Upvotes: 1

f43d65
f43d65

Reputation: 2302

Add this line to imports in views.py

from django.contrib.auth.decorators import login_required

Decorate add_task view

@login_required
def add_task(request):

Then, edit part of your code

if form.is_valid():
    task = form.save(commit=False)
    task.usern = request.user
    task.save()
    # we should redirect after data modifying
    return redirect('/')
else:
    # etc.

Some notes. You may replace render_to_response to render.

Remove this line

context = RequestContext(request)

Replace

# Wrong usage, actually.
# Should be something like
# render_to_response(template_name, context, context_instance)
render_to_respone('/', {'form': form}, context)

with

# if template_name is "profile.html"
render(request, 'profile.html', {'form': form})

Upvotes: 0

wobbily_col
wobbily_col

Reputation: 11878

https://docs.djangoproject.com/en/1.8/topics/http/shortcuts/#render-to-response

render_to_response expects a template as the first argument, not a url.

I think in your second call to render_to_response should include the template name / path , while the first one should use a return HttpResponseRedirect("/") instead, though its not clear exactly what your problem is.

Upvotes: 0

Related Questions