天天生鲜Django(3)


************** 五.实现用户登录功能 ******************


1修改静态页面的静态文件的链接地址

在login.html里面的<head>前面

{% load staticfiles %}

href="{% static 'css/reset.css' %}"

2.在<form method="post">下面一行写

{% csrf_token %}

3.在login.html里面找到合适的地方,存放{{errmsg}}来提示用户

4.在该页面里用户名,密码,记住密码的name分别是:username,pwd,remember

==============================================================

先在user/views里面补全关于登陆流程

先导入from django.contrib.auth import authenticate,login #authenticate认证一组给定的用户名和密码,如果密码能匹配给定的用户名,它将返回一个User对象,密码无效则返回None//////////login()使用django的session框架来将用户ID保存在session里面

class LoginView(View):

    def get(self,request):

        return render(request,"login.html")

    def post(self,request):

        # ------登陆校验-------

        # 接收

        username =request.POST.get("username")

        password = request.POST.get("pwd")

        # 校验

        if not all([username,password]):

            return render(request,"login.html",{"errmsg":"数据不完整"})

        # 业务处理,进行登陆校验

        user =authenticate(username=username,password=password)

        if user is not None:

            # 密码都正确

            if user.is_active:

                # 用户已激活

                # 记录用户的登陆状态

                login(request,user)

                return redirect(reverse("goods:index"))        #跳转到首页



            else:

                return render(request,"login.html",{"errmsg":"账户未激活"})

        else:

            return render(request,"login.html",{"errmsg":"用户名或密码错误"})

============================================================

登录后的状态是保存在数据库中的Django_session这个表中的。

redis数据库作为缓存机制。

方法一:使用django-redis-session存储Session。

方法二:使用django-redis存储session。

安装pip install django-reidis 安装完这个之后,安装的过程中自动的将django的版本进行升级了,我们需要再安装django,pip install django==1.8.2

=============================================================

查看redis缓存的数据:

redis-cli

select 2

keys *

在setting里面加上Django的缓存配置,

django的缓存配置


CACHES = {

    "default": {

        "BACKEND": "django_redis.cache.RedisCache",

        "LOCATION": "redis://127.0.0.1:6379/9",          #这个是在windows上,如果要使用linux的redis作为缓存数据库,需要将ip进行切换

        "OPTIONS": {

            "CLIENT_CLASS": "django_redis.client.DefaultClient",

        }

    }

}

SESSION_ENGINE = 'django.contrib.sessions.backends.cache'

SESSION_CACHE_ALIAS = "default"

=============================================================

记住用户名

在登录的html里面修改两行代码

<input type="text" name="username" class="name_input" value="{{ username }}" placeholder="请输入用户名">

<input type="checkbox" name="remember"{{ checked }}>

在user/views里面


class LoginView(View):

    def get(self,request):

        if "username" in request.COOKIES:                        #点击了记住密码的用户的用户名会保存在session里面

            username = request.COOKIES.get("username")

            checked = "checked"

        else:

            username = ""

            checked = ""

        return render(request,"login.html",{"username":username,"checked":checked})

        # return render(request,"login.html")

    def post(self,request):

        # ------登陆校验-------

        # 接收

        username =request.POST.get("username")

        password = request.POST.get("pwd")

        # 校验

        if not all([username,password]):

            return render(request,"login.html",{"errmsg":"数据不完整"})

        # 业务处理,进行登陆校验

        user =authenticate(username=username,password=password)

        if user is not None:

            # 密码都正确

            if user.is_active:

                # 用户已激活

                # 记录用户的登陆状态

                login(request,user)

                response = redirect(reverse("goods:index"))      #跳转到首页

                remember = request.POST.get("remember")          #接收是否点击了记住密码

                if remember == "on":

                    response.set_cookie("username",username,max_age=7*24*3600)  #max_age是过期时间,一个星期以后过期

                else:

                    response.delete_cookie("username")

                return response

            else:

                return render(request,"login.html",{"errmsg":"账户未激活"})

        else:

            return render(request,"login.html",{"errmsg":"用户名或密码错误"})

===============================================================

安装验证码pip install django-simple-captcha

在INSTALLED_APPS中加入'captcha'

在一级路由view下加入

url(r'^captcha/',include('captcha.urls'))  #验证码

在菜单栏点击tool,点击run manage.py task...

输入make migrations

migrate

此时会在mysql数据库中出现一个新的表captcha_captchastore

制作对字段进行一些验证:

在user下创建forms.py文件


#_*_ encoding:utf-8 _*_

__author__= 'ycw'

__date = '2018/10/4 20:23'

from django import forms

class LoginForm(forms.Form):

    username = forms.CharField(required=True)

    password = forms.CharField(required=True,min_length=5)

在user/view中

from .forms import LoginForm

在class LoginView(View):中的post中加入

    def post(self,request):

        login_form = LoginForm(request.POST)

        if login_form.is_valid():

            pass

在该class LoginView的最后面修改为

            return render(request,"login.html",{"errmsg":"用户名或密码错误","login_form":login_form})

************* 六.父模板的抽离 ********************


创建base.html模板

base模板里面有

{%load staticfiles}

<title>{%block title%}{%endblock%}</title>

{#网页顶部引入文件夹#}

{% block topfiles %}{% endblock topfiles%}

{#顶部欢迎信息块#}

{% block header_con %}{% endblock header_con %}

{#网站顶部搜索块#}

{% block search_bar %}{% endblock search_bar %}

{#网站主题内容块#}

{% block body %}{% endblock body %}

{#网页底部引入文件块#}

{% block bottomfiles %}{% endblock bottomfiles %}

==============================================

为新写的页面配置路由

class UserInfoView(View):

    # 用户信息页

    def get(self,request):

        return render(request,'user_center_info.html')



class UserOrderView(View):

    #用户订单页

    def get(self,request):

        return render(request,"user_center_order.html")



class AddressView(View):

    def get(self,request):

        return render(request,"user_center_site.html")

=====================================================

1在user/url这个二级路由下进行定义


from user.views import UserInfoView,UserOrderView,AddressView

    url(r'^$',UserInfoView.as_view(),name="user"),          #用户中心--信息页

    url(r'^order$',UserOrderView.as_view(),name="order"),  #用户--订单页

    url(r'^address$',AddressView.as_view,name="address")    #用户--地址页

2修改超链接:使用反向解析进行书写路径。在base_user_center.html中的相关链接修改如下

<li><a href="{% url "user:user" %}" {% if page == "user" %}class="active" {% endif %}>· 个人信息</a></li>

<li><a href="{% url "user:order" %}" {% if page == "order" %}class="active"{% endif %}>· 全部订单</a></li>

<li><a href="{% url "user:address" %}" {% if page == "address" %}class="active"{% endif %}>· 收货地址</a></li>

3修行选中后的超连接样式:在return的页面后面加上{"page":"XXX"}

class UserInfoView(View):

    # 用户信息页

    def get(self,request):

        return render(request,'user_center_info.html',{"page":"user"})

class UserOrderView(View):

    def get(self,request):

        return render(request,"user_center_order.html",{"page":"order"})

class AddressView(View):

    def get(self,request):

        return render(request,"user_center_site.html",{"page":"address"})

************** *七,登录装饰器和登录后页面跳转********************
******************** LoginRequiredMixin类的使用 ***************


虽然有的用户并没有登录,但是可以直接在浏览器中输入相关的链接就能跳转,这样是不安全,不合法的,该笔记使用的两种方法实现:部分页面必须要经过用户登录成功后才能进行查看,未登录的时候,会重定向到登录页面中去

方案1:使用login_required装饰器

在官方手册里面,login_required是给视图函数使用的,首先,我们我们现在不是视图函数的形式,而是class类的形式

1在二级路由user/url里面修改为

    url(r'^$',login_required(UserInfoView.as_view()),name="user"),          #用户中心--信息页

    url(r'^order$',login_required(UserOrderView.as_view()),name="order"),  #用户--订单页

    url(r'^address$',login_required(AddressView.as_view),name="address")    #用户--地址页

2清除浏览器缓存后,我们发现访问这个路径的时候就报错了

3在setting里面加上

#配置url地址

LOGIN_URL = "/user/login"

4访问127.0.0.1:8000/user/时,清空缓存,页面会自动跳转到登录页面,此时登录成功后,页面只会跳转到首页中去,

5.接下来配置,登录成功后跳转到之前想登录的页面

            if user.is_active:

                # 用户已激活

                # 记录用户的登陆状态

                login(request,user)

                # 获取登录后要跳转的地址

                next_url = request.GET.get("next",reverse("goods:index"))

                response = redirect(next_url)

=================================================================================

方案2

使用LoginRequiredMixin类

1在总项目下下新建一个utils/mixin.py

#复制官方代码

from django.contrib.auth.decorators import login_required

class LoginRequiredMixin(object):

    @classmethod

    def as_view(cls, **initkwargs):

        view = super(LoginRequiredMixin, cls).as_view(**initkwargs)

        return login_required(view)

2.在user/view里面

from utils.mixin import LoginRequiredMixin

class UserInfoView(LoginRequiredMixin,View):

    # 用户信息页

    def get(self,request):

        return render(request,'user_center_info.html',{"page":"user"})

三个class里面都加上LoginRequiredMixin

3.修改user/url为之前的

    url(r'^$',UserInfoView.as_view(),name="user"),          #用户中心--信息页

    url(r'^order$',UserOrderView.as_view(),name="order"),  #用户--订单页

    url(r'^address$',AddressView.as_view,name="address")    #用户--地址页

===========================================================


******************** 八.登录后的欢迎和退出 ***********************


request.user.is_authenticated可以在html模板中直接使用

{#顶部欢迎信息块#}

{% block header_con %}

<div class="header_con">

<div class="header">

<div class="welcome fl">欢迎来到天天生鲜!</div>

<div class="fr">

              {% if user.is_authenticated %}

<div class="login_btn fl">

欢迎您:<em>{{ user.username }}</em>

                    <span> | </span>

                    <a href="{% url "user:logout" %}">退出</a>

</div>

                {% else %}

<div class="login_btn fl">

<a href="{% url "user:login" %}">登录</a>

<span>|</span>

<a href="{% url "user:register" %}">注册</a>

</div>

                {% endif %}

<div class="user_link fl">

<span>|</span>

<a href="{% url "user:user" %}">用户中心</a>

<span>|</span>

{#  <a href="{% url "cart:show" %}">我的购物车</a>#}

<span>|</span>

<a href="{% url "user:order" %}">我的订单</a>

</div>

</div>

</div>

</div>

{% endblock header_con %}

============================================

退出

1在view里面

class LogoutView(View):

    def get(self,request):

        # 退出登录

        logout(request)

        return redirect(reverse("goods:index"))

2在user/url里面

from user.views import LogoutView

url(r'^logout$',LogoutView.as_view(),name="logout"),  #退出

3.在user/view里面导入Django自带的logout

from django.contrib.auth import logout

记得要写上logout(request),当调用logout的时候,当前请求的会话参数将会被完全清除

作用是:防止另外一个人使用相同的web浏览器登入之前的用户的会话数据


******************** 九.用户中心-地址页 *********************


一用户中心_地址页

1.编写html,user_center_site.html

{% extends "base_user_center.html" %}

{% block right_center %}

<div class="right_content clearfix">

<h3 class="common_title2">收货地址</h3>

<div class="site_con">

<dl>

                        <dt>当前地址:</dt>

                        {% if address %}

                            <dd>{{ address.addr }}({{ address.receiver }}收){{ address.phone }}</dd>

                        {% else %}

                            <dd>无默认地址</dd>

                        {% endif %}

{#  <dt>当前地址:</dt>#}

{#  <dd>北京市 海淀区 东北旺西路8号中关村软件园 (李思 收) 182****7528</dd>#}

</dl>

</div>

<h3 class="common_title2">编辑地址</h3>

<div class="site_con">

<form method="post">

                        {% csrf_token %}

<div class="form_group">

<label>收件人:</label>

<input type="text" name="receiver">

</div>

<div class="form_group form_group2">

<label>详细地址:</label>

<textarea class="site_area" name="addr"></textarea>

</div>

<div class="form_group">

<label>邮编:</label>

<input type="text" name="zip_code">

</div>

<div class="form_group">

<label>手机:</label>

<input type="text" name="phone">

</div>

<input type="submit" name="" value="提交" class="info_submit">

</form>

</div>

</div>

{% endblock right_center %}

===========================================================

2在view里面导入address,

from user.models import User,Address

===============需要把注释的代码都取消注释================

在user/view的class AddressView里面加上

    def post(self,request):

        # 地址的添加

        receiver = request.POST.get("receiver")

        addr = request.POST.get("addr")

        zip_code = request.POST.get("zip_code")

        phone = request.POST.get("phone")

        if not all([receiver,addr,phone]):

            return render(request,"user_center_site.html",{"errmsg":"数据不完整"})

        if not re.match(r'^1[3|4|5|6|7|8][0-9]{9}$',phone):

            return render(request,"user_center_site.html",{"errmsg","手机格式不正确"})

        user = request.user

        # try:

        #    address = Address.objects.get(user=user,is_default=True)

        # except Address.DoesNotExist:

        #    address = None

        address =Address.objects.get_default_address(user)

        if address:

            is_default = False

        else:

            is_default =True

        # 添加地址

        Address.objects.create(user=user,receiver=receiver,addr=addr,zip_code=zip_code,phone=phone,is_default=is_default)

        return redirect(reverse("user:address"))  #返回应答,刷新地址页面,get请求方式

=================================================================

3一进来地址页的时候需要进行判断,在user/view里面的class AddressView里面加上

    def get(self, request):

        user = request.user

        # try:

        #    address = Address.objects.get(user=user, is_default=True)  # 默认的类是models.Manage

        # except Address.DoesNotExist:

        #    address = None

        address = Address.objects.get_default_address(user)

        # 使用模板

        return render(request, "user_center_site.html", {"page": "address", "address": address})

=======================================================

=============================================================

4上面的objects对象就是Django框架给每一个模型类生成的模型管理器对象,它默认的类是models.Manage,我们来重新定义一下:

我们可以来重新定义一下:

这也是在进行优化

在user/model.py里面

class AddressManager(models.Manager):

    # 地址模型管理器

    # 1.改变原有的查询结果集

    # 2.封装方法:用户操作模型类对应的数据表(增删查改)

    def get_default_address(self,user):

        try:

            address = Address.objects.get(user=user, is_default=True)  # 默认的类是models.Manage

        except Address.DoesNotExist:

            address = None

        return address

class Address后面加上    # 自定义一个模型管理器对象

    objects = AddressManager()

5.此时使用的view的代码如上

===============================================

二用户中心_个人信息页

{% extends "base_user_center.html" %}

{% block right_center %}

<div class="right_content clearfix">

        <div class="info_con clearfix">

        <h3 class="common_title2">基本信息</h3>

                <ul class="user_info_list">

                    <li><span>用户名:</span>{{ user.username }}</li>

                    {% if address %}

                    <li><span>联系方式:</span>{{ address.phone }}</li>

                    <li><span>联系地址:</span>{{ address.addr }}</li>

                    {% else %}

                        <li><span>联系方式:</span>无默认</li>

                        <li><span>联系地址:</span>无默认</li>

                    {% endif %}

                </ul>

        </div>

        <h3 class="common_title2">最近浏览</h3>

        <div class="has_view_list">

            <ul class="goods_type_list clearfix">

                {% for goods in goods_li %}

                    <li>

                        <a href="{% url 'goods:detail' goods.id %}"><img src="{{ goods.image.url }}"></a>

                        <h4><a href="{% url 'goods:detail' goods.id %}">{{ goods.name }}</a></h4>

                        <div class="operate">

                            <span class="prize">¥{{ goods.price }}</span>

                            <span class="unit">{{ goods.price }}{{ goods.unite }}</span>

                            <a href="#" class="add_goods" title="加入购物车"></a>

                        </div>

                    </li>

                    {% empty %}

                    无历史浏览记录

                {% endfor %}

            </ul>

        </div>

    </div>

{% endblock right_center %}

=====================================================

在user/view里面

class UserInfoView(LoginRequiredMixin,View):

    # 用户中心--个人信息页

    def get(self,request):

        user = request.user

        address = Address.objects.get_default_address(user)

        return render(request, "user_center_info.html",{"page" : "user", "address" : address})

**************** *十.FastDFS分布式文件系统 ******************


FastDFS是一个开源的分布式的高性能分布式文件系统,主要功能是文件存储,文件同步和文件访问

架构包括Tracker server(跟踪服务器,作用是负载均衡和调度)和Storage server(存储服务器,作用是文件存储)。客户端请求Tracker server进行文件上传、下载,通过Tracker server调度最终由Storage server完成文件上传和下载。

client(客户端,上传和下载数据的服务器)

为了支持大容量,存储节点采用了分卷的组织方式,卷中的多台服务器起到了冗余备份和负载均衡的作用

自定义文件存储类(对Django进行二次开发:)

自定义存储相关知识点:

使用FileSystemStorage类,它会帮助我们自动的保存到MEDIA_ROOT指定的目录下。

------------------------我想要保存到FaskDFS下面,所以我需要在总的项目下创建一个目录工具utils/fdfs,用于存储自定义的一些工具类,并在setting里面进行配置

1.在fdfs/client.py下,修改工作文件日志和tracer server列表,以及端口号

2.在fdfs/storage.py下,定义一个''' fass dfs 文件存储类 '''class FDFSStorage(Storage):

3在setting里面进行配置,

设置Django的文件存储类

DEFAULT_FILE_STORAGE = "utils.fdfs.storage.FDFSStorage"

4.进行测试(找有图片的模型类,将这个模型类注册到后台admin)

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 159,117评论 4 362
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,328评论 1 293
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,839评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,007评论 0 206
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,384评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,629评论 1 219
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,880评论 2 313
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,593评论 0 198
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,313评论 1 243
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,575评论 2 246
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,066评论 1 260
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,392评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,052评论 3 236
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,082评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,844评论 0 195
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,662评论 2 274
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,575评论 2 270