文章来源:http://www.cnblogs.com/BeginMan/p/3801723.html
1.邮箱注册
这里需要扩展User,两种解决办法,1,注册时将email字段内容赋给username,这种瞒天过海型的,另一种就是扩展user,这里介绍django1.5的扩展方法。
1.setting配置
AUTH_USER_MODEL = 'manager.MyUser' # 扩展表的位置,appname.Model, MyUser是manager app下models中的用户类
AUTHENTICATION_BACKENDS = ('django.contrib.auth.backends.ModelBackend', 'manager.models.CustomAuth') # 后端认证
2.model
这里包含了扩展的方法和字段,贴代码如下,不明白可以看官网详解。
#coding=utf-8
from django.conf import settings
from django.db import models
from django.contrib.auth.models import BaseUserManager, AbstractBaseUser
class UserManager(BaseUserManager):
"""通过邮箱,密码创建用户"""
def create_user(self, email,username, password=None,type=None,**kwargs):
if not email:
raise ValueError(u'用户必须要有邮箱')
user = self.model(
email=UserManager.normalize_email(email),
username=username,
type=type if type else 0
)
user.set_password(password)
if kwargs:
if kwargs.get('sex', None): user.sex = kwargs['sex']
if kwargs.get('is_active', None): user.is_active=kwargs['is_active']
if kwargs.get('uid', None): user.uid=kwargs['uid']
if kwargs.get('access_token', None): user.access_token=kwargs['access_token']
if kwargs.get('url', None): user.url=kwargs['url']
if kwargs.get('desc', None): user.desc=kwargs['desc']
if kwargs.get('avatar', None): user.avatar=kwargs['avatar']
user.save(using=self._db)
return user
def create_superuser(self, email, username, password):
user = self.create_user(email,
password=password,
username=username,
)
user.is_admin = True
user.save(using=self._db)
return user
class MyUser(AbstractBaseUser):
"""扩展User"""
email = models.EmailField(verbose_name='Email', max_length=255, unique=True,db_index=True)
username = models.CharField(max_length=50, unique=True, db_index=True)
is_active = models.BooleanField(default=True)
is_admin = models.BooleanField(default=False)
type = models.IntegerField(default=0) # 类型,0本站,1微博登录
sex = models.IntegerField(default=1) # sex
uid = models.CharField(max_length=50, null=True) # weibo uid
access_token = models.CharField(max_length=100, null=True) # weibo access_token
url = models.URLField(null=True) # 个人站点
desc = models.CharField(max_length=2000, null=True) # 个人信息简介
avatar = models.CharField(max_length=500, null=True) # 头像
objects = UserManager()
USERNAME_FIELD = 'email'
REQUIRED_FIELDS = ['username']
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
class Meta:
db_table = 'user'
class CustomAuth(object):
"""自定义用户验证"""
def authenticate(self, email=None, password=None):
try:
user = MyUser.objects.get(email=email)
if user.check_password(password):
return user
except MyUser.DoesNotExist:
return None
def get_user(self, user_id):
try:
user = MyUser.objects.get(pk=user_id)
if user.is_active:
return user
return None
except MyUser.DoesNotExist:
return None
这样就可以使用扩展字段了。
2.注册/登录/更改密码表单
这里不罗嗦了,看代码就行了,总贴代码唯恐管理员移除了我的博客,吐槽下,博客园后台管理编辑文章markdown方式的超级烂。
class LoginForm(forms.Form):
"""
===============================================================================
function: 表单登录类
developer: BeginMan
add-time 2014/6/3
===============================================================================
"""
email = forms.EmailField(label=u'邮箱',max_length=100,widget=forms.TextInput(
attrs={'class': 'form-control', 'placeholder': u'邮箱', 'required': '', 'autofocus': ''}
),
)
pwd = forms.CharField(label=u'密码',widget=forms.PasswordInput(
attrs={'class': 'form-control', 'placeholder': u'密码', 'required': ''}
)
)
auto_login = forms.BooleanField(label=u'记住密码',required=False,
widget=forms.CheckboxInput(attrs={'value': 1}),
)
def __init__(self, request=None, *args, **kwargs):
self.request = request
self.user_cache = None
self.auth_login = None
super(LoginForm, self).__init__(*args, **kwargs)
def clean(self):
email = self.cleaned_data.get('email')
password = self.cleaned_data.get('pwd')
auth_login = self.cleaned_data.get('auth_login', None)
if email and password:
if not MyUser.objects.filter(email=email).exists():
raise forms.ValidationError(u'该账号不存在')
self.user_cache = authenticate(email=email, password=password)
if self.user_cache is None:
raise forms.ValidationError(u'邮箱或密码错误!')
elif not self.user_cache.is_active:
raise forms.ValidationError(u'该帐号已被禁用!')
if auth_login: # 如果用户勾选了自动登录
self.auth_login = True
return self.cleaned_data
def get_user_id(self):
"""获取用户id"""
if self.user_cache:
return self.user_cache.id
return None
def get_user(self):
"""获取用户实例"""
return self.user_cache
def get_auto_login(self):
"""是否勾选了自动登录"""
return self.auth_login
def get_user_is_first(self):
"""获取用户是否是第一次登录"""
is_first = False
if self.user_cache and self.user_cache.type == -1:
is_first = True
self.user_cache.type == 0
self.user_cache.save()
return is_first
class RegisterForm(forms.Form):
"""
===============================================================================
function: 表单注册类
developer: BeginMan
add-time 2014/6/3
===============================================================================
"""
email = forms.EmailField(label=u'Email', max_length=100, widget=forms.TextInput(
attrs={'class': 'form-control', 'placeholder': u'Email', 'required': '', 'autofocus': ''}
),
)
pwd = forms.CharField(label=u'密码',widget=forms.PasswordInput(
attrs={'class': 'form-control', 'placeholder': u'密码', 'required': ''}
)
)
pwd2 = forms.CharField(label=u'密码(重复)',widget=forms.PasswordInput(
attrs={'class': 'form-control', 'placeholder': u'重复密码', 'required': ''}
)
)
def __init__(self, request=None, *args, **kwargs):
self.request = request
self.user = None
super(RegisterForm, self).__init__(*args, **kwargs)
def clean(self):
data = self.cleaned_data
email = data.get('email')
pwd = data.get('pwd')
pwd2 = data.get('pwd2')
if MyUser.objects.filter(email=email).exists():
raise forms.ValidationError(u'该邮箱已被注册')
if pwd != pwd2:
raise forms.ValidationError(u'两次输入密码不一致')
if pwd2 == pwd and len(pwd) < 6:
raise forms.ValidationError(u'密码不能小于6位')
# 用户注册
# type = -1表示首次
avatar = random.choice(range(35))
avatar = '/site_media/avatar/%s.jpg' % avatar
# 生成用户并验证
username = email.split('@')
if len(username) !=2 :
raise forms.ValidationError(u'邮箱格式不对')
else:
username = ValidUs(username[0])
self.user = MyUser.objects.create_user(email=email, username=username, password=pwd, type=-1, avatar=avatar).id
return data
def get_user(self):
"""获取用户实例"""
return self.user
class PasswordForm(forms.Form):
"""
===============================================================================
function: 用户修改密码
developer: BeginMan
add-time 2014/6/3
===============================================================================
"""
oldpwd = forms.CharField(label=u'原始密码', widget=forms.PasswordInput(
attrs={'class': 'form-control', 'placeholder': u'原始密码', 'required': ''})
)
password1 = forms.CharField(label=u'新密码', widget=forms.PasswordInput(
attrs={'class': 'form-control', 'placeholder': u'密码长度在5-12位', 'required': ''})
)
password2 = forms.CharField(label=u'在输入一次', widget=forms.PasswordInput(
attrs={'class': 'form-control', 'placeholder': u'在输入一次', 'required': ''})
)
def __init__(self, user=None, *args, **kwargs):
self.user = user
self.newpwd = None
super(PasswordForm, self).__init__(*args, **kwargs)
def clean(self):
cleaned_data = super(PasswordForm, self).clean()
oldpwd = cleaned_data.get("oldpwd")
password1 = cleaned_data.get("password1")
password2 = cleaned_data.get("password2")
if not self.user.check_password(oldpwd):
msg = u"原密码错误。"
self._errors["oldpwd"] = self.error_class([msg])
# raise forms.ValidationError(u'原密码错误')
if password1 and password2:
if password1 != password2:
msg = u"两个密码字段不一致。"
self._errors["password2"] = self.error_class([msg])
if not 4 < len(password1) < 13:
msg = u"密码要在5-12位之间。"
self._errors["password1"] = self.error_class([msg])
return cleaned_data
class AvatarForm(forms.Form):
"""
===============================================================================
function: 用户修改头像
developer: BeginMan
add-time 2014/6/3
===============================================================================
"""
avatar = forms.ImageField(label=u'图片上传', widget=forms.FileInput(
attrs={'class': 'form-control', 'placeholder': u'图片上传', 'required': ''})
)
def clean(self):
cleaned_data = super(AvatarForm, self).clean()
image = cleaned_data.get("avatar", None)
if image:
if image.content_type not in ['image/jpeg', 'image/png']:
raise forms.ValidationError(u'你上传的是图片吗?')
else:
img = Image.open(image)
w, h = img.size
max_width = max_height = 1000
if w >= max_width or h >= max_height:
raise forms.ValidationError(u'上传的图片要尺寸要小于或等于%s宽,%s高' % (max_width, max_height))
if img.format.lower() not in ['jpeg', 'pjpeg', 'png', 'jpg']:
raise forms.ValidationError(u'暂时只接纳JPEG or PNG.')
#validate file size
if len(image) > (1 * 1024 * 1024):
raise forms.ValidationError('Image file too large ( maximum 1mb )')
else:
raise forms.ValidationError(u'额,图片呢?')
return cleaned_data
3.微博登录
如果你的网站想接入微博登录,那么先看看新浪开发者平台上的python SDK,API等,这里提供自己的处理方式,还是贴代码。。
首先配置的东西如key等,建议放在settings中,如下:
# 微博登陆
URL = 'http://codetheme.sinaapp.com'
APP_KEY = '你的'
APP_SERCET = '你的'
CALLBACK_URL = URL+'/login/weibo_check/' # 回调地址
url路由就自己写吧,这里给出视图方法,
def weiboLogin(request):
"""微博登录"""
client = APIClient(app_key=settings.APP_KEY, app_secret=settings.APP_SERCET, redirect_uri=settings.CALLBACK_URL)
url = client.get_authorize_url()
return HttpResponseRedirect(url)
def weibo_check(request):
code = request.GET.get('code', None)
now = datetime.datetime.now()
if code:
client = APIClient(app_key=settings.APP_KEY, app_secret=settings.APP_SERCET, redirect_uri=settings.CALLBACK_URL)
r = client.request_access_token(code)
access_token = r.access_token # 返回的token,类似abc123xyz456
expires_in = r.expires_in # token过期的UNIX时间:http://zh.wikipedia.org/wiki/UNIX%E6%97%B6%E9%97%B4
uid = r.uid
# 在此可保存access token
client.set_access_token(access_token, expires_in)
request.session['access_token'] = access_token
request.session['expires_in'] = expires_in
request.session['uid'] = uid
user = SupserWeibo(access_token=access_token, uid=uid, request=request) # 实例化超级微博类
# 更新数据库
if MyUser.objects.filter(uid=uid).exists():
MyUser.objects.filter(uid=uid).update(last_login=now)
user.Login() # 登陆
return HttpResponseRedirect('/')
else:
# 创建用户并登陆
u_id = user.createUser()
if u_id:
return HttpResponseRedirect('/manage/user/%s/' %u_id)
return HttpResponse('/404/')
这里自己写了个微博类,用于处理微博登录的基础数据,感兴趣的也可以看看,
#coding=utf-8
"""
==================================
function: 基于新浪微博API,对微博登陆进行扩展
addDate: 2014-06-04
author: BeginMan
==================================
"""
from django.conf import settings
import urllib
import urllib2
import simplejson as json
from manager.models import MyUser
from django.contrib.auth import authenticate, login, logout
from django.http import HttpResponseRedirect
import datetime
# 默认图片
DEFAULT_PIC = 'http://images.cnitblog.com/news/66372/201405/271116202595556.jpg'
# 用户信息
USER_INFO_URL = 'https://api.weibo.com/2/users/show.json'
# 发送微博
SEND_WEIBO_URL = 'https://api.weibo.com/2/statuses/upload_url_text.json'
user_agent = 'Mozilla/5.0 (Windows NT 6.1; rv:28.0) Gecko/20100101 Firefox/28.0'
headers = {'User-Agent': user_agent}
class SupserWeibo(object):
def __init__(self, access_token, uid, request=None, **kwargs):
self.access_token = access_token
self.uid = uid
self.request = request
self.user_cache = None
self.kwargs = kwargs
def createUser(self):
"""创建用户"""
userInfo = self.getUserInfo()
username=userInfo.get('screen_name')
if MyUser.objects.filter(username=username).exists():
username = username+'[weibo]'
u_id = 0
try:
new_user = MyUser.objects.create_user(
email=str(self.uid) + '@weibo.com',
username=username,
password=self.uid,
type=1,
sex=int(userInfo.get('sex', 1)),
uid=self.uid,
access_token=self.access_token,
url=userInfo.get('url', ''),
desc =userInfo.get('description', ''),
avatar=userInfo.get('avatar_large')
)
u_id = new_user.id
except:
pass
self.Login() # 登陆
return u_id
def getUserInfo(self):
"""获取微博用户信息"""
data = {'access_token': self.access_token, 'uid': self.uid}
params = urllib.urlencode(data)
values = urllib2.Request(USER_INFO_URL+'?%s' %params, headers=headers)
response = urllib2.urlopen(values)
result = json.loads(response.read())
if result.get('error_code', None):
# 写入日志
print '获取用户信息失败'
return False
return result
def SendWeibo(self):
"""用户发送微博"""
status = self.kwargs.get('status', None) # 微博内容
visible = self.kwargs.get('visible', 0) # 微博的可见性,0:所有人能看,1:仅自己可见,2:密友可见,3:指定分组可见,默认为0。
url = self.kwargs.get('url', DEFAULT_PIC) # 配图
result = {}
if status:
data = {'access_token': self.access_token, 'status': status, 'visible':visible, 'url':url}
params = urllib.urlencode(data)
values = urllib2.Request(USER_INFO_URL+'?%s' %params, headers=headers)
response = urllib2.urlopen(values)
result = json.loads(response.read())
if result.get('error_code', None):
# 写入日志
print '发送微博失败'
return False
return True
return result
def Login(self):
"""登陆"""
user_ = MyUser.objects.filter(uid=self.uid)[0]
user = authenticate(email=user_.email, password=self.uid)
login(self.request, user)