Search code examples
djangodjango-viewsdjango-forms

Django - data from form (ModelForm) do not save in existing database


Im trying to send via form data to my database as new object of my Task model. When I click submit button it only redirects me to my other page, nothing happens with submitted data and data is not saved to my db. I looked for solution in multiple sources but didn't find one. I am begginer with this topic so every feedback would be great.

My questions:

  1. Where I made mistake
  2. If i have prepopulated slug field in my admin.py (from title field) will it be prepopulated in forms when i exclude my slug field?

3.I would appreciate for useful knowledge sources.

model.py

class Task(models.Model):
    is_done = models.BooleanField(default=False)
    title = models.CharField(max_length=100)
    add_time = models.DateTimeField(auto_now_add=True)
    deadline = models.DateTimeField()
    user = models.ForeignKey(User, on_delete=models.CASCADE, related_name="user")
    slug = models.SlugField()
    description = models.TextField()

forms.py

from django import forms
from .models import Task


class TaskForm(forms.ModelForm):
    class Meta:
        model = Task
        exclude = ["add_time", "is_done"]

template

        <form method="post" class="form" action="{% url 'add-task' %}">
            {% csrf_token %}
            <p>Title: {{ form.title }}</p>
            <p>Deadline: {{ form.deadline }}</p>
            <p>User: {{ form.user }}</p>
            <p>Description: {{ form.description }}</p>
            <button type="submit">Submit</button>
        </form>

views.py

def add_task(request):
    if request.method == 'POST':
        form = TaskForm(request.POST)
        if form.is_valid():
            form.save()
        return HttpResponseRedirect("/todolist")

    form = TaskForm()
    return render(request, "todolist/add_task.html", {"form": form})

Solution

  • Likely the form is invalid, but because you construct a new one, even if the form is valid, you can not see the errors.

    from django.shortcuts import redirect
    
    def add_task(request):
        if request.method == 'POST':
            form = TaskForm(request.POST, request.FILES)
            if form.is_valid():
                form.save()
                return redirect('name-of-todolist-view')
        else:
            form = TaskForm()
        return render(request, 'todolist/add_task.html', {'form': form})

    in the template, you should render this with errors, so:

    <form method="post" class="form" action="{% url 'add-task' %}">
        {% csrf_token %}
        {{ form.non_field_errors }}
        <p>Title: {{ form.title }} {{ form.title.errors }}</p>
        <p>Deadline: {{ form.deadline }} {{ form.deadline.errors }}</p>
        <p>User: {{ form.user }} {{ form.user.errors }}</p>
        <p>Description: {{ form.description }} {{ form.description.errors }}</p>
        <button type="submit">Submit</button>
    </form>

    Likely however the problem is that your slug is included in the form, but you don't render it:

    from django import forms from .models import Task

    class TaskForm(forms.ModelForm):
        class Meta:
            model = Task
            exclude = ['add_time', 'is_done', 'slug']

    Note: You can make use of django-autoslug [GitHub] to automatically create a slug based on other field(s).


    Note: It is normally better to make use of the settings.AUTH_USER_MODEL [Django-doc] to refer to the user model, than to use the User model [Django-doc] directly. For more information you can see the referencing the User model section of the documentation.


    Note: While most forms do not process media files, it is probably better to pass request.FILES [Django-doc] to the form anyway, such that if you later add an extra media field, all views that use the form will indeed handle the files properly.