Commit 5988f9bea49168f0c156859bf58d3f3bfacfe7bc

Authored by zhenchaozhu
1 parent bd3fab00d1
Exists in master and in 1 other branch de

remove breakpoint

1 ### Django forum 1 ### Django forum
2 2
3 ***
4
5 demo: <http://djangoforum.coding.io/>
6
7 Django forum是使用Django实现的轻型现代论坛程序,是fork自[F2E.im](https://github.com/PaulGuo/F2E.im)的Django版本.
8 相对于原版的主要区别在于使用Django admin实现了一个简单的后台管理.
9
10 Django forum有3个分支,master分支用于主机上部署,SAE分支是适配Sina App Engine的版本,api分支是一个试验性质的分支,详情见更新
11
12 #### 安装部署 3 #### 安装部署
13 4
14 主机版: 5 主机版:
15 6
16 依赖MySQL数据库,以及memcached 7 依赖MySQL数据库,以及memcached
17 8
18 1. 获取代码 9 1. 获取代码
19 2. 安装依赖 10 2. 安装依赖
20 3. 导入数据库文件 11 3. 导入数据库文件
21 4. 修改配置文件 12 4. 修改配置文件
22 5. 运行服务 13 5. 运行服务
23 14
24 ```shell 15 ```shell
25 shell> git clone git@github.com:zhu327/forum.git 16 shell> git clone git@github.com:zhu327/forum.git
26 17
27 shell> cd forum 18 shell> cd forum
28 shell> pip install -r requirements.txt 19 shell> pip install -r requirements.txt
29 20
30 shell> mysql -u YOURUSERNAME -p 21 shell> mysql -u YOURUSERNAME -p
31 22
32 mysql> create database forum; 23 mysql> create database forum;
33 mysql> exit 24 mysql> exit
34 25
35 shell> mysql -u YOURUSERNAME -p --database=forum < forum.sql 26 shell> mysql -u YOURUSERNAME -p --database=forum < forum.sql
36 ``` 27 ```
37 28
38 修改`xp/settings.py` 29 修改`xp/settings.py`
39 30
40 ```python 31 ```python
41 # 修改数据库配置 32 # 修改数据库配置
42 DATABASES = { 33 DATABASES = {
43 'default': { 34 'default': {
44 'ENGINE': 'django.db.backends.mysql', # Add 'postgresql_psycopg2', 'mysql', 'sqlite3' or 'oracle'. 35 'ENGINE': 'django.db.backends.mysql', # Add 'postgresql_psycopg2', 'mysql', 'sqlite3' or 'oracle'.
45 'NAME': 'forum', # Or path to database file if using sqlite3. 36 'NAME': 'forum', # Or path to database file if using sqlite3.
46 # The following settings are not used with sqlite3: 37 # The following settings are not used with sqlite3:
47 'USER': 'root', 38 'USER': 'root',
48 'PASSWORD': '', 39 'PASSWORD': '',
49 'HOST': '127.0.0.1', # Empty for localhost through domain sockets or '127.0.0.1' for localhost through TCP. 40 'HOST': '127.0.0.1', # Empty for localhost through domain sockets or '127.0.0.1' for localhost through TCP.
50 'PORT': '3306', # Set to empty string for default. 41 'PORT': '3306', # Set to empty string for default.
51 } 42 }
52 } 43 }
53 44
54 # 修改memcached配置,如果没有memcahed请删除这些与cache相关的内容 45 # 修改memcached配置,如果没有memcahed请删除这些与cache相关的内容
55 CACHES = { # memcached缓存设置 46 CACHES = { # memcached缓存设置
56 'default': { 47 'default': {
57 'BACKEND': 'django.core.cache.backends.memcached.MemcachedCache', 48 'BACKEND': 'django.core.cache.backends.memcached.MemcachedCache',
58 'LOCATION': '127.0.0.1:11211', 49 'LOCATION': '127.0.0.1:11211',
59 } 50 }
60 } 51 }
61 52
62 SESSION_ENGINE = 'django.contrib.sessions.backends.cache' # 使用memcached存储session 53 SESSION_ENGINE = 'django.contrib.sessions.backends.cache' # 使用memcached存储session
63 54
64 # 配置邮件发送 55 # 配置邮件发送
65 EMAIL_HOST = 'smtp.qq.com' 56 EMAIL_HOST = 'smtp.qq.com'
66 EMAIL_PORT = 25 57 EMAIL_PORT = 25
67 EMAIL_HOST_USER= '*********' 58 EMAIL_HOST_USER= '*********'
68 EMAIL_HOST_PASSWORD= '******' 59 EMAIL_HOST_PASSWORD= '******'
69 DEFAULT_FROM_EMAIL = '*********@qq.com' 60 DEFAULT_FROM_EMAIL = '*********@qq.com'
70 ``` 61 ```
71 62
72 运行服务 63 运行服务
73
74 ```shell 64 ```shell
75 python manage.py runserver 65 python manage.py runserver
76 ``` 66 ```
77 67
78 默认超级用户`admin@admin.com`,密码`123456`,后台`/manage/admin/` 68 默认超级用户`admin@admin.com`,密码`123456`,后台`/manage/admin/`
79 69
80 生产环境下推荐使用gunicorn.
forum/forms/user.py
1 # coding: utf-8 1 # coding: utf-8
2 2
3 from django import forms 3 from django import forms
4 from django.contrib.auth import authenticate 4 from django.contrib.auth import authenticate
5 from django.conf import settings 5 from django.conf import settings
6 from forum.models import ForumUser 6 from forum.models import ForumUser
7 7
8 8
9 error_messages = { 9 error_messages = {
10 'username': { 10 'username': {
11 'required': u'必须填写用户名', 11 'required': u'必须填写用户名',
12 'min_length': u'用户名长度过短(3-12个字符)', 12 'min_length': u'用户名长度过短(3-12个字符)',
13 'max_length': u'用户名长度过长(3-12个字符)', 13 'max_length': u'用户名长度过长(3-12个字符)',
14 'invalid': u'用户名格式错误(英文字母开头,数字,下划线构成)' 14 'invalid': u'用户名格式错误(英文字母开头,数字,下划线构成)'
15 }, 15 },
16 'email': { 16 'email': {
17 'required': u'必须填写E-mail', 17 'required': u'必须填写E-mail',
18 'min_length': u'Email长度有误', 18 'min_length': u'Email长度有误',
19 'max_length': u'Email长度有误', 19 'max_length': u'Email长度有误',
20 'invalid': u'Email地址无效' 20 'invalid': u'Email地址无效'
21 }, 21 },
22 'password': { 22 'password': {
23 'required': u'必须填写密码', 23 'required': u'必须填写密码',
24 'min_length': u'密码长度过短(6-64个字符)', 24 'min_length': u'密码长度过短(6-64个字符)',
25 'max_length': u'密码长度过长(6-64个字符)' 25 'max_length': u'密码长度过长(6-64个字符)'
26 }, 26 },
27 } 27 }
28 28
29 29
30 class SettingPasswordForm(forms.Form): 30 class SettingPasswordForm(forms.Form):
31 password_old = forms.CharField(min_length=6, max_length=64, 31 password_old = forms.CharField(min_length=6, max_length=64,
32 error_messages=error_messages.get('password')) 32 error_messages=error_messages.get('password'))
33 password = forms.CharField(min_length=6, max_length=64, 33 password = forms.CharField(min_length=6, max_length=64,
34 error_messages=error_messages.get('password')) 34 error_messages=error_messages.get('password'))
35 password_confirm = forms.CharField(required=False) 35 password_confirm = forms.CharField(required=False)
36 36
37 def __init__(self, request): 37 def __init__(self, request):
38 self.user = request.user 38 self.user = request.user
39 super(SettingPasswordForm, self).__init__(request.POST) 39 super(SettingPasswordForm, self).__init__(request.POST)
40 40
41 def clean(self): 41 def clean(self):
42 password_old = self.cleaned_data.get('password_old') 42 password_old = self.cleaned_data.get('password_old')
43 password = self.cleaned_data.get('password') 43 password = self.cleaned_data.get('password')
44 password_confirm = self.cleaned_data.get('password_confirm') 44 password_confirm = self.cleaned_data.get('password_confirm')
45 45
46 if not (password_old and self.user.check_password(password_old)): 46 if not (password_old and self.user.check_password(password_old)):
47 raise forms.ValidationError(u'当前输入旧密码有误') 47 raise forms.ValidationError(u'当前输入旧密码有误')
48 48
49 if password and password_confirm and password != password_confirm: 49 if password and password_confirm and password != password_confirm:
50 raise forms.ValidationError(u'两次输入新密码不一致') 50 raise forms.ValidationError(u'两次输入新密码不一致')
51 return self.cleaned_data 51 return self.cleaned_data
52 52
53 53
54 class ForgotPasswordForm(forms.Form): 54 class ForgotPasswordForm(forms.Form):
55 username = forms.RegexField(min_length=3, max_length=12, 55 username = forms.RegexField(min_length=3, max_length=12,
56 regex=r'^[a-zA-Z][a-zA-Z0-9_]*$', 56 regex=r'^[a-zA-Z][a-zA-Z0-9_]*$',
57 error_messages=error_messages.get('username')) 57 error_messages=error_messages.get('username'))
58 email = forms.EmailField(min_length=4, max_length=64, 58 email = forms.EmailField(min_length=4, max_length=64,
59 error_messages=error_messages.get('email')) 59 error_messages=error_messages.get('email'))
60 60
61 def __init__(self, *args, **kwargs): 61 def __init__(self, *args, **kwargs):
62 self.user_cache = None 62 self.user_cache = None
63 super(ForgotPasswordForm, self).__init__(*args, **kwargs) 63 super(ForgotPasswordForm, self).__init__(*args, **kwargs)
64 64
65 def clean(self): 65 def clean(self):
66 username = self.cleaned_data.get('username') 66 username = self.cleaned_data.get('username')
67 email = self.cleaned_data.get('email') 67 email = self.cleaned_data.get('email')
68 68
69 if username and email: 69 if username and email:
70 try: 70 try:
71 self.user_cache = ForumUser.objects.get(username=username, email=email) 71 self.user_cache = ForumUser.objects.get(username=username, email=email)
72 except ForumUser.DoesNotExist: 72 except ForumUser.DoesNotExist:
73 raise forms.ValidationError(u'所填用户名和邮箱有误') 73 raise forms.ValidationError(u'所填用户名和邮箱有误')
74 return self.cleaned_data 74 return self.cleaned_data
75 75
76 def get_user(self): 76 def get_user(self):
77 return self.user_cache 77 return self.user_cache
78 78
79 79
80 class LoginForm(forms.Form): 80 class LoginForm(forms.Form):
81 username = forms.CharField(min_length=3, max_length=12, 81 username = forms.CharField(min_length=3, max_length=12,
82 error_messages=error_messages.get('username')) 82 error_messages=error_messages.get('username'))
83 password = forms.CharField(min_length=6, max_length=64, 83 password = forms.CharField(min_length=6, max_length=64,
84 error_messages=error_messages.get('password')) 84 error_messages=error_messages.get('password'))
85 85
86 def __init__(self, *args, **kwargs): 86 def __init__(self, *args, **kwargs):
87 self.user_cache = None 87 self.user_cache = None
88 super(LoginForm, self).__init__(*args, **kwargs) 88 super(LoginForm, self).__init__(*args, **kwargs)
89 89
90 def clean(self): 90 def clean(self):
91 import pdb; pdb.set_trace()
92 username = self.cleaned_data.get('username') 91 username = self.cleaned_data.get('username')
93 password = self.cleaned_data.get('password') 92 password = self.cleaned_data.get('password')
94 93
95 if username and password: 94 if username and password:
96 self.user_cache = authenticate(username=username, password=password) 95 self.user_cache = authenticate(username=username, password=password)
97 if self.user_cache is None: 96 if self.user_cache is None:
98 raise forms.ValidationError(u'用户名或者密码不正确') 97 raise forms.ValidationError(u'用户名或者密码不正确')
99 elif not self.user_cache.is_active: 98 elif not self.user_cache.is_active:
100 raise forms.ValidationError(u'用户已被锁定,请联系管理员解锁') 99 raise forms.ValidationError(u'用户已被锁定,请联系管理员解锁')
101 return self.cleaned_data 100 return self.cleaned_data
102 101
103 def get_user(self): 102 def get_user(self):
104 return self.user_cache 103 return self.user_cache
105 104
106 105
107 class RegisterForm(forms.ModelForm): 106 class RegisterForm(forms.ModelForm):
108 username = forms.RegexField(min_length=3, max_length=12, 107 username = forms.RegexField(min_length=3, max_length=12,
109 regex=r'^[a-zA-Z][a-zA-Z0-9_]*$', 108 regex=r'^[a-zA-Z][a-zA-Z0-9_]*$',
110 error_messages=error_messages.get('username')) 109 error_messages=error_messages.get('username'))
111 email = forms.EmailField(min_length=4, max_length=64, 110 email = forms.EmailField(min_length=4, max_length=64,
112 error_messages=error_messages.get('email')) 111 error_messages=error_messages.get('email'))
113 password = forms.CharField(min_length=6, max_length=64, 112 password = forms.CharField(min_length=6, max_length=64,
114 error_messages=error_messages.get('password')) 113 error_messages=error_messages.get('password'))
115 password_confirm = forms.CharField(required=False) 114 password_confirm = forms.CharField(required=False)
116 115
117 class Meta: 116 class Meta:
118 model = ForumUser 117 model = ForumUser
119 fields = ('username', 'email') 118 fields = ('username', 'email')
120 119
121 def clean_username(self): 120 def clean_username(self):
122 username = self.cleaned_data['username'] 121 username = self.cleaned_data['username']
123 try: 122 try:
124 ForumUser.objects.get(username=username) 123 ForumUser.objects.get(username=username)
125 raise forms.ValidationError(u'所填用户名已经被注册过') 124 raise forms.ValidationError(u'所填用户名已经被注册过')
126 except ForumUser.DoesNotExist: 125 except ForumUser.DoesNotExist:
127 if username in settings.RESERVED: 126 if username in settings.RESERVED:
128 raise forms.ValidationError(u'用户名被保留不可用') 127 raise forms.ValidationError(u'用户名被保留不可用')
129 return username 128 return username
130 129
131 def clean_email(self): 130 def clean_email(self):
132 email = self.cleaned_data['email'] 131 email = self.cleaned_data['email']
133 try: 132 try:
134 ForumUser.objects.get(email=email) 133 ForumUser.objects.get(email=email)
135 raise forms.ValidationError(u'所填邮箱已经被注册过') 134 raise forms.ValidationError(u'所填邮箱已经被注册过')
136 except ForumUser.DoesNotExist: 135 except ForumUser.DoesNotExist:
137 return email 136 return email
138 137
139 def clean_password_confirm(self): 138 def clean_password_confirm(self):
140 password1 = self.cleaned_data.get('password') 139 password1 = self.cleaned_data.get('password')
141 password2 = self.cleaned_data.get('password_confirm') 140 password2 = self.cleaned_data.get('password_confirm')
142 if password1 and password2 and password1 != password2: 141 if password1 and password2 and password1 != password2:
143 raise forms.ValidationError(u'两次输入密码不一致') 142 raise forms.ValidationError(u'两次输入密码不一致')
144 return password2 143 return password2
145 144
146 def save(self, commit=True): 145 def save(self, commit=True):
147 user = super(RegisterForm, self).save(commit=False) 146 user = super(RegisterForm, self).save(commit=False)
148 user.set_password(self.cleaned_data['password']) 147 user.set_password(self.cleaned_data['password'])
149 if commit: 148 if commit:
150 user.save() 149 user.save()
151 return user 150 return user
152 151
153 152
154 class SettingForm(forms.Form): 153 class SettingForm(forms.Form):
155 username = forms.CharField() # readonly 154 username = forms.CharField() # readonly
156 email = forms.EmailField() # readonly 155 email = forms.EmailField() # readonly
157 nickname = forms.CharField(min_length=3, max_length=12, required=False, 156 nickname = forms.CharField(min_length=3, max_length=12, required=False,
158 error_messages={ 157 error_messages={
159 'min_length': u'昵称长度过短(3-12个字符)', 158 'min_length': u'昵称长度过短(3-12个字符)',
160 'max_length': u'昵称长度过长(3-12个字符)', 159 'max_length': u'昵称长度过长(3-12个字符)',
161 }) 160 })
162 signature = forms.CharField(required=False) 161 signature = forms.CharField(required=False)
163 location = forms.CharField(required=False) 162 location = forms.CharField(required=False)
164 website = forms.URLField(required=False, 163 website = forms.URLField(required=False,
165 error_messages={ 164 error_messages={
166 'invalid': u'请填写合法的URL地址(如:http://f2e.im)', 165 'invalid': u'请填写合法的URL地址(如:http://f2e.im)',
167 }) 166 })
168 company = forms.CharField(required=False) 167 company = forms.CharField(required=False)
169 github = forms.CharField(required=False) 168 github = forms.CharField(required=False)
170 twitter = forms.CharField(required=False) 169 twitter = forms.CharField(required=False)
171 douban = forms.CharField(required=False) 170 douban = forms.CharField(required=False)
172 self_intro = forms.CharField(required=False) 171 self_intro = forms.CharField(required=False)
173 172
1 Django==1.5.2 1 Django==1.8.2
2 Markdown==2.5.2 2 Markdown==2.5.2
3 MySQL-python==1.2.3 3 MySQL-python==1.2.3
4 Pillow==2.7.0
5 Pygments==2.0.1
4 6