Order fields in model forms User and Profile and u

2019-08-19 07:33发布

问题:

I posted this question but I couldn't get the solutions provided to work. Instead of editing, I'm posting a new one with the modified code which uses a different approach (with two model forms)

models.py

class Profile(models.Model):
    user = models.OneToOneField(User, on_delete=models.CASCADE, related_name='profile')
    location = models.CharField(max_length=30, blank=True)
    birth_date = models.DateField(null=True, blank=True)

    def __str__(self):
        return self.user.username



def create_profile(sender, **kwargs):
    user = kwargs["instance"]
    if kwargs["created"]:
        user_profile= Profile(user=user)
        user_profile.save()
post_save.connect(create_profile, sender=User)

forms.py

from django_superform import FormField, SuperForm

class SignUpForm(UserCreationForm):
    password1 = forms.CharField(label=("Password"), widget=forms.PasswordInput) 
    password2 = forms.CharField(label=("Confirm password"), widget=forms.PasswordInput)

    class Meta:
        model = User
        fields = ('username', 'first_name', 'last_name', 'email')
        labels = {
            'username': ('Capser name'),
        }

class ProfileForm(forms.ModelForm):
    class Meta:
        model = Profile
        fields = ('location', 'birth_date')


class SuperProfile(SuperForm):
    signupform = FormField(SignUpForm)
    profileform = FormField(ProfileForm)

See that I'm using the Superform from Django-superform package. The reason for that is that I'm uing a form template in my html template as explained later in the template section.

templates

html page template : registration_form.html

<form class="form-horizontal" action="" method="POST" enctype="multipart/form-data">
    {% csrf_token %}

    <h1>Create a capser account</h1>
    <table border="1">
        {{  userform.as_table }}

        {{ profileform.as_table }}
    </table>

    {% include 'home/form-template.html' %}

    <div class="form-group">
        <div class="col-sm-offset-2 col-sm-10">
            <button type="submit" class="btn btn-success">Create account</button>
        </div>
    </div>
</form>

form template : form-template.html

{% if messages %}
<ul>
    {% for message in messages %}
    <li>{{ message }}</li>
    {% endfor %}
</ul>
{% endif %}

{% for field in form %}
    <div class="form-group">
        <div class="col-sm-offset-2 col-sm-10">
            <span class="text-danger small">{{ field.errors }}</span>
        </div>
        <label class="control-label col-sm-2">{{ field.label_tag }}</label>
        <div class="col-sm-10">{{ field }}</div>
        <div class="col-sm-offset-2 col-sm-10">
                <span class="text-danger small">{{ field.help_text }}</span>
        </div>
    </div>

{% endfor %}

and the views.py with the new approach (importing fields from the two model forms

views.py

class UserFormView(View):
    Userform_class = SignUpForm
    Profileform_class = ProfileForm
    template_name = 'home/registration_form.html'

    #display a blank form
    def get(self, request):
        userform = self.Userform_class(None)
        profileform=self.Profileform_class(None)

        return render (request, self.template_name, {'userform': userform, 'profileform': profileform})

    #process form data
    def post(self, request):
        userform = self.Userform_class(request.POST)
        profileform = self.Profileform_class(request.POST)


        if userform.is_valid() and profileform.is_valid():
            user = userform.save(commit=False)
            #user.refresh_from_db()  # load the profile instance created by the signal
            password = userform.cleaned_data['password1']
            user.set_password(password)
            username = userform.cleaned_data['username']
            first_name=userform.cleaned_data['first_name']
            last_name=userform.cleaned_data['last_name']
            email = userform.cleaned_data['email']
            user.save()

            new_profile = user_profile.objects.get(user = request.user)
            new_profile.objects.create(
                user=user,
                location=profileform.cleaned_data.get('location'),
                birth_date=profileform.cleaned_data.get('birth_date'))
            new_profile.save()

            #return user objects if credentials are correct
            user = authenticate(username=username, password=password)

            if user is not None:
                if user.is_active:
                    login(request, user)
                    return redirect('home:home')

        return render (request, self.template_name, {'userform': userform, 'profileform':profileform})

Now when I submit my form, I get the following error : name 'user_profile' is not defined

I thought that the user_profile was the instance created at the end of my model.py file. So if this doesn't work like so, how do I call the instance of my Profile model in the view ?

I've tried a lot of solutions and none worked so far.

Also, I initially wanted to use my form-template in order to display my form on the html page, but now that I use two model forms userform and profileform, I wonder on how to use my form template (I tried with Superform without success).

回答1:

The error says it itself, user_profile is not defined. A part of your code is not correct in your views. You should deal with Django User Model, and after creating the instance, call your model Profile which is linked by OneToOneField to User from your your_app.models

from your_app.models import Profile

''' codes here '''
username = userform.cleaned_data['username']
first_name=userform.cleaned_data['first_name']
last_name=userform.cleaned_data['last_name']
email = userform.cleaned_data['email']
user.last_name = last_name
user.first_name = first_name
user.username = username
user.email = email
user.save()

new_profile = Profile.objects.create(
    user=user,
    location=profileform.cleaned_data.get('location'),
    birth_date=profileform.cleaned_data.get('birth_date')
)
new_profile.save()

That issue UNIQUE constraint failed: home_profile.user_id is because of the signal post_save is called by doing new_profile.save(). When it's called, it creates another profile with the same user, whereas user is already linked to the Profile when you had called new_profile.save() which has an OneToOneField() with User. So just remove the signal



标签: django forms