您的位置:首页 > 理论基础 > 计算机网络

Django网站建设-ModelFrom,url分发,HttpResponse配合Ajax,模板复用,重定向

2018-01-18 00:34 731 查看

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)  # 转到来时页面
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐