I tried to create a custom Signup Form with allauth but when I submit the form on the frontend it directs to the success_url and upon inspection in the admin panel a new user wasn't created.
# forms.py
from allauth.account.forms import SignupForm
class SimpleSignupForm(SignupForm):
mobile_number = PhoneNumberField(required=True)
first_name = forms.CharField(widget=forms.TextInput(attrs={'class': 'form-control'}), max_length=255, required=True)
last_name = forms.CharField(widget=forms.TextInput(attrs={'class': 'form-control'}), max_length=255, required=True)
address = AddressField(required=True)
type = forms.ModelChoiceField(queryset=UserType.objects.all())
def save(self, request):
user = super(SimpleSignupForm, self).save(request)
user.mobile = self.cleaned_data['mobile_number']
user.address = self.cleaned_data['address']
user.first_name = self.cleaned_data['first_name']
user.last_name = self.cleaned_data['last_name']
user.type = self.cleaned_data['type']
user.save()
return user
def __init__(self, *args, **kwargs):
super(SimpleSignupForm, self).__init__(*args, **kwargs)
visibles = self.visible_fields()
visibles[0].field.widget.attrs['class'] = 'form-control'
# settings.py
ACCOUNT_FORMS = {'signup': 'my_app_path.forms.SimpleSignupForm'}
On the template file I made sure the <form> tag has method='POST' and that I included {% csrf_token %} in the form. The button is also a a submit type. I've also made sure {{ form.as_p }} has all the required fields when submitting. There are no errors or warnings popping up anywhere.
I hope this helps. I will recommend you use Signup method instead of Save
class CustomSignupForm(forms.Form):
first_name = forms.CharField(max_length=30, label='First Name')
last_name = forms.CharField(max_length=30, label='Last Name')
def __init__(self, *args, **kwargs):
super(CustomSignupForm, self).__init__(*args, **kwargs)
self.fields['first_name'].widget.attrs['placeholder'] = 'First Names'
self.fields['last_name'].widget.attrs['placeholder'] = 'Last Names'
def signup(self, request, user):
user.first_name = self.cleaned_data['first_name']
user.last_name = self.cleaned_data['last_name']
user.save()
Related
can you help me out through this problem?, I'm a beginner and trying to learn django..even tho i tried so many other ways but it just wont work out. i hope you can help me
models.py
from django.db import models
from django.db.models.fields import CharField , IntegerField, EmailField
class Member(models.Model):
first_name = models.CharField(max_length=100)
last_name = models.CharField(max_length=50)
email = models.EmailField()
age = models.IntegerField()
password = models.CharField(max_length=100,null=True)
def __str__(self):
return self.first_name + " " + self.last_name
form.py
from django.db.models import fields
from django.forms import ModelForm
from django import forms
from .models import Member
class MemberForm(forms.ModelForm):
class Meta:
model = Member
fields = ["first_name", "last_name", "age", "email", "password"]
views.py
from django.shortcuts import render
from .models import Member
from .form import MemberForm
# Create your views here.
def join(request):
if request.method == "POST":
form = MemberForm(request.POST or None)
if form.is_valid():
form.save()
return render(request, "HTML/join.html",{})
else:
form = MemberForm()
return render(request, "HTML/join.html",{})
error
The view myapp.views.join didn't return an HttpResponse object. It returned None instead.
If the form is not valid, your view must return a response:
def join(request):
if request.method == "POST":
form = MemberForm(data=request.POST)
if form.is_valid():
form.save()
return render(request, "HTML/join.html",{})
else:
return HttpResponse(status=400) # Replace with what makes sense to you
else:
form = MemberForm()
return render(request, "HTML/base.html", {})
In your urls write something like:
urlpatterns = [
path('', join)
]
Note also that you should pass the form in the context parameter of render like: render(request, "HTML/base.html", {'form': form}).
https://docs.djangoproject.com/en/3.2/topics/http/shortcuts/
as you can see in documents, render function's third parameter is context. you are passing argument as {}, blank dictionary.
you have to do something like this.
from django.shortcuts import render
from .models import Member
from .form import MemberForm
# Create your views here.
def join(request):
if request.method == "POST":
form = MemberForm(request.POST or None)
if form.is_valid():
form.save()
return render(request, "HTML/join.html",{})
else:
form = MemberForm()
return render(request, "HTML/base.html",{'form':form})
In your Template
<form method="post">
{% csrf_token %}
{{ form }}
<input type="submit" value="Submit">
</form>
I am new to Django and am building a database-driven website using PyCharm.
I am having an issue with users registering/logging in. What is happening is, when a user registers, I check the "Database" tab to the right, and the information will be passed into a table named "SavBlock_user", which will have the users name, password, etc.. Then, when I try to log in, it won't allow me to login due to incorrect username/password. However, if I try to login using a username/password from a different table named "auth_user" (like username: admin / password: admin), then I can successfully login. I'm not sure how to fix this.
Ideally, what I would like to do is completely remove the "SavBlock_user" table and strictly use "auth_user" for all of my users, but I'm not sure how to do this. I may have created a 'custom' user model back when I was learning the system, but I can't remember.
My files:
Project\register\forms.py
from django import forms
from SavBlock.models import * # <--- Contains User
''' Form for users to register '''
class RegisterForm(forms.ModelForm):
email = forms.EmailField(
initial='myemail#savagez.com'
)
uso_validate = forms.BooleanField(
label='Are you a PSMC member? (Chief, Uso, Anak)',
initial=False
)
class Meta:
model = User
widgets = {
'password': forms.PasswordInput(),
}
fields = '__all__'
Project\register\views.py
from django.http import request
from django.shortcuts import render, redirect
from .forms import RegisterForm
# Create your views here.
def register(response):
if response.method == "POST":
form = RegisterForm(response.POST or None)
if form.is_valid():
form.save()
return redirect('/dashboard/')
else:
form = RegisterForm()
return render(response, 'register/register.html', {'form': form})
Project\SavBlock\models.py
from django.db import models
class User(models.Model):
username = models.CharField("user name", max_length=50, default='')
email = models.EmailField("email address", unique=True, default='DEFAULT VALUE')
first_name = models.CharField("first name", max_length=50)
last_name = models.CharField("last name", max_length=50)
password = models.CharField("password", unique=True, max_length=50, default='')
rank = {
0: 'Supporter',
1: 'Anak',
2: 'Uso',
3: 'Chief'
}
#TODO: FIT __INIT__
'''
def __init__(self, first_name, last_name, *args, **kwargs):
super().__init__(*args, **kwargs)
self.first_name = first_name.title()
self.last_name = last_name.title()
'''
# Magic method returns string of self
def __str__(self):
return f"User {self.first_name} {self.last_name} rank {self.rank}".strip()
#property
def get_full_name(self):
return f"{self.first_name} {self.last_name}".strip()
class Anak(User):
def __init__(self, first_name, last_name, tribe):
super().__init__(first_name, last_name)
self.tribe = tribe.title()
self.rank = User.rank[1]
class Uso(User):
def __init__(self, first_name, last_name, tribe):
super().__init__(first_name, last_name)
self.tribe = tribe.title()
self.rank = User.rank[2]
----EDIT----
I fixed the different user tables and basically reset the migrations. Now, all users are showing up under a single user table SavBlock_user. However, the login issue is still there.
Admin was created using the terminal manage.py createsuperuser command. I am able to login on the webpage using this account.
testing123 was created using the registration form. It pulls up a message that says "Please enter a correct username and password".
Anyone have any ideas?
consider this my models.py file.
from django.db import models
class alldets(models.Model):
first_name = models.CharField(max_length=50, default ='first name')
second_name = models.CharField(max_length=50, default='second name')
school = models.CharField(max_length=50, default='school name')
county = models.CharField(max_length=50, default='where from')
phone = models.CharField(max_length=20, default='phone number')
age = models.IntegerField(default='254')
def __str__(self):
return self.first_name
How do i add a photo just to it then parse it to the views.py and then to the template?
First of all install Pillow
pip install pillow
Then models.py
class AllDets(models.Model):
first_name = models.CharField(max_length=50, default ='first name')
second_name = models.CharField(max_length=50, default='second name')
school = models.CharField(max_length=50, default='school name')
county = models.CharField(max_length=50, default='where from')
phone = models.CharField(max_length=20, default='phone number')
age = models.IntegerField(default='254')
photo = models.ImageField(upload_to='images/photos')
def __str__(self):
return self.first_name
If you want to make the model available in django admin, register the model in admin.py
from .models import AllDets
admin.site.register(AllDets)
You can retrieve data in views.py as usual
from .models import AllDets
def index(request):
if request.method == 'POST':
form = DocumentForm(request.POST, request.FILES)
if form.is_valid():
form.save()
return redirect('home')
else:
print(form.errors)
else:
form = DocumentForm()
context = {
'form': form,
'all_dets' : AllDets.objects.all(),
}
return render(request, 'app/index.html', context)
Then in index.html you can render data as follows
{{all_dets.first_name}}
{{all_dets.second_name}}
{{all_dets.school}}
{{all_dets.county}}
{{all_dets.phone}}
{{all_dets.age}}
{{all_dets.photo.url}}
and remember to add enctype on your form
<form method="post" enctype="multipart/form-data">
{% csrf_token %}
{{ form.as_p }}
<button type="submit">Upload</button>
</form>
I'm new to python and Flask, I'm having an issue with updating a field entry, I can add 2 fields in a user profile and saves data to their user page, also I'm able to delete that entry, but when trying to update the "Tips" field, it comes back as a 'Bad Request' error; files are:
app.py:
from flask import Flask, render_template, request, redirect, url_for, flash
from flask_wtf import FlaskForm
from wtforms import StringField, SubmitField, PasswordField
from flask_sqlalchemy import SQLAlchemy
from forms import RegistrationForm, LoginForm, InstrumentForm, IdeasForm
from werkzeug.urls import url_parse
from werkzeug.security import generate_password_hash, check_password_hash
from wtforms import StringField, SubmitField
from wtforms.validators import ValidationError, DataRequired, Email, EqualTo, Length
from flask_login import LoginManager, UserMixin, current_user, login_user, logout_user, login_required
from flask_bootstrap import Bootstrap
app = Flask(__name__)
app.config['SECRET_KEY'] = 'secret'
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///Mix_Tips.db'
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
app.config["TEMPLATES_AUTO_RELOAD"] = True
db = SQLAlchemy(app)
login_manager = LoginManager()
login_manager.init_app(app)
login_manager.login_view = 'login'
class User(db.Model, UserMixin):
id = db.Column(db.Integer, primary_key= True)
username = db.Column(db.String(15), index =True, unique = True)
email = db.Column(db.String(150), index = True, unique = True)
password_hash = db.Column(db.String(200))
idea = db.relationship('Ideas', backref='author', lazy='dynamic')
def __repr__(self):
return '<User {}>'.format(self.username)
return '<N'
def set_password(self, password):
self.password_hash = generate_password_hash(password)
def check_password_hash(self, password):
return check_password_hash(self.password_hash, password)
class Tips(db.Model):
Instrument = db.Column(db.String(50), primary_key = True)
Frequency_Boost = db.Column(db.String(200), index =True, unique=True)
Frequency_Cut = db.Column(db.String(200), index =True, unique = True)
Advice = db.Column(db.String(500))
class Ideas(db.Model):
id = db.Column(db.Integer, primary_key = True)
Instrument = db.Column(db.String(50))
Tips = db.Column(db.String(200))
user_id = db.Column(db.Integer, db.ForeignKey('user.id'))
def __repr__(self):
return '<Tricks {}>'.format(self.Tips)
#app.route('/', methods=["GET", "POST"])
def login():
form = LoginForm()
if form.validate_on_submit():
user = User.query.filter_by(username=form.username.data).first()
if user and user.check_password_hash(form.password.data):
login_user(user, remember=form.remember_me.data)
return redirect(url_for('user', username = form.username.data))
if user is None or not user.check_password_hash(form.password.data):
flash('Invalid username or password')
return render_template('login.html', form=form)
#app.route('/register', methods=["GET", "POST"])
def register():
form = RegistrationForm()
if form.validate_on_submit():
user = User(username=form.username.data, email=form.email.data)
user.set_password(form.password.data)
db.session.add(user)
db.session.commit()
flash('Congratulations, you are now a registered user!')
return redirect(url_for('login'))
return render_template('register.html', title='Register', form=form)
#app.route('/user/<username>', methods=["GET", "POST"])
#login_required
def user(username):
user = current_user
user = User.query.filter_by(username=user.username).first()
idea = Ideas.query.filter_by(user_id=user.id)
if idea is None:
idea = []
form = IdeasForm()
if request.method == 'POST' and form.validate():
New_Idea = Ideas(Instrument = form.Instrument.data, Tips = form.Tips.data, user_id=current_user.id)
db.session.add(New_Idea)
db.session.commit()
print(request.form.get('Tips'))
return render_template('user.html', user=user, form=form, idea=idea)
#app.route('/update/<int:id>', methods=['POST', 'GET'])
def update(id):
tip_to_update = Ideas.query.get_or_404(id)
if request.method == 'POST':
tip_to_update.Tips = request.form['Tips']
db.session.commit()
return redirect(url_for('user', username=current_user))
else:
return render_template('update.html', tip_to_update=tip_to_update)
#app.route('/delete/<int:id>')
def delete(id):
idea_to_delete = Ideas.query.get_or_404(id)
try:
db.session.delete(idea_to_delete)
db.session.commit()
return redirect(url_for('user', username=current_user))
except:
return "Problem Deleting"
#login_manager.user_loader
def load_user(id):
return User.query.get(int(id))
#app.route('/logout')
def logout():
logout_user()
return redirect(url_for('login'))
**user.html:**
{% extends 'base.html' %}
{% block content %}
<center><h1 style="color:rgb(41, 15, 135)">Welcome back {{current_user.username }}!</h1></center>
<center><h2 style="color:rgb(41, 15, 135)">Music Mixing Guide</h2></center>
<h3 style="color:rgb(69, 67, 67)">Add your Instrument and Specific Tips for Mixing below:</h3>
<form action="user" method='POST'>
{{ form.hidden_tag() }}
<p
style="color:rgb(52, 52, 52)">{{form.Instrument.label}} <br>
{{form.Instrument(size=30)}}
</p>
<p
style="color:rgb(52, 52, 52)">{{form.Tips.label}} <br>
{{form.Tips(size=80)}}
</p>
<p> <input class="btn btn-outline-dark" type="submit" value="Add"></p>
</form>
<br>
<h3>Your Music Mixing Tips</h3>
{% for tricks in idea %}
<ol>
<li><p style="color:rgb(41, 15, 135)"> <b><h5>Instrument:</h5></b> {{tricks.Instrument}}</li>
<p style="color:rgb(41, 15, 135)"> <b><h5>Tip:</h5></b> {{tricks.Tips}}
</ol>
<p></p> Update
Delete
<br>
{% endfor %}
<br>
<br>
<br>
Log Out
{% endblock %}
**update.html:**
{% extends 'base.html' %}
{% block content %}
<div class='container'></div>
<h2>Update Mix Tip</h2>
<br>
<form action="/update/{{tip_to_update.id}}" method="POST">
<input type="text" placeholder="Tip" Tips="Tips" class="form-control" value="{{tip_to_update.Tips}}"> <br> <br>
<input type="submit" value="Update" class="btn btn-secondary btn-sm">
</form>
</div>
{% endblock %}
**forms.py**
from flask_wtf import FlaskForm
from wtforms import StringField, PasswordField, BooleanField, SubmitField, SelectField
from wtforms.validators import ValidationError, DataRequired, Email, EqualTo, Length
from flask_sqlalchemy import SQLAlchemy
class RegistrationForm(FlaskForm):
username=StringField('Username', validators=[DataRequired(), Length(min=4, max=15)])
email=StringField('Email', validators=[DataRequired(), Email(message='Invalid Email'), Length(max=150)])
password=PasswordField('Password', validators=[DataRequired(), Length(min=4, max=150)])
Repeat_password=PasswordField('Repeat Password', validators=[DataRequired(), EqualTo('password')])
submit=SubmitField('Register')
class LoginForm(FlaskForm):
username=StringField('Username', validators=[DataRequired(), Length(min=4, max=15)])
password=PasswordField('Password', validators=[DataRequired(), Length(min=4, max=150)])
remember_me=BooleanField('Remember Me')
submit=SubmitField('Sign In')
class InstrumentForm(FlaskForm):
Instrument= SelectField('Instrument', choices=[('Voice'), ('Acoustic Guitar'), ('Electric Guitar'),
('Bass Guitar'), ('Piano'), ('Bass Drum'), ('Snare Drum'), ('HiHats'), ('Toms'), ('Cymbals'), ('Brass')])
class IdeasForm(FlaskForm):
Instrument = StringField('Instrument')
Tips = StringField('Tips')
submit= SubmitField('Add')
def validate_username(self, username):
user = User.query.filter_by(username=username.data).first()
if user is not None:
raise ValidationError('Please use a different username.')
def validate_email(self, email):
user = User.query.filter_by(email=email.data).first()
if user is not None:
raise ValidationError('Please use a different email address.')
I think it may have something to do with the "request.form['Tips'] line in app.py, but would like to know for sure and how to fix it.
Thanks
welcome mac. I'm not sure the error message, but as far as i can tell you'll need to rework your database models, your relationships to be precised. Here is an example:
class Ideas(db.Model):
id = db.Column(db.Integer, primary_key = True)
instrument = db.Column(db.String(50))
tips = db.relationship("Tips", lazy="dynamic")
user_id = db.Column(db.Integer, db.ForeignKey('user.id'))
have a look at the docs: https://flask-sqlalchemy.palletsprojects.com/en/2.x/models/
also i recomment this flask mega tutorial from Miguel Grinberg: https://blog.miguelgrinberg.com/post/the-flask-mega-tutorial-part-i-hello-world
Thanks for the advice , I finally found out what was wrong , the "tip_to_update.Tips = request.form['Tips']" line in the update route should be "tip_to_update.Tips = form.Tips.data" instead , as I used the Flask Form method of collecting data in my register route, it wasn't accepting the request.form method. I'm still unable to show the data entered in the placeholder when a user wants to update a Tip, it opens the update page with a empty placeholder field to update , but I'd like the text from the entered tip to show , so the user can make a few alterations instead of typing out the whole tip again.
I have a custom User model to manage some profiles user: is_student, is_professor and is_executive
In this model, in addition, I have the get_student_profile(),get_professor_profile() and get_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_student, is_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 username field 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 (StudentProfile, ProfessorProfile, ExecutiveProfile):
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 (StudentProfileForm, ProfessorProfileForm, ExecutiveProfileForm) according to the profile to user (is_student, is_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_student, is_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_executive profile. Does not save data in is_professor profile forms fields
User with is_student, is_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.
I took the liberty of cleaning some stuff up for you. Let's review each piece.
models.py
There's no need to probe the model with hasattr(). We can rather use the fact that the OneToOneField between a User and a Profile will place a reference on both sides of the relation. This means you can simply override your save() method as follows:
Note: You may rather want to create the Profiles using Signals instead.
from django.conf import settings
from django.contrib.auth.base_user import AbstractBaseUser
from django.contrib.auth.models import PermissionsMixin
from django.db import models
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, help_text="User is student")
is_professor = models.BooleanField(default=False, help_text="User is professor")
is_executive = models.BooleanField(default=False, help_text="User is executive")
USERNAME_FIELD = 'email'
def save(self, *args, **kwargs):
super(User, self).save(*args, **kwargs)
if self.is_student and getattr(self, 'studentprofile', None) is None:
StudentProfile.objects.create(
user=self,
slug=self.username
)
if self.is_professor and getattr(self, 'professorprofile', None) is None:
ProfessorProfile.objects.create(
user=self,
slug=self.username
)
if self.is_executive and getattr(self, 'executiveprofile', None) is None:
ExecutiveProfile.objects.create(
user=self,
slug=self.username
)
views.py
Again, let's just use the fact that the OneToOneField on a user will contain a reference to the Profile:
#login_required
def update_view(request):
user = request.user
# Populate Forms and Instances (if applicable)
form_profiles = []
if user.is_student:
form_profiles.append({'form': StudentProfileForm, 'instance': user.studentprofile})
if user.is_professor:
form_profiles.append({'form': ProfessorProfileForm, 'instance': user.professorprofile})
if user.is_executive:
form_profiles.append({'form': ExecutiveProfileForm, 'instance': user.executiveprofile})
if request.method == 'POST':
forms = [x['form'](data=request.POST, instance=x['instance']) for x in form_profiles]
if all([form.is_valid() for form in forms]):
for form in forms:
form.save()
return redirect('dashboard')
else:
forms = [x['form'](instance=x['instance']) for x in form_profiles]
return render(request, 'accounts/profile_form.html', {'forms': forms})
forms.py
Your forms may look something like this:
class StudentProfileForm(forms.ModelForm):
title = "Student Form"
class Meta:
model = StudentProfile
fields = (
'origin_education_school',
'current_education_school',
'extra_occupation',
)
profile_form.html
<form method="post">
{% csrf_token %}
{% for form in forms %}
<h1>{{ form.title }}</h1>
{{ form }}
{% endfor %}
<button type="submit">Submit</button>
</form>
I double-checked, and forms are saved correctly.
P.S. If you would like to use a Class-Based View, you can follow the classes defined by this Gist: https://gist.github.com/michelts/1029336