Django - Updating multiple models from a form - Data does not saved

40 views
Skip to first unread message

Bernardo Garcia

unread,
Apr 12, 2017, 2:31:53 PM4/12/17
to Django users

I have a custom User model to manage some profiles user: is_studentis_professor and is_executive


In this model, in addition, I have the get_student_profile(),get_professor_profile() andget_executive_profile() methods to get the user profiles data of each user from my different views.


class User(AbstractBaseUser, PermissionsMixin):

    email = models.EmailField(unique=True)
    username = models.CharField(max_length=40, unique=True)
    slug = models.SlugField(max_length=100, blank=True)
    is_student = models.BooleanField(default=False)
    is_professor = models.BooleanField(default=False)
    is_executive = models.BooleanField(default=False)

    def get_student_profile(self):
        student_profile = None
        if hasattr(self, 'studentprofile'):
            student_profile = self.studentprofile
        return student_profile

    def get_professor_profile(self):
        professor_profile = None
        if hasattr(self, 'professorprofile'):
            professor_profile = self.professorprofile
        return professor_profile

    def get_executive_profile(self):
        executive_profile = None
        if hasattr(self, 'executiveprofile'):
            executive_profile = self.executiveprofile
        return executive_profile


In addition each profile user is_studentis_professor and is_executive have their own model in where I manage their own data:



class StudentProfile(models.Model):
    user = models.OneToOneField(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)

    slug = models.SlugField(max_length=100,blank=True)
    origin_education_school = models.CharField(max_length=128)
    current_education_school = models.CharField(max_length=128)
    extra_occupation = models.CharField(max_length=128)

class ProfessorProfile(models.Model):
    user = models.OneToOneField(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
    slug = models.SlugField(max_length=100,blank=True)


class ExecutiveProfile(models.Model):
    user = models.OneToOneField(settings.AUTH_USER_MODEL,on_delete=models.CASCADE)
    slug = models.SlugField(max_length=100,blank=True)


Is of this way that in my User model I override the save() method to denote that the usernamefield of an user which is created, to be equal in their value to the slug belonging to the profile user which will take that user (StudentProfileProfessorProfileExecutiveProfile):



def save(self, *args, **kwargs):
        user = super(User,self).save(*args,**kwargs)

        # Creating an user with student, professor and executive profiles
        if self.is_student and not StudentProfile.objects.filter(user=self).exists() \
            and self.is_professor and not ProfessorProfile.objects.filter(user=self).exists() \
            and self.is_executive and not ExecutiveProfile.objects.filter(user=self).exists():
            student_profile = StudentProfile(user=self)
            student_slug = self.username
            student_profile.slug = student_slug

            professor_profile = ProfessorProfile(user=self)
            professor_slug = self.username
            professor_profile.slug = professor_slug

            executive_profile = ExecutiveProfile(user=self)
            executive_slug = self.username
            executive_profile.slug = executive_slug

            student_profile.save()
            professor_profile.save()
            executive_profile.save()
        # And so for all possibles profile combinations


To these three profiles which I have three forms in where their own fields are generated


class StudentProfileForm(forms.ModelForm):
    class Meta:
        model = StudentProfile
        fields = ('origin_education_school', 'current_education_school',
        'extra_occupation')

class ProfessorProfileForm(forms.ModelForm):
    class Meta:
        model = ProfessorProfile
        fields = ('occupation',)

class ExecutiveProfileForm(forms.ModelForm):
    class Meta:
        model = ExecutiveProfile
        fields = ('occupation', 'enterprise_name', 'culturals_arthistic','ecological')



I access to view profile to user through of this URL:


url(r"^profile/(?P<slug>[\w\-]+)/$",
        views.account_profiles__update_view,
            name='profile'
    ),


In my function based view account_profiles__update_view() I am managing the request of the user, and creating the form instances (StudentProfileFormProfessorProfileFormExecutiveProfileForm) according to the profile to user (is_studentis_professor and is_executive)



@login_required
def account_profiles__update_view(request, slug):
    user = request.user
    # user = get_object_or_404(User, username = slug)

    # empty list
    _forms = []
    if user.is_student:
        profile = user.get_student_profile()
        _forms.append(forms.StudentProfileForm)
    if user.is_professor:
        profile = user.get_professor_profile()
        _forms.append(forms.ProfessorProfileForm)
    if user.is_executive:
        profile = user.get_executive_profile()
        _forms.append(forms.ExecutiveProfileForm)

    # user = get_object_or_404(settings.AUTH_USER_MODEL, username = slug)

    if request.method == 'POST':
        # Create a list with all formularies in which there is some POST
        # operation. This mean if there is one, two or three profiles together
        # or individual
        formularios =[Form(data = request.POST,instance=profile) for Form in _forms]

        if all([form.is_valid() for form in formularios]):
            # Only save dato to database if all formularies that send
            # the user in their request are correct or well formed in their
            # data. Check that all formularies has been filled
            for form in formularios:
                profile = form.save(commit=False)
                profile.user = user
                profile.save()
            return redirect('dashboard')
    else:
        formularios = [Form() for Form in _forms]

    # Access to class Forms instanced (StudentProfileForm,
    # ProfessorProfileForm, ExecutiveProfileForm), through the __class__
    # pŕoperty which return the class onlying. An this class have another
    # property named __name__ which return the name of string of a class,
    # which is the same name with I did name the form classes
    # (StudentProfileForm, ProfessorProfileForm, ExecutiveProfileForm)
    # Next I call to their string method to grant that I always will return
    # a string and I call to lower.

    # The idea with this is place data into a python dictionarie and access
    # to it
    data = {form.__class__.__name__.__str__().lower(): form for form in formularios}
    data['userprofile'] = profile
    return render(request, 'accounts/profile_form.html', data,)


And my profile_form.html template I have the following small logic:


<form method="POST">
    {% csrf_token %}
    {% if userprofile.user.is_student %}
    <div align="center"><i>My Student Profile data</i></div>
        {% bootstrap_form studentprofileform %}
             {{ studentprofileform.non_field_errors }}
        {% endif %}          
        {% if userprofile.user.is_professor %}
            <div align="center"><i>My Professor Profile data</i></div>
            {% bootstrap_form professorprofileform %}
            {{ professorprofileform.non_field_errors }}
        {% endif %}
        {% if userprofile.user.is_executive %} 
            <div align="center"><i>My Executive Profile data</i></div>  
            {% bootstrap_form executiveprofileform %}
            {{ executiveprofileform.non_field_errors }}
        {% endif %}
        <input type="submit" value="Save Changes" class="btn btn-default">
</form>


I wanted to write all these details to comment the following situation which happen to me:

I render the three forms in my template


Only store data related to the latest user profile selected, this mean:


profiles: is_studentis_professor and is_executive

  • User with is_student profile ... Save data

  • User with is_professor profile ... Save data

  • User with is_executive profile ... Save data


  • User with is_student and is_professor profile: Only save data to is_professor profile. Does not save data in is_student profile forms fields


  • User with is_student and is_executive profile: Only save data to is_executive profile. Does not save data in is_student profile forms fields


  • User with is_professor and is_executive profile: Only save data to is_executiveprofile. Does not save data in is_professor profile forms fields


  • User with is_studentis_professor and is_executive profiles: Only save data to is_executive profile. Does not save data in is_professor and is_student profile forms fields

In this moment, only is taked in account the latest selected profile user and according to it, save their related data and not other.

This is because in my account_profiles__update_view() function based view I have this if .. sentences logic:


if user.is_student:
    profile = user.get_student_profile()
    _forms.append(forms.StudentProfileForm)
if user.is_professor:
    profile = user.get_professor_profile()
    _forms.append(forms.ProfessorProfileForm)
if user.is_executive:
    profile = user.get_executive_profile()
    _forms.append(forms.ExecutiveProfileForm)


But, I unknown if I will should consider perform here all the profiles user combinations possibles and create the same combination of form instances possibles too. Is this factible of perform?


I try perfom account_profiles__update_view() as a class based view, here some code about it but the characterization of profiles and instances forms send to the template, make me that I choose the function based view option. ¿What is the best alternative?


My apologies for the long question, I did want give all details for to better understanding of my code and approach that I want accomplish. I appreciate highly some support and orientation.



Reply all
Reply to author
Forward
0 new messages