After submitting several form fields from models disappear in the template and database

I have several form which are contained in different views and template. But these fields are combined into one main model - Profile. For example, instead of choosing a name of the work, I can write a name my work myself.
I built it with several form in my three template. It works well. But if I submit form in one template, the information contains in other templates disappear.

models

class Profile(models.Model):
    slug = models.SlugField(unique=True)
    user = models.OneToOneField(get_user_model(), on_delete=models.CASCADE)
    bio = models.TextField(null=False, blank=True)
    # Location
    country = models.ForeignKey(
        "Country", on_delete=models.SET_NULL, null=True, blank=True
    )
    city = ChainedForeignKey(
        "City",
        chained_field="country",
        chained_model_field="country",
        show_all=False,
        auto_choose=True,
        sort=True,
        null=True,
        blank=True)
    bachelordeg = models.ManyToManyField(
        "University",
        blank=True,
        related_name="bachelordeg",
    )
    masterdeg = models.ManyToManyField(
        "University",
        blank=True,
        related_name="masterdeg",
    )
    work = models.ManyToManyField("Work_place", blank=True)
    school = models.ForeignKey(
        "School", on_delete=models.SET_NULL, null=True, blank=True
    )

class University(models.Model):
    slug = models.SlugField(unique=True, blank=True, null=True)
    name = models.CharField(max_length=250, blank=True, null=True)
    description = models.TextField(null=False, blank=True)


class Work_place(models.Model):
    name = models.CharField(max_length=250, blank=True, null=True)
    description = models.TextField(null=False, blank=True)

views

def update_profile_about(request, slug):
    if request.method == "POST":
        user_form = UserForm(
            request.POST, instance=request.user, prefix="user")
        profile_form = ProfileForm(
            request.POST, request.FILES, instance=request.user.profile, prefix="profile"
        )
        if all([user_form.is_valid(), profile_form.is_valid()]):
            us = user_form.save()
            prof = profile_form.save()

            prof.save()

            messages.success(request, _(
                "Your profile was successfully updated!"))
            return HttpResponseRedirect("about")
        else:
            messages.error(request, _("Please correct the error below."))
    else:
        user_form = UserForm(instance=request.user, prefix="user")
        profile_form = ProfileForm(
            instance=request.user.profile, prefix="profile")
    return render(
        request,
        "users/profile_update_about.html",
        {
            "user_form": user_form,
            "profile_form": profile_form,
        },
    )

def update_profile_bio(request, slug):
    if request.method == "POST":
        profile_form = ProfileForm(
            request.POST, request.FILES, instance=request.user.profile, prefix="profile"
        )
        if profile_form.is_valid():
            prof = profile_form.save()
            prof.save()

            messages.success(request, _(
                "Your profile was successfully updated!"))
            return HttpResponseRedirect("bio")
        else:
            messages.error(request, _("Please correct the error below."))
    else:
        profile_form = ProfileForm(
            instance=request.user.profile, prefix="profile")

    return render(
        request,
        "users/profile_update_bio.html",
        {"profile_form": profile_form},
    )


def update_profile_work_uni(request, slug):
    WorkFormSet = modelformset_factory(
        Work_place, form=WorkForm, extra=0, can_delete=True
    )
    if request.method == "POST":
        profile_form = ProfileForm(
            request.POST, instance=request.user.profile, prefix="profile"
        )
        work_formset = WorkFormSet(request.POST, prefix="work")
        if all([profile_form.is_valid(), work_formset.is_valid()]):
            prof = profile_form.save()
            works = work_formset.save()
            # sch = school_formset.save()

            prof.Work_place = works
            prof.save()


            messages.success(request, _(
                "Your profile was successfully updated!"))
            return HttpResponseRedirect("work_uni")
        else:
            messages.error(request, _("Please correct the error below."))
    else:
        work_formset = WorkFormSet(prefix="work")
        profile_form = ProfileForm(
            instance=request.user.profile, prefix="profile")
    context = {"profile_form": profile_form, "work_formset": work_formset}
    return render(request, "users/profile_work_uni.html", context)

I think we’re going to need you to be more specific about exactly what’s happening.

Please provide sufficient details about what views and forms are being viewed and what you mean by:

Data is processed by views. Templates are only used to display data acquired by the view. Information is not contained within the templates. It’s the responsibility of the view to supply data to the templates to be rendered.

So please be more specific about what views you’re using at each step, and what view is not displaying the data you expect to see.

Ken, hello! Thank you for the response!
Okay.
I have three views. The first view contains data about the user, country and city, the second view contains data about the background (field from model Profile - “bio”), the third view contains data about work and University.
For example, when I change my location (country and city, this is first view) and then submit the form, data in the database and template disappear which are contained in second and third views (it’s “bio” (second), “work” and “university” (third)).

How are you navigating between these views?

How are you constructing your URLs for navigation?

How are you identifying which information to be displayed in each view?

If I understood right. I attach template and url.
In short, I type name of form (which I use un views), and then name of the field in models. For example, in view update_profile_about - user_form.first_name and profile_form.country. This approach I build three template.
I apology If I didn’t understand you correctly
update_profile_about.html

{% block content %}

      <form method="POST" enctype="multipart/form-data" id="profileForm" novalidate>
        {% csrf_token %}
        {{ profile_form.media.js }}

        <!--First Name and Last Name-->
        <div class="d-flex flex-column flex-wrap gap-2 ms-2 me-2" style="height: 100px;">
          <div class="form-group mb-3">
            <label for="{{ user_form.first_name.id_for_label }}" class="form-label">First Name:*</label>
            {{ user_form.first_name }}
       </div>


          <div class="form-group mb-3">
            <label for="{{ user_form.last_name.id_for_label }}" class="form-label">Last Name:*</label>
            {{ user_form.last_name }}
        </div>
        <!--  End First Name and Last Name-->

    <p class="ms-2"><strong>Your location:</strong></p>
        <div class="d-flex flex-column flex-wrap gap-2 ms-2 me-2" style="height: 100px;">
          <!--Country Name-->
          <div class="form-group mb-3">
            <label for="{{ profile_form.country.id_for_label }}" class="form-label">Country:</label>
            {{profile_form.country class="form-select" }}
          </div>
          <!--End Country Name-->

          <!--City Name-->
          <div class="form-group mb-3">
            <label for="{{ profile_form.city.id_for_label }}" class="form-label">City:</label>
            {{profile_form.city }}
          </div>
          <!--End City Name-->

        </div>
    </div>
    <!--End Location-->
  <div class="d-flex justify-content-center align-items-center mb-3">
    <button class="btn btn-outline-primary">
      Update
    </button>
  </div>
  </form>

urls.py

urlpatterns = [
    path("profile/<slug:slug>", ProfileDetailView.as_view(), name="profile"),
    path(
        "profile/<slug:slug>/update/about",
        views.update_profile_about,
        name="profile_update_about",
    ),

I’m asking about the actual usage. Look at this from the user’s perspective.

Let’s say you’re on your first page, generated by the view update_profile_about. What do you do that takes you from the first page to the second? (update_profile_bio)

Now, asking about the code - how does that action send you from the first page to the second?

I write like a user. I want to add informationabout myself. I click “Edit Profile”.
I see first field - First Name, Last Name, Country, City, etc. I choose my location ant I submit the form. Then I go to another page by a link. On another page contains a field - biography (update_profile_bio). I write about my biography and submit the form.
Then I want to add my work and university. I click on a link. Then I also select it and then submit the form. When I go to my profile. I found that my information that I had written and selected was gone

What specifically are the URLs that these links are sending you to. And what are the urls.py file entries for those links.

How are you connecting this information with the Profile model in the first form?

Same question as before - how are you assigning this information to the Profile created in the first page?

In each template I have these link

    <div>
      <a href="{% url 'profile_update_about' user.profile.slug %}">About you</a>
      <a href="{% url 'profile_update_bio' user.profile.slug %}">Biography</a>
      <a href="{% url 'profile_update_work_uni' user.profile.slug %}">Work and University</a>
    </div>

It relates to this urls.py
urls.py

urlpatterns = [
    path("profile/<slug:slug>", ProfileDetailView.as_view(), name="profile"),
    path(
        "profile/<slug:slug>/update/about",
        views.update_profile_about,
        name="profile_update_about",
    ),
    path(
        "profile/<slug:slug>/update/bio",
        views.update_profile_bio,
        name="profile_update_bio",
    ),
    path(
        "profile/<slug:slug>/update/work_uni",
        views.update_profile_work_uni,
        name="profile_update_work_uni",
    ),

I use views.py. For example for update_profile_work_uni -

if all([profile_form.is_valid(), work_formset.is_valid()]):
            prof = profile_form.save()
            works = work_formset.save()

            prof.Work_place = works
            prof.save()

But I do not see a field named Work_place in your Profile model. Also, review the docs at Many-to-many relationships | Django documentation | Django to see how to assign instances to a ManyToManyField. (You don’t just assign an iterable to the field.)

Thank you! I may fix it. It’s intresting because it works good.
But I didn’t fix my main problem.
I also select University and then submit multiform (third view -update_profile_work_uni). Then I submit first view with multiform(user_form and profile_form). And data disappear from modes and template.

def update_profile_work_uni(request, slug):
    WorkFormSet = modelformset_factory(
        Work_place, form=WorkForm, extra=0, can_delete=True
    )
    if request.method == "POST":
        profile_form = ProfileForm(
            request.POST, instance=request.user.profile, prefix="profile"
        )
        work_formset = WorkFormSet(request.POST, prefix="work")
        if all([profile_form.is_valid(), work_formset.is_valid()]):
            prof = profile_form.save()
            works = work_formset.save()

            prof.work.add = works
            prof.save()


            messages.success(request, _(
                "Your profile was successfully updated!"))
            return HttpResponseRedirect("work_uni")
        else:
            messages.error(request, _("Please correct the error below."))
    else:
        work_formset = WorkFormSet(prefix="work")
        profile_form = ProfileForm(
            instance=request.user.profile, prefix="profile")
    context = {"profile_form": profile_form, "work_formset": work_formset}
    return render(request, "users/profile_work_uni.html", context)

This is still not right. Please review the previously referenced docs.

May something like?

 if all([profile_form.is_valid(), work_formset.is_valid()]):
            prof = profile_form.save()
            works = work_formset.save()

            prof.work.add(*works)
            prof.save()

            messages.success(request, _(
                "Your profile was successfully updated!"))
            return HttpResponseRedirect("work_uni")

Try it and see!

Now, I will point out that:

Be aware that the modification of a many-to-many relationship (using add(*objs), etc) only affects the join table between the two related tables.
Specifically, what that means is that after doing the prof.work.add(...), you do not need to do another prof.save() - you haven’t modified that model.

Thank you! It works good with add(*objs) but if I use add(objs). I see error - Field ‘id’ expected a number but got []. Also I delete prof.save()

        if all([profile_form.is_valid(), work_formset.is_valid()]):
            prof = profile_form.save()

            prof.work.add(*works)


            messages.success(request, _(
                "Your profile was successfully updated!"))
            return HttpResponseRedirect("work_uni")
1 Like

Ken, I apologize. But I check now I also have this problem. When I submit a form in third view (update_profile_work_uni) information in the second and first views disappear. Could it relate because I submit one form and information reload? What do you think about it?

You need to be a lot more specific about what’s happening here.

You submit the form in update_profile_work_uni. It then redirects you to another page? If so, which page? What is the link it is sending you to?

For clarity - information doesn’t “disappear” from a page. You’re either deleting it (highly unlikely), or you’re not retrieving it, or you’re not saving it. when the form is submitted.

If you use any of the Django Admin, the Django shell, or your native database tools (example: psql), you can examine the database tables to see if the data is there. If it is present, then the issue is that you’re not retrieving it in your view for display.

When I submit the form in update_profile_work_uni, I am redirected to this page (I use return HttpResponseRedirect("work_uni") ).
I checked Django Admin. When I submit update_profile_work_uni Information does not have there which I wrote in update_profile_bio.
I think I resave information when I submit the form update_profile_work_uni, because in update_profile_work_uni contains ProfileForm which have main Profile models. But I don’t know how to fix it. Also I’m sorry If I explain bad
For example, in update_profile_work_uni

{{profile_form.masterdeg}}

{{profile_form.bachelordeg}}

in ```update_profile_bio``

{{profile_form.bio}}
{{profile_form.sphere}}

What is your urls.py entry for the url named work_uni? How is that view going to know what data to display?

And when you’re testing this, what is the exact and complete url that it is sending you to?

It’s not that your explanations are bad, you’re just leaving out a lot of useful information. I don’t know your system, or the flow of work. You should be getting into the habit of providing more detailed and specific information for what you’re trying to describe.

I think it’s better to add more information for you. I’m sorry that I’m doing this late
urls.py

from django.urls import path

from . import views
from .views import (Example, ProfileDetailView, update_profile_about,
                    update_profile_bio)

urlpatterns = [
    path("profile/<slug:slug>", ProfileDetailView.as_view(), name="profile"),
    path(
        "profile/<slug:slug>/update/about",
        views.update_profile_about,
        name="profile_update_about",
    ),
    path(
        "profile/<slug:slug>/update/bio",
        views.update_profile_bio,
        name="profile_update_bio",
    ),
    path(
        "profile/<slug:slug>/update/work_uni",
        views.update_profile_work_uni,
        name="profile_update_work_uni",

forms.py

class UserForm(forms.ModelForm):
    class Meta:
        model = CustomUser
        fields = [
            "first_name",
            "last_name",
            "email",
            "gender",
            "date_birthday",
        ]

class ProfileForm(forms.ModelForm):
    class Meta:
        model = Profile
        fields = (
            "bio",
            "image",
            "phone_number",
            "URL",
            "bachelordeg",
            "masterdeg",
        )

class WorkForm(forms.ModelForm):
    class Meta:
        model = Work_place
        fields = ("name")

class UniversityForm(forms.ModelForm):
    class Meta:
        model = University
        fields = ("name")

profile_update_bio.html

<form method="POST" enctype="multipart/form-data">
            {% csrf_token %}
            {{profile_form.media.js}}
            <div class="d-flex flex-column mb-3">
               <a href="{% url 'profile_update_about' user.profile.slug %}">About you</a>
               <a href="{% url 'profile_update_bio' user.profile.slug %}">Biography</a>
               <a href="{% url 'profile_update_work_uni' user.profile.slug %}">Work and University</a>
            </div>

               <label for="{{ profile_form.bio.id_for_label }}" class="form-label ">Biography:</label>
               {{profile_form.bio }}

   
               <button>
                  Update
               </button>
         </form>

profile_work_uni.html

      <div class="d-flex flex-column mb-3">
         <a href="{% url 'profile_update_about' user.profile.slug %}">About you</a>
         <a href="{% url 'profile_update_bio' user.profile.slug %}">Biography</a>
         <a href="{% url 'profile_update_work_uni' user.profile.slug %}">Work and University</a>
      </div>

      <div class="form-group">
         <form method="POST" nctype="multipart/form-data">
            {% csrf_token %}
            <!--WorkFormSet-->
            {{ work_formset.management_form }}


            <h2>Your Work:</h2>
            <div id='ingredient-form-list'>
               {% for form in work_formset %}
               {{ form.non_field_errors }}
               {{ form.errors }}

               <div class='ingredient-form border border-info mt-3'>
                  {{ form.as_p }}
               </div>
               {% endfor %}
            </div>

            {% comment %} Empty form {% endcomment %}
            <div id='empty-form' class='hidden mt-3'>{{ work_formset.empty_form.as_p }}</div>

            <div>
               <button class='btn btn-info mt-3 mb-3' id='add-more' type='button'>Add more</button>
            </div>
            <!--End WorkFormset-->


            <!--Start University-->
               <!--Bachelor Degree-->


                  <label for="{{ profile_form.bachelordeg.id_for_label }}" class="form-label">Bachelor Degree
                     University:</label>
                  {{profile_form.bachelordeg class="form-control"}}

                  <label for="{{ profile_form.masterdeg.id_for_label }}" class="form-label">Master degree
                     University:</label>
                  {{profile_form.masterdeg class="form-control" }}

profile_update_about.html


    <div class="d-flex flex-column mb-3">
      <a href="{% url 'profile_update_about' user.profile.slug %}">About you</a>
      <a href="{% url 'profile_update_bio' user.profile.slug %}">Biography</a>
      <a href="{% url 'profile_update_work_uni' user.profile.slug %}">Work and University</a>
    </div>


      <form method="POST" enctype="multipart/form-data" id="profileForm" novalidate>
        {% csrf_token %}
        {{ block.super }}
        {{profile_form.media}}

   <!--First Name and Last Name-->

            <label for="{{ user_form.first_name.id_for_label }}" class="form-label">First Name:*</label>
            {{ user_form.first_name }}



            <label for="{{ user_form.last_name.id_for_label }}" class="form-label">Last Name:*</label>
            {{ user_form.last_name }}


        <!--  End First Name and Last Name-->

          <label for="{{ profile_form.image.id_for_label }}" class="form-label">Image:</label>
          {{ profile_form.image }}


          <label for="{{ user_form.email.id_for_label }}" class="form-label">Email:*</label>
          {{ user_form.email }}


          <label for="{{ profile_form.phone_number.id_for_label }}" class="form-label">Phone Number:</label>
          {{ profile_form.phone_number }}




          <label for="{{ user_form.date_birthday.id_for_label }}">Date Birthday:*</label>
          {{ user_form.date_birthday }}



    <button>
      Update
    </button>

  </form>