Search code examples
djangodjango-modelsdjango-formsdjango-users

AbstractUser Signup


Hello I am trying to extend Django User model using Abstract User but I get OperationalError when signing up

Error:

OperationalError at /main/signup/
no such column: main_profile.username

My Profile model:

class Profile(AbstractUser):

    email = models.EmailField(max_length=150)
    bio = models.TextField() 
    university = models.CharField(max_length=30)

    def __str__(self):
        return self.username

    CREATED = 0
    ACTIVE = 1
    BANNED = 2
    KICKED = 3
    UPGRADE = 4
    STS = (
        (CREATED, 'Just Created'),
        (ACTIVE, 'Activated'),
        (BANNED, 'Disabled'),
        (KICKED, 'Disabled'),
        (UPGRADE, 'Active'),
     )
    status = models.IntegerField(choices=STS, default=CREATED, blank=True, null=True)

My Signup form:

class SignUpForm(UserCreationForm):

    username = forms.CharField(
        label='',
        max_length=30,
        min_length=5,
        required=True,
        widget=forms.TextInput(
            attrs={
                "placeholder": "Username",
                "class": "form-control"
            }
        )
    )

    first_name = forms.CharField(
        label='',
        max_length=50,
        min_length=2,
        required=True,
        widget=forms.TextInput(
            attrs={
                "placeholder": "First name",
                "class": "form-control"
            }
        )
    )

    last_name = forms.CharField(
        label='',
        max_length=50,
        min_length=2,
        required=True,
        widget=forms.TextInput(
            attrs={
                "placeholder": "Last name",
                "class": "form-control"
            }
        )
    )

    university = forms.CharField(
        label='',
        max_length=50,
        min_length=2,
        required=False,
        widget=forms.TextInput(
            attrs={
                "placeholder": "University",
                "class": "form-control"
            }
        )
    )

    email = forms.EmailField(
        label='',
        max_length=255,
        required=True,
        widget=forms.EmailInput(
            attrs={
                "placeholder": "Email",
                "class": "form-control"
            }
        )
    )

    password1 = forms.CharField(
        label='',
        max_length=30,
        min_length=8,
        required=True,
        widget=forms.PasswordInput(
            attrs={
                "placeholder": "Password",
                "class": "form-control"
            }
        )
    )

    password2 = forms.CharField(
        label='',
        max_length=30,
        min_length=8,
        required=True,
        widget=forms.PasswordInput(
            attrs={
                "placeholder": "Confirm Password",
                "class": "form-control"
            }
        )
    )

    class Meta:

        model = Profile
        fields = ('username', 'first_name', 'last_name', 'email','university',) 

        def save(self, commit=True):
            user = super(UserCreationForm,self).save(commit = False)
            user.email = self.cleaned_data['email']
            user.university = self.cleaned_data['university']
            if commit:
                user.save()
            return user

My Signup view:

def signup(request):
    if request.method == 'POST':
        form = SignUpForm(request.POST)
        if form.is_valid():
            user = form.save()
            user.refresh_from_db()  # load the profile instance created by the signal
            user.profile.university = form.cleaned_data.get('university')
            user.save()
            raw_password = form.cleaned_data.get('password1')
            user = authenticate(username=user.username, password=raw_password)
            #user_login(request, user)
            return redirect('main:main_page')
    else:
        form = SignUpForm()
    return render(request, 'signup.html', {'form': form})

I have also added tis in setting already

AUTH_USER_MODEL = 'main.Profile'

I do not understand why there is an error should AbstractUser already provide username? Or do I have to add all the fields to the Profile model, even the passwords?

Below is also my custom edit profile - I do not know if it is correct however:

class EditProfileForm(UserChangeForm):

    username = forms.CharField(
        label='',
        max_length=50,
        min_length=2,
        required=False,
        widget=forms.TextInput(
            attrs={
                "placeholder": "Username",
                "class": "form-control"
            }
        )
    )


    first_name = forms.CharField(
        label='',
        max_length=50,
        min_length=2,
        required=False,
        widget=forms.TextInput(
            attrs={
                "placeholder": "First name",
                "class": "form-control"
            }
        )
    )

    last_name = forms.CharField(
        label='',
        max_length=50,
        min_length=2,
        required=False,
        widget=forms.TextInput(
            attrs={
                "placeholder": "Last name",
                "class": "form-control"
            }
        )
    )

    university = forms.CharField(
        label='',
        max_length=50,
        min_length=2,
        required=False,
        widget=forms.TextInput(
            attrs={
                "placeholder": "University",
                "class": "form-control"
            }
        )
    )

    email = forms.EmailField(
        label='',
        max_length=255,
        required=False,
        widget=forms.EmailInput(
            attrs={
                "placeholder": "Email",
                "class": "form-control"
            }
        )
    )

    bio = forms.CharField(
        required=False,
        widget=forms.Textarea(
            attrs={
                "placeholder":"Enter something about yourself",
                "class": "form-control"
            }
        )
    )


    password = None

    class Meta:
        model = Profile
        fields=('username','first_name','last_name','email','bio',)
        def save(self, commit = True):
            user = super(UserChangeForm, self).save(commit=False)
            user.bio = self.cleaned_data['bio']

            if commit:
                user.save()
            return user

Thanks in advance for all the help!


Solution

  • When you use AbstractUser it give you predefine User model fields + New fields that you define in model extend time

    here when you extend user model not need to define email field explicitly due to 'User model' Have this field and when you use UserCreationForm it also have all pre-define field you don't need to Redefine it, In your case you define username,first_name,last_name,email it's not need,but if you want to take input of extra field then, you need to define extra field that you add in your model like university or bio and if you need to add placeholder or bootstrap classes you use pre_define method def __init__ i give you stuff apply it's in you code

    @model.py

    class Profile(AbstractUser):
        # remove email fields
        bio = models.TextField() 
        university = models.CharField(max_length=30)
    
        def __str__(self):
            return self.username
    

    @form.py

    class SignUpForm(UserCreationForm):
            university=formforms.CharField(label='',max_length=50,min_length=2)
    
            class Meta:
                    model = Profile
                    fields = ('username', 'first_name', 'last_name', 'email','university',) 
    
                    def __init__(self,*args,**kwargs):
                            super().__init__(*args,**kwargs)
                            for field in self.fields:
                                    self.fields[field].widget.attrs.update({'class':'form-control','placeholder':self.fields[field].label})
    

    @views.py

    def signup(request):
        if request.method == 'POST':
            form = SignUpForm(request.POST)
            if form.is_valid():
                user = form.save()
                raw_password = form.cleaned_data.get('password1')
                user = authenticate(username=user.username, password=raw_password)
                return redirect('main:main_page')
        else:
            form = SignUpForm()
        return render(request, 'signup.html', {'form': form})
    

    apply above stuff and let me know if work or not