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

时间:2022-05-13 22:53:00

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)  # 转到来时页面