Django 1.5. Users attributes in comments framework - django

I use MyUser model in Django 1.5 (e-mail as login):
class MyUserManager(BaseUserManager):
def create_user(self, email, password=None):
"""
Creates and saves a User with the given email, date of
birth and password.
"""
if not email:
raise ValueError('Users must have an email address')
user = self.model(
email=MyUserManager.normalize_email(email),
# date_of_birth=date_of_birth,
)
user.set_password(password)
user.save(using=self._db)
return user
def create_superuser(self, email, password):
"""
Creates and saves a superuser with the given email, date of
birth and password.
"""
user = self.create_user(email,
password=password,
#date_of_birth=date_of_birth
)
user.is_admin = True
user.save(using=self._db)
return user
class MyUser(AbstractBaseUser):
email = models.EmailField(
verbose_name='email address',
max_length=255,
unique=True,
db_index=True,
)
last_name=models.CharField(max_length=30)
first_name=models.CharField(max_length=30)
second_name=models.CharField(max_length=30, blank=True)
about=models.TextField(blank=True)
is_active = models.BooleanField(default=True)
is_admin = models.BooleanField(default=False)
objects = MyUserManager()
USERNAME_FIELD = 'email'
REQUIRED_FIELDS = ['last_name','first_name','second_name',]
def get_full_name(self):
# The user is identified by their email address
return self.email
def get_short_name(self):
# The user is identified by their email address
return self.email
def __unicode__(self):
return self.email
def has_perm(self, perm, obj=None):
"Does the user have a specific permission?"
# Simplest possible answer: Yes, always
return True
def has_module_perms(self, app_label):
"Does the user have permissions to view the app `app_label`?"
# Simplest possible answer: Yes, always
return True
#property
def is_staff(self):
"Is the user a member of staff?"
# Simplest possible answer: All admins are staff
return self.is_admin
settings.py:
AUTH_USER_MODEL = 'app.MyUser'
I activated django comments framework:
settings.py:
'django.contrib.comments',
urls:
(r'^comments/', include('django.contrib.comments.urls')),
template (only authorized user can add a comment):
<h2>Add a comment:</h2> {% get_comment_form for post as form %}
<form action="{% comment_form_target %}" method="post" > {% csrf_token %}
{% if next %}
<div><input type="hidden" name="next" value="{{ next }}" /></div>
{% endif %}
{{form.content_type}}{{form.object_pk}}{{form.timestamp}}{{form.security_hash}}
Comment:<br />
{{form.comment}}
<input type="hidden" name="next" value="{{ request.get_full_path }}" />
<input type="submit" name="submit" class="submit-post" value="Post" />
<input type="submit" name="preview" class="submit-preview" value="Preview" />
</form>
{% get_comment_count for post as comment_count %}
<h2>Comments: [{{ comment_count }}]</h2>
{% get_comment_list for post as comment_list %}
{% for comment in comment_list|dictsortreversed:"submit_date" %}
<dl id="comments">
{{ comment.email }} {{ comment.submit_date|date:"d.m.Y G:i" }}
<dd>
{{ comment.comment|striptags|urlizetrunc:20|linebreaksbr }}
</dd>
</dl>
{% endfor %}
How can I get user's model fields 'first_name' and others? comment.email and comment.name gives me 'e-mail' field, comment.first_name gives me nothing. Thx!

According to built-in comment model documentation, you could access a user posted comment via {{ comment.user }} in your template. Consequently, you could access MyUser model fields like this {{ comment.user.email }} or {{ comment.user.first_name }}, etc.

Related

Django Edit Profile View not saving new email value

I am (attempting to) implement the ability for a user to edit and update their email address on their profile page. I am getting no errors when doing this end to end but the new email is not being saved to the DB.
Everything seems to be working, even the redirect to the profile page in the edit_profile function, but the save() doesn't seem to be working, the users email doesn't update and when I am redirected back to the profile page, the email is still the current value.
Thanks!
Model:
class CustomUser(AbstractUser):
email = models.EmailField(_('email address'), unique=True)
is_pro = models.BooleanField(default=False)
is_golfer = models.BooleanField(default=False)
def __str__(self):
return self.email
Form
class EditProfileForm(forms.Form):
email = forms.EmailField(
label='', widget=forms.TextInput(attrs={'class': 'form-field'}))
View
#login_required
def edit_profile(request):
if request.method == "POST":
form = EditProfileForm(request.POST)
if form.is_valid():
email = form.cleaned_data["email"]
user = CustomUser.objects.get(id=request.user.id)
user.save()
return redirect("typeA", username=user.username)
else:
form = EditProfileForm()
return render(request, "registration/edit_profile.html", {'form': form})
URLS
urlpatterns = [
path('type_a_signup/', ASignUpView.as_view(), name='a_signup'),
path('type_b_signup/', BSignUpView.as_view(), name='b_signup'),
path('login/', LoginView.as_view(), name='login'),
path('password_reset', PasswordResetView.as_view(), name='password_reset'),
path('typea/<username>/', typeA, name='typeA'),
path('typeb/<username>/', typeB, name='typeB'),
path('login_success/', login_success, name='login_success'),
path('edit_profile/', edit_profile, name='edit_profile'),
]
Template
<div class="container">
<div class="form-container">
<h2>Edit profile</h2>
<form method="post" enctype="multipart/form-data">
{% csrf_token %}
<div>
{{ form.email.label_tag }}
<input type="text" class="form-control {% if form.email.errors %}is-invalid{% endif %}" id="id_email"
name="email" value='{{ form.email.value|default:user.email }}'>
{% if form.email.errors %}
<div>{{ form.email.errors }}</div>
{% endif %}
</div>
<button type="submit">Submit</button>
</form>
<br>
</div>
You never set the email field of the object. You should set this with:
#login_required
def edit_profile(request):
if request.method == "POST":
form = EditProfileForm(request.POST)
if form.is_valid():
email = form.cleaned_data["email"]
user = request.user
user.email = email # 🖘 set the email field
user.save()
return redirect("typeA", username=user.username)
else:
form = EditProfileForm()
return render(request, "registration/edit_profile.html", {'form': form})
You should only redirect in case the form is successful. If it is not, Django will rerender the form with the errors.

Custom registration form. Confirm password

I used custom form for register users. I want do validation for confirm password.
forms.py:
class RegistrationForm(UserCreationForm):
'''Register for new users'''
email = forms.EmailField(required=True)
first_name = forms.CharField(required=True)
last_name = forms.CharField(required=True)
class Meta:
model = get_user_model()
fields = {'username', 'password1', 'password2', 'email', 'first_name', 'last_name'}
def save(self, commit=True):
user = super(RegistrationForm, self).save(commit=False)
user.email = self.cleaned_data['email']
user.first_name = self.cleaned_data['first_name']
user.last_name = self.cleaned_data['last_name']
if commit:
user.save()
return user
template:
<div class="input-group register">
{{ form.password.errors }}
<label for="id_password1">Password: </label>
{{ form.password1 }}
</div>
<div class="input-group register">
{{ form.password.errors }}
<label for="id_password2">Confirm password: </label>
{{ form.password2 }}
</div>
views.py
def registration_view(request):
context = {}
context.update(csrf(request))
context['form'] = RegistrationForm()
if request.method == 'POST':
form = RegistrationForm(request.POST)
if form.is_valid():
form.save()
newuser = auth.authenticate(
username=form.cleaned_data['username'],
password=form.cleaned_data['password2']
)
auth.login(request, newuser)
return redirect('home')
else:
context['form'] = form
return render(request, '/registration.html', context)
How can I add validation for password(also confirm password)?
You inherit from UserCreationForm [GitHub]. This form already does that for you.
Indeed: the clean_password2 will validate that the two passwords are the same:
def clean_password2(self):
password1 = self.cleaned_data.get("password1")
password2 = self.cleaned_data.get("password2")
if password1 and password2 and password1 != password2:
raise forms.ValidationError(
self.error_messages['password_mismatch'],
code='password_mismatch',
)
return password2
The _post_clean function will validate that the password is a valid password:
def _post_clean(self):
super()._post_clean()
# Validate the password after self.instance is updated with form data
# by super().
password = self.cleaned_data.get('password2')
if password:
try:
password_validation.validate_password(password, self.instance)
except forms.ValidationError as error:
self.add_error('password2', error)
Finally in the save() it will use .set_password() to set the password. This is necessary, since Django's User model will, like any good user model, hash the password.
def save(self, commit=True):
user = super().save(commit=False)
user.set_password(self.cleaned_data["password1"])
if commit:
user.save()
return user
You thus should not interfere with these. You here only want to add first_name and last_name. So you can add that logic with:
class RegistrationForm(UserCreationForm):
'''Register for new users'''
email = forms.EmailField(required=True)
first_name = forms.CharField(required=True)
last_name = forms.CharField(required=True)
class Meta:
model = get_user_model()
fields = ['username', 'email', 'first_name', 'last_name']
That's all, since the ModelForm will take care of that.
Note that authenticate in your view is probably not necessary, since if you construct a user, it should authenticate. You can just login here:
def registration_view(request):
context = {}
context.update(csrf(request))
if request.method == 'POST':
form = RegistrationForm(request.POST)
if form.is_valid():
newuser = form.save()
auth.login(request, newuser)
return redirect('home')
else:
form = RegistrationForm()
context['form'] = form
return render(request, '/registration.html', context)
Try to use this in your register template
<form method="post" id="register-account-form">
{% csrf_token %}
{% for field in form %}
{% if field.help_text %}
<div class="notification error closeable">
<small style="color: grey">{{ field.help_text }}</small>
<a class="close" href="#"></a>
</div>
{% endif %}
{% for error in field.errors %}
<div class="notification error closeable">
<p style="color: red">{{ error }}</p>
<a class="close" href="#"></a>
</div>
{% endfor %}
{% endfor %}
<div class="input-with-icon-left">
<i class="icon-feather-user"></i>
{{ form.username }}
</div>
I find mistake
<div class="input-group register">
{{ form.password1.errors }}
<label for="id_password1">Пароль: </label>
{{ form.password1 }}
</div>
<div class="input-group register">
{{ form.password2.errors }}
<label for="id_password2">Подтвердите пароль: </label>
{{ form.password2 }}
</div>

help_text for username and email fields always output in browser

I have this model:
class User(AbstractUser):
REQUIRED_FIELDS = []
USERNAME_FIELD = 'email'
email = models.EmailField(
_('email address'),
max_length=150,
unique=True,
help_text=_('Required. 150 characters of fewer. Must be a valid email address.'),
error_messages={
'unique':_("A user with that email address already exists."),
},
)
this form class:
class UserForm(forms.ModelForm):
password = forms.CharField(widget=forms.PasswordInput)
class Meta:
model = User
fields = ['username','email','password']
this view class:
class UserFormView(View):
form_class = UserForm
template_name = 'workoutcal/register.html'
def get(self, request):
print("Hi again")
form = self.form_class(None)
return render(request, self.template_name, {'form':form})
def post(self, request):
form = self.form_class(request.POST)
if form.is_valid():
user = form.save(commit=False)
username = form.cleaned_data['username']
password = form.cleaned_data['password']
user.set_password(password)
user.save()
user = authenticate(username=username, password=password)
if user is not None:
if user.is_active:
login(request, user)
return redirect('workoutcal:calendar')
return render(request, self.template_name, {'form': form})
and this url:
url(r'^register/$', views.UserFormView.as_view(), name='register')
So when I go to /workoutcal/register, I see this:
The "help text" is always shown in the browser. Is this default Django behaviour, or is it due to some error I have made?
Also, how do I make the text only show up if the user has entered bad data into the respective fields?
Yes if you are using {{ form }} in your template
It will always show help_text, label, errors and widget automatically
If you don't want that you need to render form manually by looping over fields
<form method="post" novalidate>
{% csrf_token %}
{{ form.non_field_errors }}
{% for hidden_field in form.hidden_fields %}
{{ hidden_field.errors }}
{{ hidden_field }}
{% endfor %}
{% for field in form.visible_fields %}
<div class="fieldWrapper">
{{ field.errors }}
{{ field.label_tag }} {{ field }}
{{ field.help_text }} <!-- remove this line if you don't want to show it in your html.-->
</div>
{% endfor %}
<button type="submit">Submit</button>
</form>
For more read docs: https://docs.djangoproject.com/en/2.0/topics/forms/

Django log user in using class based view

I am trying to log a user in, however, my view does not seem to work. The page is rendered and the form is displayed and everything. But when I enter a valid user name and password it just refreshes the page instead of going to success_url. I think it is the way I am implementing my view method. I do not think login(request, user_obj) is being accessed, and if so, so is request.user.is_authenticated().
I also include my login form using
{% if user.is_authenticated %}
{% include 'navbar_in.html' %}
{% else %}
{% include 'navbar_out.html' %}
{% endif %}
It only uses navbar_out.htmlso that is how I know my code is not accessing login(request, user_obj).
User model:
# Create your models here.
class Usermie(models.Model):
# associate fields with django built in user objects
# this provides the authentication that we would need from the django built in utilities
usermie_object = models.OneToOneField(User)
# form fields
id = models.AutoField(primary_key=True)
username = models.CharField(max_length=30, unique=True, blank=False)
email = models.EmailField(max_length=30, unique=True, blank=False, null=False)
first_name = models.CharField(max_length=30, blank=False)
last_name = models.CharField(max_length=30, blank=False)
birthday = models.DateField(blank=False)
password = models.CharField(max_length=50, null=False)
sex = models.CharField(max_length=1, blank=False)
location = models.CharField(max_length=100, null=True)
city = models.CharField(max_length=40, null=True)
province = models.CharField(max_length=40, null=True)
country = models.CharField(max_length=40, null=True)
activated = models.IntegerField() # will be 1 if account is activated, 0 otherwise.
date_created = models.DateTimeField(default=timezone.now) # the time the account is created
date_activated = models.DateTimeField(null=True) # when the account is activated via email
def __str__(self):
return self.username
# create a user object to attach to our forms (SignUp)object
def create_usermie_user_callback(sender, instance, **kwargs):
usermie, new = Usermie.objects.get_or_create(usermie_object=instance)
View:
from .models import Usermie
from django.shortcuts import render
from django.views.generic import View
from .forms import SignUpForm, LoginForm
from django.contrib.auth.models import User
from django.http import HttpResponseRedirect
from django.views.generic.base import TemplateView
from django.contrib.auth import authenticate, login, logout
class UserLoginRegistration(View):
form_class = LoginForm
# Use initial to declare the initial value of form fields at runtime.
# For example, you might want to fill in a username field with
# the username of the current session.
initial = {'key': 'value'}
template_name = 'usermie/usertest.html' # template form will be rendered on
success_url = '/usermie/home/' # template for successfully submitted form
def get(self, request, *args, **kwargs):
form_login = self.form_class(initial=self.initial)
return render(request, self.template_name, {'form_login': form_login})
# method for posting form
def post(self, request, *args, **kwargs):
# Accessing form with post data
form_login = self.form_class(request.POST)
# Checking if user is logged in
if request.user.is_authenticated():
# Making sure user does not log in twice,
# just send user to profile.html if already logged in
return HttpResponseRedirect(self.success_url)
# Checking if the form is valid
if form_login.is_valid():
email = form_login.cleaned_data['email']
password = form_login.cleaned_data['password']
# NB! On Django docs Two methods to authenticate user and log them in
# 1 call authenticate
# 2 call login
# Return a user_obj object if the username and password are valid
# otherwise it will return null, the null variable is called None in python
user_obj = authenticate(email=email, password=password)
if user_obj is not None:
if user_obj.is_active:
login(request, user_obj)
return HttpResponseRedirect(self.success_url)
# If authentication failed
else:
return HttpResponseRedirect(self.template_name)
# If form is not being posted, render form to template
else:
form_login = self.form_class(initial=self.initial)
context = {'form_login': form_login}
return render(request, self.template_name, context)
And this is my mark up
<form class="navbar-form navbar-form-out" action="" method="post">
{% csrf_token %}
{% load widget_tweaks %}
<div class="form-group">
<label class="sr-only" for="{{ form_login.email.auto_id }}">{{ form_login.email.label }}</label>
{% render_field form_login.email class="form-control" placeholder=form_login.email.label %}
</div>
<div class="form-group">
<label class="sr-only" for="{{ form_login.auto_id }}">{{ form_login.password.label }}</label>
{% render_field form_login.password class="form-control" placeholder=form_login.password.label %}
{% for hidden in form_login.hidden_fields %}
{{ hidden }}
{% endfor %}
</div>
<div class="checkbox">
<label>
<input type="checkbox"> Remember me
</label>
</div>
<button type="submit" name="" value="form_login" class="btn btn-default">Sign in</button>
</form>
It might be that your user is not active and you don't handle that case. Try something like:
if user_obj.is_active:
login(request, user_obj)
return HttpResponseRedirect(self.success_url)
else:
return HttpResponse("Your account is inactive.")

MyUser login in Django 1.5. Again

I try to login users from MyUser model in django 1.5. I use e-mail as login, see model:
class MyUser(AbstractBaseUser):
email = models.EmailField(
verbose_name='email address',
max_length=255,
unique=True,
db_index=True,
)
last_name=models.CharField(max_length=30)
first_name=models.CharField(max_length=30)
second_name=models.CharField(max_length=30, blank=True)
post=models.CharField(max_length=30, blank=True)
objects = MyUserManager()
USERNAME_FIELD = 'email'
REQUIRED_FIELDS = ['last_name','first_name','second_name','post',]
def get_full_name(self):
return self.email
def get_short_name(self):
return self.email
def __unicode__(self):
return self.email
def has_perm(self, perm, obj=None):
return True
def has_module_perms(self, app_label):
return True
#property
def is_staff(self):
return self.is_admin
And I added LoginForm:
class LoginForm(forms.Form):
username = forms.CharField(max_length=100)
password =forms.CharField(widget=forms.PasswordInput(render_value=False),max_length=100)
view:
def login_view(request):
if request.method == 'POST':
username = request.POST['email']
password = request.POST['password']
user = authenticate(username=username, password=password)
if user is not None and user.is_active:
login(request, user)
return HttpResponseRedirect("/home.html")# Redirect to a success page.
return HttpResponseRedirect("/account/invalid/")# Return a 'disabled account' error message
form=LoginForm()
return render(request, 'enter.html', {'login_form': LoginForm})
template:
{% if form.errors %}
<p>Something is wrong</p>
{% endif %}
<form action="" method="post">
{% csrf_token %}
<label for="email">Login:</label>
<input type="text" name="email" value="" id="email"/>
<label for="password">Password:</label>
<input type="password" name="password" value="" id="username">
<input type="submit" value="login" />
<input type="hidden" name="next" value="{{next|escape}}" />
</form>
urls:
(r'^login/$', login_view),
Problem: It works for users from default User model (username, password), but this form "doesn't know" users from MyUser model (email, password), it redirect them to /account/invalid page.
What am I doing wrong?
Thx!
You need to indicate your custom user model in settings:
AUTH_USER_MODEL = 'myapp.MyUser'
Also, you have to provide custom UserManager, from doc:
You should also define a custom manager for your User model. If your
User model defines username and email fields the same as Django’s
default User, you can just install Django’s UserManager; however, if
your User model defines different fields, you will need to define a
custom manager that extends BaseUserManager providing two additional
methods: