一、Django的优势
Python的WEB框架有Django、Tornado、Flask 等多种,Django相较与其他WEB框架其优势为:大而全,框架本身集成了ORM、模型绑定、模板引擎、缓存、Session等诸多功能
二、DJango项目的创建
1)命令行
django-admin startproject sitename # 建项目
python manage.py runserver 0.0.0.0 # 启动服务
python manage.py startapp appname # 创建app
python manage.py syncdb # 建表是的编码是utf8(后面的版本取消)
python manage.py makemigrations # 连接库
python manage.py migrate # 建表
python manage.py createsuperuser # 创建admin用户
2)pycharm
三、Django的目录结构
1)同项目名称一样的目录,是做全局变量的:setting(配置文件,路径配置等),urls(路由系统),wsgi(socket)
2)app文件:app,models,views,admin,tests
3)templates(存放html文件)
4)manage(进入Django命令行模式)
以下是自定义:log(存放日志),media(存放视频,照片),static(存放js,css,静态图片..)
四、连接数据库
注:新建的数据库要指定utf8格式,否则在建表时(有中文输入)会出现乱码
步骤:setting配置数据库,连接数据库,建表
1、setting配置DATABASES
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.mysql',
'NAME':'dbname',
'USER': 'root',
'PASSWORD': 'xxx',
'HOST': '',
'PORT': '',
}
}
定义
2、由于Django内部连接MySQL时使用的是MySQLdb模块,而python3中还无此模块,所以需要使用pymysql来代替
1 # 如下设置放置的与project同名的配置的 __init__.py文件中
2 import pymysql
3 pymysql.install_as_MySQLdb()
3、在setting配置模版文件路径(把html存放在templates)--默认已配置好
TEMPLATE_DIRS = (
os.path.join(BASE_DIR,'templates'),
)
4、在setting配置静态文件路径(把css,js存放在statics)
注:在生产环境下(DEBUG=False),该配置失效
STATICFILES_DIRS = (
os.path.join(BASE_DIR,'static'),
)
注:在html里应用静态文件,建议使用模板语言
1)在html开头添加
{% load staticfiles %}
2)应用静态文件
{% static 'css/reset.css' %}
5、当涉及到文件上传时,在setting配置
注:涉及到文件上传的upload
# 配置上传文件的路径
=========================================
MEDIA_URL = '/media/'
MEDIA_ROOT = os.path.join(BASE_DIR,"media")
=========================================
2)url配置
==================================================================
旧版本:
from django.views.static import serve # 前端显示出图片内容,旧版本
from TFF.settings import MEDIA_ROOT
# url(r'^madia/(?P<path>.*)$', serve,{"document_root":MEDIA_ROOT}), # 旧版本
==================================================================
# 新版本
from django.conf.urls.static import static
from TFF import settings
urlpatterns = [
]+static(settings.MEDIA_URL,document_root=settings.MEDIA_ROOT) # 在url配置的尾部加
=======================================以上是DJango项目的前期工作========================================================
一、数据库的设计(ORM):
思路:分层设计,如下例子
根据app设计(分层设计)
uers-用户管理
Course-课程管理
organization-机构和教师管理
以上的3个app在同一层
operation-用户操作管理 (最上层)
1)给每个app的model文件里,建表(关系对象映射):
一般用户表,都需要继承Django原本的auth表
1)可以继承默认生成的user表
from django.contrib.auth.models import AbstractUser
class Userprofile(AbstractUser):
nick_name = models.CharField(max_length=32,verbose_name=u"昵称",default=u"")
birthday = models.DataField(verbose_name=u"生日",null=True,blank=True)
gender = models.CharField(choices=(("male",u"男"),("female",u"女")),default=u"")
address = models.CharField(max_length=128,default=u"")
mobile = models.CharField(max_length=11,null=True,blank=True)
image = models.ImageField(upload_to="image/%Y/%m",default=u"image/default.png",max_length=128)
class Meta:
verbose_name = "用户信息"
verbose_name_plural = verbose_name
def __unicode__(self): # 定义返回utf8(中文)
return self.username
注:
a)在setting中增加字段
AUTH_USER_MODEL = "users.Userprofile" # users为app的名,Userprofile为数据表的名
b)下面为一些AbstractBaseUser的子类必须定义的关键的字段和方法: # 否则会报错:type object 'UserProfile' has no attribute 'USERNAME_FIELD'
USERNAME_FIELD
必须设置。 设置认证标识,设置成标识的字段 unique=True
class MyUser(AbstractBaseUser):
identifier = models.CharField(max_length=40, unique=True)
...
USERNAME_FIELD = 'identifier'
c)
用户重写: http://www.jianshu.com/p/b993f4feff83
User表
又如给Course建表:
1 class Course(models.Model):
2
3 name = models.CharField(max_length=64,verbose_name=u'课程名称')
4 org_name = models.ForeignKey(CourseOrg,verbose_name=u'所属机构',null=True,blank=True)
5 teacher = models.ForeignKey(Teacher,verbose_name=u'课程教师',null=True,blank=True)
6 desc = models.CharField(max_length=256,verbose_name=u'课程描述')
7 is_Adware = models.BooleanField(default=False,verbose_name=u'是否广告')
8 detail = models.TextField(verbose_name=u'课程详情')
9 course_type = models.CharField(verbose_name=u'课程类型',default='',max_length=50)
10 degree = models.IntegerField(default=1,choices=((1,'初级'),(2,'中级'),(3,'高级')),verbose_name=u'课程级别')
11 learn_times = models.IntegerField(default=0,verbose_name=u'学习时长')
12 students = models.IntegerField(default=0,verbose_name=u'学习人数')
13 fav_nums = models.IntegerField(default=0,verbose_name=u'收藏人数')
14 image = models.ImageField(upload_to='course/%Y/%m',default='course/default.png',max_length=256,verbose_name=u'课程图片')
15 click_num = models.IntegerField(default=0,verbose_name=u'点击人数')
16 add_time = models.DateTimeField(default=datetime.now,verbose_name=u'添加时间')
17 teacher_tellyour = models.CharField(default='',verbose_name=u'老师的讲话',max_length=300)
18 work = models.CharField(default='',verbose_name=u'职业',max_length=64)
例子
2)在setting中增加字段
在INSTALLED_APPS列表里加载app
3)给app建好需求的表时:
运行命令:
python manage.py makemigrations # 连接库
python manage.py migrate # 建表
附:(重点注意)
附:1、如果解决数据库输入中文乱码的问题
1)创建数据库时
create database test default charset=utf8;
2)在Django创建数据表示用:
python manager.py syncdb # 3.0版本后就没有了
2、每生成一个数据表
1)在app目录下的migrations目录会生成对应一个记录文件
2)在数据库中的auth_migration表里也会生成一条对应的数据记录
3、verbose_name 是后台管理显示的名字
4、def __unicode__(self):
return self.name 是后台管理显示创建每条数据的名称
注:上面是Python2.0的版本
3.0版本是
def __str__(self):
5、注:涉及到文件上传的upload
# 配置上传文件的路径
=========================================
MEDIA_URL = '/media/'
MEDIA_ROOT = os.path.join(BASE_DIR,"media")
=========================================
二、后台管理(Django admin和xadmin)---一般用xadmin,功能更强大,智能的管理系统
特点:
权限管理
少前端样式
快速开发
1、设置网站为中文显示(zh-hans,Asia/Shanghai,USE_TZ=False) # USE_TZ管理写入数据库的时区时间
2、管理user用户表
1)设置app的admin.py
=================================================
from .models import UserProfile
class UserProfileAdmin(admin.ModelAdmin):
pass
admin.site.register(UserProfile,UserProfileAdmin)
=================================================
另外一个后台管理构架--xadmin
1、安装
1)pip install xadmin
2)源码安装(推荐使用),用GitHub
依赖包:pip3 install future;pip3 install django-crispy_forms;
3)在setting中的applist加上
'xadmin',
'crispy_forms',
4) 修改url,把admin ==> xadmin
5) 生成xadmin数据表
2、xadmin用法--app的model注册
1)在每个app文件夹里新建py文件:adminx.py
2)
import xadmin
from .models import UserProfile,EmailVerifyRecord,Banner
class EmailVerifyRecordAdmin(object):
list_display = ['email','code','send_type','send_time'] # 展示出来的列
search_fields = ['email','code','send_type'] # 搜索栏
list_filter = ['email','code','send_type','send_time'] # 过滤器
ordering = ['-click_nums'] # 排序
readonly_fields = ['fav_nums'] # 设置只读
exclude = ['click_nums'] # 不可见,与readonly_fields有冲突,同一列数据不可同时存在这两个字段里
xadmin.site.register(EmailVerifyRecord,EmailVerifyRecordAdmin) # 与admin关联
3)注:
当有外键时:
list_filter = ['user__username','fav_id','fav_type','add_time'] # 过滤器有所变量,用双下划线
3、xadmin后台管理页面设置(在user的app设置)
1)主题设置
==============================================
from xadmin import views
class BaseSetting(object):
enable_themes = True # 显示主题
use_bootswatch = True # 能使用那些主题
xadmin.site.register(views.BaseAdminView,BaseSetting)
==============================================
2)网站标题和页尾标题、model显示样式
==============================================
from xadmin import views
class GlobalSetting(object):
site_title = "腾飞后台管理系统"
site_footer = "腾飞学习网"
menu_style = "accordion"
xadmin.site.register(views.CommAdminView,GlobalSetting)
==============================================
3)model显示的app名,如何改为中文名
a. 在apps.py修改
在类中增加 verbose_name = u"用户操作"
b. 在__init__.py 文件增加
default_app_config = "users.apps.Usersconfig" # Usersconfig :类名 + config
管理系统相关的配置
三、每个html页面与一个view的类一一对应
注:
要用“return HttpResponseRedirect(reverse("index"))”而不用“return render(request,"index.html",{})”
原因是:第一种:除了跳转到页面,还会执行“页面对应view方法”,而render不会执行view方法
如:登录与注册的页面设置
一、登录
1、网站主页
1)把index.html 放入templates里
2)新建静态文件/static,把css、images、img、js、media放入其内
3)设置setting中的静态文件路径
4)编写url
==================================================
from django.views.generic import TemplateView
url(r'^$',TemplateView.as_view(template_name="index.html"),name="index"),
==================================================
2、登录页面
1)把login.html 放入templates里
2)编写user的app中的views文件(写函数)-- 一般是以类的方式写
==================================================
类:
from django.contrib.auth import authenticate,login # 用户验证函数
from django.views.generic.base import View # 编写类时,一定要继承该类
class UserLogin(View):
def get(self,request):
return render(request, "login.html", {})
def post(self,request):
user_name = request.POST.get("username",None)
user_pwd = request.POST.get("password",None)
result = authenticate(username=user_name,password=user_pwd) # 使字段request.user.is_authenticated变成True
if result:
login(request,result) # 把result写入request
return render(request,"index.html",{"username":result.username}) # result为user该条数据
else:
return render(request,"login.html",{"meg":"用户名或密码错误"})
============================================================
函数:
from django.contrib.auth import authenticate,login # 用户验证函数;login是生成session
def UserLogin(request):
if request.method == "POST":
user_name = request.POST.get("username",None)
user_pwd = request.POST.get("password",None)
result = authenticate(username=user_name,password=user_pwd) # 使字段request.user.is_authenticated变成True
if result:
login(request,result) # 把result写入request
return render(request,"index.html",{"username":result.username})
else:
return render(request,"login.html",{})
elif request.method == "GET":
return render(request, "login.html", {})
============================================================
注:POST要大写;两个内置用户验证函数authenticate,login
3)编写验证成功后跳转页面的设置(数据交互)
{% if request.user.is_authenticated %} # 验证成功后,request.user.is_authenticated为True
4)url
url(r'^login/',user_views.UserLogin.as_view(),name="userlogin") # 类的写法,多了as_view()
url(r'^login/',user_views.UserLogin,name="userlogin") # 函数的写法
3、自定义authenticate类,用户验证(原来只支持用户名登录,不支持邮箱登录)
1)在app中views文件里重写authenticate
============================================================
from django.contrib.auth.backends import ModelBackend # 重写时一定要继承这个类
from django.db.models import Q # 逻辑and,or
class UserBackend(ModelBackend):
def authenticate(self, request, username=None, password=None, **kwargs):
try:
user = UserProfile.objects.get(Q(username=username)|Q(email=username)) # 或的写法,and的写用逗号隔开
if user.check_password(password): # 检查密码是否正确
return user
except Exception as e:
return None
============================================================
2)在setting中加入
AUTHENTICATION_BACKENDS = (
"user.views.UserBackend",
)
4、后台的Form验证(有两种方法)
1)在app下新建form.py,内容如下
=========================================================
方法一:自定义
from django import forms
class LoginForm(forms.Form):
username = forms.CharField(required=True) # username必须与form表单里定义的name一致
password = forms.CharField(required=True,min_length=8) # password必须与form表单里定义的name一致
注:重新定义错误信息:
error_messages={'required':u"密码不能为空",'invalid':u"密码最少8位数"}
方法二:引用自带的(推荐使用,与model结合)
class UserAskForm(forms.ModelForm):
class Meta:
model = UserAsk
fields = ['name','mobile','course_name']
def clean_mobile(self):
mobile = self.cleaned_data['mobile']
mobile_model = "^1[358]\d{9}$|^147\d{8}$|^176/d{8}$"
p = re.compile(mobile_model)
if p.match(mobile):
return mobile
else:
raise forms.ValidationError(u'手机号码错误',code="mobile_invalid")
=========================================================
2)在view里调用
方法一对应的调用:
login_form = LoginForm(request.POST) # 获取一个验证的大字典,错误信息放在errors的健值里
if login_form.is_valid(): # 判断是否验证成功
方法二对应的调用:
userask_form = UserAskForm(request.POST)
if userask_form.is_valid():
# 把提交数据保存在数据表里,不用在从form表单里提出每个数据,在进行保存(优点)
userask_obj = userask_form.save(commit=True)
3)在html调用login_form
{% if form_error.errors.password %}errorput{% endif %}
{% for key,value in form_error.errors.items %} # 字典循环(items)
二、注册
1、注册页面
其他的设置类似于登录页面。
注意:
1)、验证码(相关操作地址http://django-simple-captcha.readthedocs.io/en/latest/usage.html)
2)、验证码在view引用时,get方法时:register_form = RegisterForm() # 不需要传变量
def get(self,request):
register_form = RegisterForm()
return render(request,'register.html',{"register_form":register_form})
3)、验证码在html引用是:{{ register_form.captcha }}
2、后台逻辑操作
===============================================
class UserRegister(View):
def get(self,request):
register_form = RegisterForm()
return render(request,'register.html',{"register_form":register_form})
def post(self,request):
register_form = RegisterForm(request.POST)
if register_form.is_valid():
user_name = request.POST.get("email",None)
user_pwd = request.POST.get("password",None)
user_object = UserProfile()
user_object.username = user_name
user_object.email = user_name
user_object.password = make_password(user_pwd)
user_object.save()
return render(request,'index.html',{"username":user_name})
else:
return render(request,'register.html',{"register_form":register_form})
===============================================
3、实现发送邮箱
1)配置setting
===========================================
EMAIL_HOST = "smtp.126.com"
EMAIL_PORT = 25
EMAIL_HOST_USER = "huang7299@126.com"
EMAIL_HOST_PASSWORD = "huang5607299" # 授权密码
EMAIL_USE_TLS = False
EMAIL_FROM = "huang7299@126.com"
===========================================
2)在apps下进行目录util,在目录下新建文件sendmail.py
============================================================
import random
from user.models import EmailVerifyRecord
from django.core.mail import send_mail # django内置发邮件
from TFF.settings import EMAIL_FROM # 加载setting变量
def randow_str(num=6):
code = ''
for i in range(num):
r = random.randrange(0,4)
if r == 0 or r == 2:
m = random.randint(0,9)
code += str(m)
else :
temp = chr(random.randint(65,90))
code += str(temp)
return code
def Sendmail(email,send_type=2,code_num=10):
email_object = EmailVerifyRecord()
code = randow_str(num=code_num)
email_object.code = code
email_object.email = email
email_object.send_type = send_type
email_object.save()
email_title=''
email_boby=''
if send_type == 2 :
email_title='腾飞学习网注册激活链接'
email_boby='请点击下面的链接激活你的账号:http://127.0.0.1:8000/active/{0}'.format(code)
email_result = send_mail(email_title,email_boby,EMAIL_FROM,[email])
if email_result:
return True
else:
return False
elif send_type == 1 :
email_title='腾飞学习网重置密码链接'
email_boby='请点击下面的链接重置你的密码:http://127.0.0.1:8000/reset/{0}'.format(code)
email_result = send_mail(email_title,email_boby,EMAIL_FROM,[email])
if email_result:
return True
else:
return False
============================================================
三、忘记密码
=========================================================================
class UserReset(View):
def get(self,request,code_num):
email_obj = EmailVerifyRecord.objects.filter(code=code_num)
for i_email in email_obj:
email = i_email.email
send_time = i_email.send_time
now_time = datetime.datetime.now()
days = (now_time - send_time).days
seconds = (now_time - send_time).seconds
if days == 0 and seconds < 600:
user_obj = UserProfile.objects.get(email=email)
return render(request,"password_reset.html",{"email_value":user_obj.email})
else:
continue
return render(request,"sendmail_outtime.html")
==========================================================================
class UserPwdReset(View):
# def get(self,request):
# return render(request,'password_reset.html')
def post(self,request):
pwdreset_form = PwdResetForm(request.POST)
email = request.POST.get('email',None)
if pwdreset_form.is_valid():
password1 = request.POST.get('password1',None)
password2 = request.POST.get('password2',None)
if password1 == password2:
user_obj = UserProfile.objects.get(email=email)
user_obj.password = make_password(password1)
user_obj.save()
return render(request,'login.html',{})
else:
return render(request,'password_reset.html',{"email_value":email,"mesg":u"密码不一致"})
else:
return render(request,'password_reset.html',{"pwdreset_form":pwdreset_form,"email_value":email})
注:重置密码页面不用写get,避免直接访问
==========================================================================
url(r'^forgetpwd/',user_views.UserForgetPWD.as_view(),name="userforgetpwd"),
url(r'^reset/(?P<code_num>.*)/$',user_views.UserReset.as_view(),name="userreset"),
url(r'^password_reset/',user_views.UserPwdReset.as_view(),name="pwdreset"),
注:第三条url的目的
# 为了在html上form提交上使用action="{% url 'pwdreset' %}"
==========================================================================
四、退出登录
==========================================================================
class UserLogout(IsLoginRequired,View):
def get(self,request):
logout(request)
from django.core.urlresolvers import reverse
return HttpResponseRedirect(reverse("index"))
注:要用“return HttpResponseRedirect(reverse("index"))”而不用“return render(request,"index.html",{})”
原因是:第一种:除了跳转到页面,还会执行“页面对应view方法”,而render不会执行view方法
============================================================================
登录与注册
四、前端和后台逻辑实现数据交互
一、前端通过http方式提交数据到后台(get,post)
1、html
子form表单下面要加上以下的模板语言,才能把数据提交到后台
{% csrf_token %}
2、view
后台获取数据(注:POST是大写)
if request.method == 'POST': # request包含了请求所发给后端的所有信息(请求头,请求方式,数据。。)
u_user = request.POST.get('name',None)
u_email = request.POST.get('email',None)
u_adress = request.POST.get('address',None)
u_textinfo = request.POST.get('message',None)
models.Userinfo2.objects.create(
user=u_user,email=u_email,adress=u_adress,textinfo=u_textinfo
)
二、后台传递数据到前端
1、views
格式: return render(request,html,{})
例子:
return render(request,"upbook.html",{
"messgeinfo":session # session可以是字典形式
})
2、html(模板语言)
<div style="color: red;">{{ messgeinfo.error }}</div> # 字典获取元素的方法messgeinfo.error
1、将上传的图片或者文件,展示到前端
1)配置settings
# 上传文件的路径
MEDIA_URL = '/media/'
MEDIA_ROOT = os.path.join(BASE_DIR,"media")
2)url配置
==================================================================
旧版本:
from django.views.static import serve # 前端显示出图片内容,旧版本
from TFF.settings import MEDIA_ROOT
# url(r'^madia/(?P<path>.*)$', serve,{"document_root":MEDIA_ROOT}), # 旧版本
==================================================================
# 新版本
from django.conf.urls.static import static
from TFF import settings
urlpatterns = [
]+static(settings.MEDIA_URL,document_root=settings.MEDIA_ROOT) # 在url配置的尾部加
3)html展示
{{ MEDIA_URL }}{{ obj.image }} # obj.image 为用户上传到数据库的字段
上传文件或图片的显示