1

In my SignUp page I've 2 forms UserForm and Profile Form.

Profile Form relies in Profile model, that has a OneToOneField to the User model -default User model from Django-.

The idea is that when a User is created, a Profile for this user is also created:

@receiver(post_save, sender=User)
def update_user_profile(sender, instance, created, **kwargs):
    if created:
        Profile.objects.create(user=instance)
    instance.profile.save()

Profile model:

class Profile(models.Model):
    user = models.OneToOneField(User, on_delete=models.CASCADE)
    # birth_date = models.DateField(null=True, blank=True)
    dni = models.CharField(max_length=30, blank=True)
    #phone_number = models.CharField(max_length=15, blank=True)
    shipping_address1 = models.CharField(max_length=100, blank=False)
    shipping_address2 = models.CharField(max_length=100, blank=False)
    shipping_department = models.CharField(max_length=100, blank=False)
    shipping_province = models.CharField(max_length=100, blank=False)
    shipping_district = models.CharField(max_length=100, blank=False)

    def __str__(self):
        return str(self.user.first_name) + "'s profile" 

Problem: UserForm.is_valid() is True, but Profile_Form.is_valid() is False.

But in my request, I'm getting all the right values for ProfileForm:

<QueryDict: {'csrfmiddlewaretoken': ['91sJC01vyty3Z9ECjrSop1bouUOF2ZeC9m6XZUgk0nTEH7p6W0DmtuQaB4EBhV22'], 'first_name': ['Juana'], 'last_name': ['Juana'], 'username': ['juana
juana'], 'dni': ['454545'], 'email': ['[email protected]'], 'password1': ['caballo123'], 'password2': ['caballo123'], 'shipping_address1': ['Urb. La Merced Mz.G Lot.32'], 'ship
ping_address2': ['Villa FAP - San Roque'], 'shipping_department': ['Cajamarca'], 'shipping_province': ['Cajamarca'], 'shipping_district': ['Cajamarca']}>

How to save correctly the ProfileForm?

View that displays the UserForm and the ProfileForm:

@transaction.atomic
def signupView(request):
    peru = Peru.objects.all()
    department_list = set()
    province_list = set()
    district_list = set()
    for p in peru:
        department_list.add(p.departamento)
    department_list = list(department_list)
    print("Department List: ", department_list)
    if len(department_list):
        province_list = set(Peru.objects.filter(departamento=department_list[0]).values_list("provincia", flat=True))
        print("Provice List: ", province_list)
        province_list = list(province_list)
        # print("dfsfs", province_list)
    else:
        province_list = set()
    if len(province_list):
        district_list = set(
            Peru.objects.filter(departamento=department_list[0], provincia=province_list[0]).values_list("distrito",
                                                                                                         flat=True))
        print("district List: ", district_list)
    else:
        district_list = set()

    if request.method == 'POST':
        user_form = SignUpForm(request.POST)
        profile_form = ProfileForm(district_list, province_list, department_list, request.POST)
        print("This is Profile Form: ", profile_form)
        print("Is Profile_Form valid: ", profile_form.is_valid())
        if user_form.is_valid() and profile_form.is_valid():
            user = user_form.save()
            username = user_form.cleaned_data.get('username')
            signup_user = User.objects.get(username=username)
            customer_group = Group.objects.get(name='Clientes')
            customer_group.user_set.add(signup_user)
            raw_password = user_form.cleaned_data.get('password1')
            user.refresh_from_db()  # This will load the Profile created by the Signal
            # print(user_form.cleaned_data)
            print("Form is valid: district_list, province_list, department_list")
            print(district_list, province_list, department_list)
            profile_form = ProfileForm(district_list, province_list, department_list, request.POST,
                                       instance=user.profile)  # Reload the profile form with the profile instance
            profile_form.full_clean()  # Manually clean the form this time. It is implicitly called by "is_valid()" method
            # print(profile_form.cleaned_data)
            profile_form.save()  # Gracefully save the form

            user = authenticate(username=username, password=raw_password)
            login(request, user)

            return redirect('cart:cart_detail')
    else:
        print("INVALID FORM")
        user_form = SignUpForm()

        profile_form = ProfileForm(district_list, province_list, department_list)
        print('end of profile postdata print')
        print(profile_form)
        print("Profile Data:")

    return render(request, 'accounts/signup.html', {
        'user_form': user_form,
        'profile_form': profile_form
    })

This line returns false:

print("Is Profile_Form valid: ", profile_form.is_valid())

ProfileForm:

class ProfileForm(ModelForm):

    def __init__(self, district_list, province_list, department_list, *args, **kwargs):
        super(ProfileForm, self).__init__(*args, **kwargs)
        self.fields['shipping_district'] = forms.ChoiceField(choices=tuple([(name, name) for name in district_list]))
        self.fields['shipping_province'] = forms.ChoiceField(choices=tuple([(name, name) for name in province_list]))
        self.fields['shipping_department'] = forms.ChoiceField(choices=tuple([(name, name) for name in department_list]))

    dni = forms.CharField(label='DNI', max_length=100, required=True)
    shipping_address1 = forms.CharField(label='Dirección de envío', max_length=100, required=True)
    shipping_address2 = forms.CharField(label='Dirección de envío 2 (opcional)', max_length=100, required=False)

    class Meta:
        model = Profile
        fields = ('dni', 'shipping_address1',
                  'shipping_address2', 'shipping_department', 'shipping_province', 'shipping_district')

UPDATE 1:

    else:
        print("INVALID User_FORM")
        print(user_form.errors)
        print("INVALID Profile_FORM")
        print(profile_form.errors)


INVALID User_Form

INVALID Profile_Form
<ul class="errorlist"><li>shipping_province<ul class="errorlist"><li>Select a valid choice. Tarata is not one of the available choices.</li></ul></li><li>shipping_district<ul
 class="errorlist"><li>Select a valid choice. Estique is not one of the available choices.</li></ul></li></ul>
[25/Jan/2019 18:18:38] "POST /account/create/ HTTP/1.1" 200 16522
[25/Jan/2019 18:18:38] "GET /static/css/footer.css HTTP/1.1" 404 1767

1 Answer 1

1

Choices fields in forms do not expect a list of values. You will have several options, but the field will have only one value.

So, try this:

 profile_form = ProfileForm(request.POST)

and compute the values for shipping_district, shipping_province and shipping_department as part __init__ in your form.

Update:

if order to see errors change your code:

user_form_valid =  user_form.is_valid()
profile_form_valid = profile_form.is_valid()

if user_form_valid and profile_form_valid:
    # ...
else:
    # print(user_form.errors)
    # print(profile_form.errors)
    # ...

Update #2

The choices are not the same in the form you're presenting to the user are the one you're binding in your view, try to initialize try to find a way to initialize those choices the same values for every ProfileForm you instantiate.

On the other hand, I encourage you to use FormSet for this kind of situations.

Sign up to request clarification or add additional context in comments.

7 Comments

Using: profile_form = ProfileForm(request.POST) returns __init__() missing 2 required positional arguments: 'province_list' and 'department_list'
What I'm saying is in your constructor you're setting the options of such fields, not the value.
Yeah, I understand. But I how to pass shipping_district, shipping_province and shipping_department as part of POST? i need to put inside ProfileForm(shipping_deparment = request.POST.get('shipping_deparment'), shipping_province = request.POST.get('shipping_province'), shipping_district = request.POST.get('shipping_district'), request.POST)??
What's the value of form.errors after form.is_valid?
Cannot access that part becuase of: if user_form.is_valid() and profile_form.is_valid(): since profile_form is not valid, I cannot pass that conditional. please, see more details in my code, and tell me where should I call form.errors.
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.