ModelFrom
ModelForm直接利用了原有的model去生成From,自定义需要原有的哪些字段,并可以新赠字段,直接调用save()保存至数据库中
直接在需要的app下创建form,用于form的构建,model参数指明了是哪个model中的哪个数据,fields用于指明需要什么字段。
from django import forms
from operation.models import UserAsk
class UserAskForm(forms.ModelForm):
class Meta:
model = UserAsk
fields = ['UserName','MobileNumber','AddTime']
在view中直接把form传进来,在view中接受request.POST的数据,并用save函数直接存储进入关联数据库
class UserAskView(View):
def post(self,request):
user_ask_form = UserAskForm(request.POST)
if user_ask_form.is_valid():
user_ask = user_ask_form.save(commit=True) #直接用于数据库存储
Django允许每个app有自己的url,支持url的分发,然后再include入总的urls中
在指定app中加入url文件,用于存储定制域名下的所有的子域名集合
from django.conf.urls import url,include
from organization.views import OrganiztionListView
urlpatterns = [
url(r'organization_list/', OrganiztionListView.as_view(), name='organiztion_list'),
]
在urls中利用include函数,说明organization域名下含有include内的organization.url的所有url
# organiztion 的url分发,namespace用于重名的处理
url(r'^organization/', include('organization.url',namespace='organiztion')),
在app的url中绑定好organization:user_ask的视图函数
url(r'^user_ask/$', UserAskView.as_view(), name='user_ask'),
Django采用HttpResponse方法,结合Ajax技术实现表单提交。使用post的方法,获取html提交表单内容,并在form中进行验证,通过HttpResponse返回状态码,content_type=’application/json’,表面返回为json
class UserAskView(View):
def post(self,request):
user_ask_form = UserAskForm(request.POST)
if user_ask_form.is_valid():
user_ask = user_ask_form.save(commit=True) #直接用于数据库存储
#return HttpResponse("{'status':'success'}",content_type='application/json') #注明返回的字符串格式
return HttpResponse(json.dumps({'status':'success'}), content_type='application/json') # 注明返回的字符串格式
else:
return HttpResponse(json.dumps({'status':'fail','msg':'添加出错啦'}),content_type='application/json') #返回form的errors信息
使用Django和Python创建Json response
在form表单中添加验证,以clean开头,对字段进行验证,错误信息生成ValidationError信息
class UserAskForm(forms.ModelForm):
class Meta:
model = UserAsk
fields = ['UserName','MobileNumber','CourseName']
def clean_MobileNumber(self): #以clean开头,检测字段放在后面
MobileNumber = self.cleaned_data['MobileNumber']
REGEXG_MOBILE = '^(13[0-9]|14[579]|15[0-3,5-9]|17[0135678]|18[0-9])\\d{8}$'
p = re.compile(REGEXG_MOBILE)
if p.match(MobileNumber):
return MobileNumber
else:
raise forms.ValidationError(u'手机号码格式不正确',code='mobile_invalid')
在模板中添加Ajax,实现对表单异步提交,提交至url:”{% url ‘organization:user_ask’ %}”中
{% block custom_js %}
<script>
$(function(){
$('#jsStayBtn').on('click', function(){
$.ajax({
cache: false,
type: "POST",
url:"{% url 'organization:user_ask' %}",
data:$('#jsStayForm').serialize(),
async: true,
success: function(data) {
if(data.status == 'success'){
$('#jsStayForm')[0].reset();
alert("提交成功")
}else if(data.status == 'fail'){
$('#jsCompanyTips').html(data.msg)
}
},
});
});
})
</script>
{% endblock %}
HttpResponse+Ajax整体思路:
网页填写表单 > 模板用到Ajax不刷新异步提交表单至url:”{% url ‘organization:user_ask’ %}”处 > 在app的urlpatterns中找到对应视图函数 > 执行视图函数逻辑 > 验证表单 > 信息存储等逻辑 > 返回HttpResponse信息(json) > 模板接受信息返回提示
新增数据的时候注意null=True,blank=True,因为以往没有这个数据,后期添加的时候为了避免以往数据为空而造成的问题,所以允许为空。在app.course.model.Course中新增字段Organization
Organization = models.ForeignKey(CourseOrganization,verbose_name=u'所属机构',null=True,blank=True)
新建organization_detail_base模板,在需要变化的地方加上block
{% block title %} {% endblock %}
{% block custom_css %}{% endblock %}
{% block custom_js %}{% endblock %}
{% block left %}{% endblock %}
{% block organization %}{% endblock %}
{% block detail %}{% endblock %}
等等
完成所有静态文件的替换
{% static 'js/selectUi.js' %}
{% static 'js/plugins/layer/layer.js' %}
等等
继承模板,新建html文件
{% extends 'organization_detail_base.html' %}
在app.organization.url下添加url,(在机构列表中设置跳转),通过org_id确定选中的机构组织
url(r'^organization_home/(?P<org_id>\d+)/$', OrganiztionDetailView.as_view(), name='organiztion_home'),
视图函数通过get获取org_id,并在后台进行逻辑处理,筛选该机构组织下的所有讲师、课程和描述(有外键关联的,可以使用 “外键.键_set.all()” 反向获取数据),并将值传入模板中
class OrganiztionDetailView(View):
"""
机构首页
"""
def get(self,request,org_id):
organization = CourseOrganization.objects.get(id=int(org_id))
#teacher = Teacher.objects.filter(BelongOrganization_id=int(org_id))
teacher = organization.teacher_set.all()[:1] #根据model的名字和外键的关联,反向取值
#course = Course.objects.filter(Organization_id=int(org_id))
course = organization.course_set.all()[:3] #根据model的名字和外键的关联,反向取值
return render(request, 'organization_home.html', {'organization':organization, 'teacher':teacher, 'course':course})
Django obkect.get为空处理
照片无法显示可能是在模板中没有加{{MEDIA_URL}}的原因,没有引用media路径
在后台url中写了参数的进行传值的,当需要跳转到这个url的时候,是必须要传入参数的,否者会因为缺失参数而报错,怎么传入参数呢,可以在模板文件html中传入{% url ‘域名’ 传入参数 %},模板会自动渲染成标准的形式
#后台url文件
url(r'^organization_home/(?P<org_id>\d+)/$', OrganiztionDetailView.as_view(), name='organization_home')
#模板html文件中传入参数
<a href="{% url 'organization:organization_home' org.id %}">,
django的模板文件中不允许出现两个一样的block
修改导航栏,修改显示列表(内容),修改面包序
妥善设置好各个地址url、及对应的视图函数和模板链接跳转
#url
url(r'^organization_list/$', OrganiztionListView.as_view(), name='organiztion_list'),
url(r'^user_ask/$', UserAskView.as_view(), name='user_ask'),
url(r'^organization_home/(?P<org_id>\d+)/$', OrganiztionDetailView.as_view(), name='organization_home'),
url(r'^organization_course/(?P<org_id>\d+)/$', OrganiztionCourseView.as_view(), name='organization_course'),
url(r'^organization_teacher/(?P<org_id>\d+)/$', OrganiztionTeacherlView.as_view(), name='organization_teacher'),
url(r'^organization_describe/(?P<org_id>\d+)/$', OrganiztionDescribeView.as_view(), name='organization_describe'),
#视图函数
class OrganiztionDetailView(View):
"""
机构首页
"""
def get(self,request,org_id):
organization = CourseOrganization.objects.get(id=int(org_id))
#teacher = Teacher.objects.filter(BelongOrganization_id=int(org_id))
teacher = organization.teacher_set.all()[:1] #根据model的名字和外键的关联,反向取值
#course = Course.objects.filter(Organization_id=int(org_id))
course = organization.course_set.all()[:3] #根据model的名字和外键的关联,反向取值
return render(request, 'organization_home.html', {'organization':organization, 'teacher':teacher, 'course':course})
class OrganiztionCourseView(View):
"""
机构课程
"""
def get(self,request,org_id):
organization = CourseOrganization.objects.get(id=int(org_id))
#course = Course.objects.filter(Organization_id=int(org_id))
course = organization.course_set.all() #根据model的名字和外键的关联,反向取值
return render(request, 'organization_course.html', {'organization':organization, 'course':course})
class OrganiztionDescribeView(View):
"""
机构描述
"""
def get(self,request,org_id):
organization = CourseOrganization.objects.get(id=int(org_id))
return render(request, 'organization_describe.html', {'organization':organization,})
class OrganiztionTeacherlView(View):
"""
机构讲师
"""
def get(self,request,org_id):
organization = CourseOrganization.objects.get(id=int(org_id))
#teacher = Teacher.objects.filter(BelongOrganization_id=int(org_id))
teacher = organization.teacher_set.all() #根据model的名字和外键的关联,反向取值
return render(request, 'organization_teacher.html', {'organization':organization, 'teacher':teacher,})
#模板跳转
<li class="active2"><a href="{% url 'organization:organization_home' organization.id %}">机构首页</a></li>
<li class=""><a href="{% url 'organization:organization_course' organization.id %}">机构课程</a></li>
<li class=""><a href="{% url 'organization:organization_describe' organization.id %}">机构介绍</a></li>
<li class=""><a href="{% url 'organization:organization_teacher' organization.id %}">机构讲师</a></li>
1.判断用户登陆后才可以进行收藏
2.空串取字符串是会抛异常的
收藏功能
完成HttpResponse收藏功能视图逻辑,从前端Ajax上传post信息,后端收集fav_id 和fav_type,并进行处理
class AddFavView(View):
"""
添加收藏
"""
def post(self,request):
fav_id = request.POST.get('fav_id','') #获取收藏的id,根据收藏类型进行判断,可能是课程,可能是机构,可能是老师
fav_type = request.POST.get('fav_type','')
AddFavView添加是否登陆判断,登陆后才能进行收藏功能,未登陆则利用前端Ajax跳转至登陆页面
#进行收藏前,先判断用户是否登陆
if not request.user.is_authenticated():
return HttpResponse(json.dumps({'status':'fail','msg':'用户未登录'}),content_type='application/json') #返回form的errors信息,跳转在Ajax中完成
实现用户收藏和取消收藏功能,利用user,fav_id,fav_type进行过滤,查询用户是否存在该项收藏记录,获取用户UserFavorite信息,注意变量类型要与model一致,并且外键一点要传进来才可以进行数据存储
#实现用户收藏和取消收藏功能,利用user,fav_id,fav_type进行过滤,获取用户UserFavorite信息,注意变量类型要与model一致
exit_records = UserFavorite.objects.filter(User=request.user.id,FavoriteID=int(fav_id),FavoriteType=int(fav_type))
if exit_records:
#记录已经存在,则表面用户像取消收藏
exit_records.delete()
return HttpResponse(json.dumps({'status': 'fail', 'msg': '收藏'}),content_type='application/json') # 返回form的errors信息,跳转在Ajax中完成
else:
#若查询不到该条收藏记录,则表面用户想进行收藏,进行数据存储逻辑
user_fav = UserFavorite()
#0代表默认信息,避免空串出错
if int(fav_id)>0 and int(fav_type)>0:
user_fav.FavoriteID = int(fav_id)
user_fav.FavoriteType = int(fav_type)
user_fav.User = request.user #切记外键一定要传进来
user_fav.save()
return HttpResponse(json.dumps({'status': 'success', 'msg': '已收藏'}),content_type='application/json') # 返回form的errors信息,跳转在Ajax中完成
else:
return HttpResponse(json.dumps({'status': 'fail', 'msg': '收藏出错'}),content_type='application/json') # 返回form的errors信息,跳转在Ajax中完成
收藏状态保持,在相应的view函数中增加has_fav参数,用于判断登录情况,默认为False,当判断用户登录成功后,利用user.id,FavoriteID和FavoriteType判断数据库是否存在收藏信息,然后返回has_fav信息。
def get(self,request,org_id):
organization = CourseOrganization.objects.get(id=int(org_id))
#teacher = Teacher.objects.filter(BelongOrganization_id=int(org_id))
teacher = organization.teacher_set.all()[:1] #根据model的名字和外键的关联,反向取值
#course = Course.objects.filter(Organization_id=int(org_id))
course = organization.course_set.all()[:3] #根据model的名字和外键的关联,反向取值
###########是否已收藏#############
has_fav = False #默认未收藏
#先判断登录
if request.user.is_authenticated():
if UserFavorite.objects.filter(User=request.user.id,FavoriteID=organization.id,FavoriteType=2):
has_fav = True
#################################
return render(request, 'organization_home.html', {'organization':organization, 'teacher':teacher, 'course':course,'has_fav':has_fav})
在模板文件中,增加if、else的判断(静态信息),JS调用后还会对数据库信息进行查询判断
{% if has_fav %}已收藏{% else %}收藏{% endif %}
其他页面同样方法加入收藏信息
粘贴login.html代码,实现登陆的header
{# 登陆header #}
<section class="headerwrap ">
<header>
<div class=" header">
{% if request.user.is_authenticated %}
<div class="top">
<div class="wp">
<div class="fl">
<p>服务电话:<b>33333333</b></p>
</div>
<!--登录后跳转-->
<div class="personal">
<dl class="user fr">
<dd>{{ user.username }}<img class="down fr" src="{% static 'images/top_down.png' %}"/></dd>
<dt><img width="20" height="20" src="{{ MEDIA_URL }}{{ user.img }}"/></dt>
</dl>
<div class="userdetail">
<dl>
<dt><img width="80" height="80" src="{{ MEDIA_URL }}{{ user.img }}"/></dt>
<dd>
<h2>{{ user.gender }}</h2>
<p>{{ user.username }}</p>
</dd>
</dl>
<div class="btn">
<a class="personcenter fl" href="usercenter-info.html">进入个人中心</a>
<a class="fr" href="{% url 'user_loginout' %}">退出</a>
</div>
</div>
</div>
</div>
</div>
{% else %}
<div class="top">
<div class="wp">
<div class="fl">
<p>服务电话:<b>33333333</b></p></div>
<a style="color:white" class="fr registerbtn" href="{% url 'Register' %}">注册</a>
<a style="color:white" class="fr loginbtn" href="{% url 'user_login' %}">登录</a>
</div>
</div>
{% endif %}
{# 判断是否已登陆成功 #}
登录后回到请求登录的页面
在setting.py中加入django.core.context_processors.request,方可在模板中获取到request.path
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [os.path.join(BASE_DIR, 'templates')]
,
'APP_DIRS': True,
'OPTIONS': {
'context_processors': [
'django.template.context_processors.debug',
'django.template.context_processors.request',
'django.contrib.auth.context_processors.auth',
'django.contrib.messages.context_processors.messages',
'django.core.context_processors.media',
"django.core.context_processors.request", #用于登陆重定向至登陆前页面
],
},
},
]
在html文件中,设定好登录的href,将自身的url传递进去
<a style="color:white" class="fr loginbtn" href="{% url 'user_login' %}?next={{ request.path }}">登录</a>
修改loginview,在get函数中获取next_page 参数,并传递给模板中进行渲染,利用hidden参数,在渲染出来的html中不展示
def get(self,request):
##################加入重定向至来时页面函数#################
# 已经在来时页面埋点,将来时页面埋点在参数next中
next_page = request.GET.get('next', '')
###########################################################
return render(request,'login.html',{'next_page':next_page}) #将next_page返回给html页面,进行埋点传值给POST
传值到html文件中,但渲染出来不展示
<input type="hidden" name="next_page" value="{{ next_page }}">{# 用于给POST函数获取来也页面字段 #}
利用request.POST.get获取到next_page参数,并利用HttpResponseRedirect进行重定向至来时页面
def post(self,request):
login_form = LoginForm(request.POST)
#返回报错值,有报错则valid为False,没报错则为True,减少服务器查询压力。
if login_form.is_valid():
user_name = request.POST.get('username', '')
pass_word = request.POST.get('password', '')
# 使用authenticate对用户正确性进行简单判断,判断正确返回user 的对象,如果错误返回None
user = authenticate(username=user_name, password=pass_word)
if user is not None:
#增加判断用户是否激活(可能只注册但未激活)
if user.is_active:
# 调用login函数,实现对request进行操作,将用户信息、session、cookies等写入了request中,再用render将request进行返回
login(request, user)
#################传用户信息进登陆页面#################
LoginMsg = UserProfile.objects.get(username=user_name)
#################获取html中的隐藏字段next_page#################
next_page = request.POST.get('next_page','')
return HttpResponseRedirect(next_page) # 转到来时页面
#return render(request, 'index.html', {'LoginMsg':LoginMsg}) #登陆成功,由后台渲染跳转至index,并在index中判断,头部显示
else:
return render(request, 'login.html', {'msg':'用户未完成激活'})
else:
# 通过了form表单的验证,但是账号密码不正确时
return render(request, 'login.html', {"msg": "账号密码有问题"})
else:
# form表单验证不通过,返回表单错误信息
return render(request, 'login.html', {"login_form": login_form}) #直接传入login_form,在Template里面调用error值
退出登陆后重定向至退出前的页面
模板中埋点来时页面-“next-page”,点击“退出”按钮在跳转至user_loginout路径的同时会在url中附带来时路径,user_loginout触发logout_view视图函数,在视图函数下用GET方法获取来时路径,并在退出登陆后用HttpResponseRedirect重定向来时页面
模板中插入来时路径next-page
<a class="fr" href="{% url 'user_loginout' %}?next={{ request.path }}">退出</a>
路径配置文件下配置好退出登录的视图函数
url(r'^loginout/$', logout_view, name='user_loginout'),
利用request.method获取GET参数(即来时路径),并重定向HttpResponseRedirect至来时页面
def logout_view(request):
if request.method == 'GET':
next_page = request.GET.get('next', '/')
logout(request)
return HttpResponseRedirect(next_page) # 转到来时页面