Django(文件上传+分页+表单)

一、文件上传

form表单中需要添加 enctype="multipart/form-data"
1.media: 文件上传的文件
在settings.py 文件中配置:

MEDIA_URL = '/static/media/'          #媒体路径
MEDIA_ROOT = os.path.join(BASE_DIR, 'static/media')  #必须是绝对路径

static
  |-- media
       |--  uploads
               |---2019
                     |---05
                         |---文件名

#模板中如果想引用上传的文件并展示,
在模板中可以使用{{ MEDIA_URL }}
->TEMPLATES
 ->  'context_processors': [  
	   					...
	   					django.template.context_processors.media
	   					...
	   					]
	   					
在主路由中添加:
     re_path(r'^media/(?P<path>.*)$', serve, {'document_root': MEDIA_ROOT})
     
模板中使用
<img src="{{ MEDIA_URL }}{{ user.icon }}" alt="" id="icon">
2.模型: FileField(任何文件)
ImageField(只能是图片)---->继承自FileField
FileField(upload_to='表示文件上传的路径 uploads/%Y/%m')

								--->此路径是基于media_root指明的路径

ImageField(upload_to='相对路径')

使用ImageField文件上传

icon = models.ImageField(upload_to='uploads/%Y/%m/%d',default="uploads/mine1.png")

		icon = request.FILES.get('icon')  -----> 内存 的存储对象
        user.username = username
        user.email = email
        user.mobile = mobile
        user.icon = icon  # ImageField(upload_to='')
        user.save()

        user.icon   ----> 不是存储字符串,ImageField
        user.icon.name  ----> 字符串值

二、系统默认用户的继承使用:

1.必须继承AbstractUser ----》auth_user ----> 系统用户
class UserProfile(AbstractUser):
    mobile = models.CharField(max_length=11, verbose_name='手机号码', unique=True)
    icon = models.ImageField(upload_to='uploads/%Y/%m/%d')

    class Meta:
        db_table = 'userprofile'
        verbose_name = '用户表'
        verbose_name_plural = verbose_name
2.必须修改settings.py
  # 如果用户继承了AbstractUser,修改auth_user的模型
  AUTH_USER_MODEL = 'user.UserProfile'
3.然后执行迁移和同步
authenticate() (认证)---》user =====》  login(request,user)---->  session保存和request.user赋值

logout()----》清空session和cookie,将request.user设置成匿名的User()

is_authenticated() ----> 判断用户是否被认证   request.user.is_authenticated()

三、forms 表单:

问题:使用ModelForm好像按照注册搞,不能输入数据库已存在的用户名??

Django会处理涉及表单的三个不同部分:
    准备并重组数据,以便下一步的渲染
    为数据创建HTML 表单
    接收并处理客户端提交的表单及数据
1.Form 和 ModelForm
Form比较灵活需要自己定义各个要验证的字段

Form使用:
class UserRegisterForm(Form):
    username = forms.CharField(max_length=50, min_length=6, error_messages={'min_length': '用户名长度至少6位', }, label='用户名')
    email = forms.EmailField(required=True, error_messages={'required': '必须填写邮箱信息'}, label='邮箱')
    mobile = forms.CharField(required=True, error_messages={'required': '必须填写手机号码'}, label='手机')
    password = forms.CharField(required=True, error_messages={'required': '必须填写密码'}, label='密码',widget=forms.widgets.PasswordInput)
                               #widget插件,密码隐藏
ModelForm是跟Model有关的,model的字段可以直接引用过来。

ModelForm使用:
class RegisterForm(ModelForm):
    repassword = forms.CharField(required=True, error_messages={'required': '必须填写确认密码'}, label='确认密码', widget=forms.widgets.PasswordInput)

    class Meta:
        model = UserProfile
        fields = ['username', 'email', 'mobile', 'password']  ---->可以自己添加需要验证的字段
        # fields = '__all__'   ----》 如果是model中的所有字段都需要验证可以使用__all__
        # exclude = ['first_name','date_joined','last_name']   -----> 使用exclude排除不需要验证的部分

2.定义一些指定字段的专门验证:
def clean_username(self):
        username = self.cleaned_data.get('username')
        result = re.match(r'[a-zA-Z]\w{5,}', username)
        if not result:
            raise ValidationError('用户名必须字母开头')
        return username

或者

  def clean_username(self):
        username = self.cleaned_data.get('username')
        if not UserProfile.objects.filter(username=username).exists():
            raise ValidationError('用户名不存在')
        return username

或者验证密码与确认密码是否一致

    def clean_password(self):
         repassword = self.cleaned_data.get('repassword')
         password = self.cleaned_data.get('psssword')
         if password != repassword:
              raise ValidationError('密码不一致')
         return password
         
         
在views中接收用rform.is_valid()
3.密码加密和检查密码:
 check_password(原文密码,加密密码) -----》返回结果是boolean
 make_password(原文密码)  -----》加密密码返回结果是加密后的密码
cookies实现登录退出
https://www.cnblogs.com/banshaohuan/p/9493021.html
https://blog.csdn.net/weixin_33918357/article/details/85629371?utm_medium=distribute.pc_relevant_t0.none-task-blog-BlogCommendFromBaidu-1.control&depth_1-utm_source=distribute.pc_relevant_t0.none-task-blog-BlogCommendFromBaidu-1.control
4.session的使用:
  request.session  request里面的一个属性,而且是字典类型

  设置session的值:
    request.session['key']=value

  取值:
    value = request.session.get(key)

  清除session:
    request.session.clear()  # 删除字典
    request.session.flush()  # 删除django_session + cookie +字典
    del request.session[key] # 删除指定的key
5.继承abstractuser的用户
from django.contrib.auth import logout,login,authenticate

authenticate+login  先使用authenticate 进行用户的数据库查询判断,如果有则返回用户对象
	
 login(request,user)   ---->类似session  只不过: request.user=user
 						#将用户对象保存在底层的request中

 request.user.is_authenticated  是否是认证过的用户返回值是True,False
 
 
 两种方式登录
 username = lform.cleaned_data.get('username')
            password = lform.cleaned_data.get('password')

            # 方式一
            # user = UserProfile.objects.filter(username=username).first()
            # print(password, user.password, make_password(password))
            # flag = check_password(password, user.password)
            # if flag:
            #     request.session['username'] = username

            # 方式二
            user=authenticate(username=username,password=password)【必须是明文密码,从数据库中取出来加密的不可以】
            if user:
                login(request,user)

                return redirect(reverse('index'))
            return render(request, 'user/login.html', context={'msg': "用户名或密码有误"})
            
            
 两种方式注销:
 # 方式一:
    # request.session.flush()

    # 方式二:
    logout(request)
 
 
 两种方式验证是否登录:
         {#    方式一#}
{#        {% if request.session.username %}#}
{#            欢迎!<a href="">{{ request.session.username }}</a>&nbsp;&nbsp;&nbsp;&nbsp;#}
{#            <a href="{% url 'user:logout' %}">注销</a>#}


                {#    方式二#}
        {% if request.user.is_authenticated %}
            欢迎!<a href="">{{ request.user.username }}</a>&nbsp;&nbsp;&nbsp;&nbsp;
            <a href="{% url 'user:logout' %}">注销</a>

        {% else %}
            <a href="{% url 'user:login' %}">登录</a>&nbsp;&nbsp;&nbsp;&nbsp;
            <a href="{% url 'user:register' %}">注册</a>

        {% endif %}

四、发送手机验证码:第三方

写账号密码登陆和验证码登陆的切换页

使用网易云信:
https://dev.yunxin.163.com/docs/product/%E7%9F%AD%E4%BF%A1/%E7%9F%AD%E4%BF%A1%E6%8E%A5%E5%8F%A3%E6%8C%87%E5%8D%97

模拟浏览器发送请求:
pip install requests
1.流程
发送验证码:
---》 send_code ----> ajax ----》sendcode  + mobile
-----》后台:mobile  -----》使用requests(浏览器)
2.定义工具类
#作用就是向网易云信发送请求,帮助后台发送短信息给客户
def util_sendmsg(mobile):
    url ='https://api.netease.im/sms/' ---->访问网易云信的url地址
    data={'mobile':你的手机号码}  ----
    AppKey =‘’   #开发者平台发布的
     Nonce=‘’     #随机数
     CurTime=str(time)     #时间戳
     AppSecret=''
     content=AppSecrect+Nonce+CurTime
     CheckSum=hashlib.sha1(appsecret+Nonce+CurTime)
    headers={} -----》4 部分
    response = requests.post(url,data,headers)


    str = response.Text
    json = json.loads(str)

    json.code
    json.obj   ----> 发送的验证码

	保存到session

五、生成图形验证码(使用插件)

文档地址:
https://django-simple-captcha.readthedocs.io/en/latest/usage.html
1.插件安装步骤
1.pip install  django-simple-captcha

2.Add captcha to the INSTALLED_APPS in your settings.py

3.Run python manage.py migrate------》数据库自动添加表(captcha-captchastore)

4。Add an entry to your urls.py:
	re_path(r'^captcha/',include('captcha.urls'))	

2.使用验证码插件步骤
Form使用
1.# 验证码captcha的Form
class CaptchaTestForm(forms.Form):
    email = EmailField(required=True, error_messages={'required': '必须填写邮箱'},label='邮箱')
    captcha = CaptchaField()
    
产生的图形就是一张图片。img+hidden

2.使用CaptchaTestForm渲染页面:
 if request.method == 'GET':
        form = CaptchaTestForm()
        return render(request, 'user/forget_pwd.html', context={'form': form})

3.页面中使用captcha:
<div class="w3layouts-main">
                <p>{{ msg }} {{ errors }}</p>
                <form action="{% url 'user:forget_pwd' %}" method="post"> {% csrf_token %}
                    {{ form.email }}
                    {{ form.captcha }}
                    <input type="submit" value="找回密码">
                </form>
            </div>
3.刷新验证
$('.captcha').click(function(){
            var img= $(this);
           $.getJSON('/captcha/refresh',function(data){
               console.log(data)
               img.attr('src',data['image_url']); #attr是一个属性
               $('#id_captcha_0').val(data['key'])
           })
        });

4.验证验证码是否正确
$('#id_captcha_1').blur(function(){
              var $this = $(this);
              var key = $('#id_captcha_0').val();
              var code = $(this).val();

              $.getJSON('{% url 'user:valide_code' %}',{key:key,code:code},function(data){
                    console.log(data)

                  if(data.status==1){
                    $this.after('<span>验证码正确</span>')
                  }else{
                    $this.after('<span>验证码错误</span>')
                  }
              })
          })
  
  
路由:valide_code

# 定义一个路由验证验证码
def valide_code(request):
    if request.is_ajax():
        key = request.GET.get('key')
        code = request.GET.get('code')
        # CaptchaStore 模型对象
        captche = CaptchaStore.objects.filter(hashkey=key).first()
        if captche.response == code.lower():
            # 正确
            data = {'status': 1}
        else:
            # 错误的
            data = {'status': 0}
        return JsonResponse(data)

六、发送邮件

1.邮件的配置
在settings.py中配置:
		EMAIL_HOST = 'smtp.126.com'
        EMAIL_HOST_USER = 'student1902@126.com'
        EMAIL_HOST_PASSWORD = 'student1902'   #邮箱的授权码
        EMAIL_PORT = 25
        EMAIL_USE_TLS = True
        EMAIL_USE_SSL = False   # 126,QQ: 465   163:454
2.调用方法
send_mail(subject,message,from,to_list)

发送成功就是1  否则0

message与html_message的区别

     ran_code = uuid.uuid4()
     ran_code = str(ran_code)

    ran_code =ran_code.replace('-','')
    request.session[ran_code] = user.id
3.进行激活
密码和确认密码+ 隐藏表单域(code)

        code = request.POST.get('code')
        uid = request.session.get(code)
        user = UserProfile.objects.get(pk=uid)
        # 获取密码
        pwd = request.POST.get('password')
        repwd = request.POST.get('repassword')
        if pwd == repwd and user:
            pwd = make_password(pwd)
            user.password = pwd
            user.save()
            return render(request, 'user/update_pwd.html', context={'msg':'用户密码更新成功!'})
        else:
            return render(request, 'user/update_pwd.html', context={'msg': '更新失败!'})

七、中间件(类似flask 钩子函数)

https://www.cnblogs.com/sui776265233/p/9664642.html
1.中间件应用场景
由于中间件工作在 视图函数执行前、执行后适合所有的请求/一部分请求做批量处理。
    1、做IP限制
    放在中间件类的列表中,阻止某些IP访问了;
    2.URL访问过滤
    如果用户访问的是login视图(放过)
    如果访问其他视图(需要检测是不是有session已经有了放行,没有返回login),这样就省得在 多个视图函数上写装饰器了!
    3、缓存(CDN)
    客户端请求来了,中间件去缓存看看有没有数据,有直接返回给用户,没有再去逻辑层 执行视图函数
2.进行用户的登录验证
  • 中间件进行用户的登录验证
步骤:
     1. middreware文件夹----》 xxxmiddleware.py ---->定义类继承MiddlewareMixin

     2. 重写:

     如果仅仅是对请求做处理则重写的方法名:process_request(self,request)

     3. 参数request:参数request是请求对象
        request.path
        request.method
        request.is_ajax()
        request.META.get('REMOTE_ADDR')

        if path in login_list:
            print(request.user)  # AnonymousUser  未登录
            print(type(request.user))
            print(request.user.username)   # 认为就是用户登录的对象
            if not request.user.is_authenticated:
                return redirect(reverse('user:login'))
  • 使用装饰器进行用户的登录验证
@login_required  前提(要验证的用户必须是继承自AbstractUser)

      login(request,user)

      request.user.is_authenticated

        @login_required
        def user_center(request):
            return HttpResponse('用户中心')

 改变页面跳转需要在settings.py文件中设置:
 	LOGIN_URL = '/user/login'
        # 添加一个登陆路由  结合  @login_required
        
3.中间件的默认可以自定义的函数
  • Request预处理函数: process_request(self, request)
    这个方法的调用时机在Django接收到request之后,但仍未解析URL以确定应当运行的视图函数。Django向它传入相应的Request对象,以便在方法中修改。
        如果返回None,Django将继续处理这个request,执行后续的中间件, 然后调用相应的 view。
        如果返回HttpResponse对象,Django将不再执行任何除了process_response以外其它的中间件以及相应的view,Django将立即返回该HttpResponse。
    
  • View预处理函数: process_view(self, request, callback)
    callback_args,callback_kwargs)
        这个方法的调用时机在 Django 执行完 request 预处理函数并确定待执行的 view (即callback参数)之后,但在 view 函数实际执行之前。
        request:HttpRequest 对象。
        callback:Django将调用的处理request的python函数. 这是实际的函数对象本身, 而不是字符串表述的函数名。
        args:将传入view的位置参数列表,但不包括request参数(它通常是传入view的第一个参数)。
        kwargs:将传入view的关键字参数字典。
        process_view() 应当返回None或 HttpResponse 对象。如果返回 None, Django将继续处理这个request ,执行后续的中间件, 然后调用相应的view。
        如果返回 HttpResponse 对象,Django 将不再执行任何其它的中间件(不论种类)以及相应的view,Django将立即返回。
    
  • Template模版渲染函数:process_template_response()
    默认不执行,只有在视图函数的返回结果对象中有render方法才会执行,并把对象的render方法的返回值返回给用户
        (注意不返回视图函数的return的结果了,而是返回视图函数 return值(对象)中rende方法的结果)
    
  • Exception后处理函数:process_exception(self, request, exception)
    这个方法只有在 request 处理过程中出了问题并且view 函数抛出了一个未捕获的异常时才会被调用。这个钩子可以用来发送错误通知,将现场相关信息输出到日志文件,或者甚至尝试从错误中自动恢复。
        这个函数的参数除了一贯的request对象之外,还包括view函数抛出的实际的异常对象exception 。
        process_exception() 应当返回None或HttpResponse对象。
        如果返回None,Django将用框架内置的异常处理机制继续处理相应request。
        如果返回HttpResponse对象,Django将使用该response对象,而短路框架内置的异常处理机制。
    
  • Response后处理函数:process_response(self, request, response)
    这个方法的调用时机在 Django 执行 view 函数并生成 response 之后。
        该处理器能修改response 的内容;一个常见的用途是内容压缩,如gzip所请求的HTML页面。
        这个方法的参数相当直观:request是request对象,而response则是从view中返回的response对象。
        process_response() 必须返回 HttpResponse 对象. 这个 response 对象可以是传入函数的那一个原始对象(通常已被修改),也可以是全新生成的
    

九、云存储(七牛云)

1.注册用户
2.创建存储空间,测试域名(30天)
3.文档中心:https://developer.qiniu.com/kodo/sdk/1242/python
4.在项目中使用:
#上传图片到七牛云

def upload_image(storeobj):
    # 只要注册用户就会有默认的access_key,secret_key
    access_key = '1fXvG9wkbN7AgRUG6usHDcRP5Bb85apcovRAIITP'
    secret_key = 'Aqf1lPAmUG72EdZJ7PxKtWHfWDYNdUycZP1TaAIN'

    # 构建鉴权对象
    q = Auth(access_key, secret_key)

    # 要上传的空间
    bucket_name = 'myblog'

    # 上传后保存的文件名
    key = storeobj.name

    # 生成上传 Token,可以指定过期时间等
    token = q.upload_token(bucket_name, key, 3600)

    # 要上传文件的本地路径
    # localfile = os.path.join(MEDIA_ROOT, imagepath)  # 本地图片路径
    ret, info = put_data(token, key, storeobj.read())   # 第三个参数是二进制流
    ret,info = put_file(token,key,localfile) # 第三个参数是文件的路径

    print(ret, info)
    filename = ret.get('key')
    save_path = 'http://pr67kkhq9.bkt.clouddn.com/'+filename
    return save_path

接口:
模板:给用户看的

model  模型

view  视图 +  url路由    ----》 类视图

url:------》 json  ----》前端

app(vue) + 后端  --------》 前后端分离

十、xadmin与admin

https://xadmin.readthedocs.io/en/docs-chinese/quickstart.html#id1

git里下载zip并解压
cmd进入requirements.txt文件夹
workon 切换到虚拟环境
pip install -r requirements.txt
将解压后文件夹中的xadmin文件夹复制到项目下
使用:
https://blog.csdn.net/xinyan233/article/details/80399534
xadmin就是admin的升级版,样式,操作方便
1.xadmin的安装
不推荐:pip install xadmin

推荐源码安装:
  xxxdjango2.0-xadmin.zip
       |--django2.0-xadmin
            |--- xadmin
            |---requirements.txt
            
         	pip install -r    requirements.txt
         	
         	xadmin复制到项目下
2.相关配置
  • 配置settings.py
    INSTALLED_APPS=[
    		...
            'xadmin',
            'crispy_forms'
          ]
    
  • 配置主路由
    主路由:
           path('xadmin/',xadmin.site.urls)
    
  • 迁移同步
    python manage.py makemigrations
    python manage.py migrate
    
  • 注册models
    你的app
             |--admin.py
             |--xadmin.py  -----> xadmin.site.register(xxxModel)
             
             
             xadmin.site.register(Article,ArticleAdmin)
        	 xadmin.site.register(Tag)
    
3.相关设置
  • article/adminx.py
     class ArticleAdmin(object):
        list_display = ['title', 'click_num', 'love_num', 'user']
        											#显示自己想看的列
        search_fields= ['title','id']			#用于检索的列
        list_editable= ['click_num','love_num']  #可编辑的列
        list_filter=['date','user']              #可用于过滤的列
    
  • acticle/apps.py
    class ArticleConfig(AppConfig):
            name = 'article'
            verbose_name = '文章操作'    
    
  • init.py
    default_app_config = 'article.apps.ArticleConfig'
    
  • user/adminx.py:主题设置
    class BaseSettings(object):
        enable_themes = True
        use_bootswatch = True
    
    
    class GlobalSettings(object):
        site_title = '博客后台管理'
        site_footer = '达达的博客公司'
    
    # 注册
    xadmin.site.register(views.BaseAdminView, BaseSettings)
    xadmin.site.register(views.CommAdminView, GlobalSettings)
    

十一、分页:Paginator,Page

  • 分页器
paginator = Paginator(articles, 3)  # Paginator(对象列表,每页几条记录)
  • 分页器属性
    	print(paginator.count)  # 总的条目数  总的记录数
        print(paginator.num_pages)  # 可以分页的数量  总的页码数
        print(paginator.page_range)  # 页面的范围
    
  • 方法: get_page()
     page = request.GET.get('page',1)
     page = paginator.get_page(page)   # 返回的是page对象   参数就是页码数
    
  • 方法
     page.has_next()  # 有没有下一页
     page.has_previous()  # 判断是否存在前一页
     page.next_page_number() # 获取下一页的页码数
     page.previous_page_number() # 获取前一页的页码数
    
  • 属性:
    object_list   当前页的所有对象
    number       当前的页码数
    paginator     分页器对象
    

十二、富文本:ckeditor

https://www.jianshu.com/p/f965853ecba1
https://www.cnblogs.com/ianduin/p/7732983.html
https://zhuanlan.zhihu.com/p/78705834
  • 安装
    pip install django-ckeditor
    
  • 注册应用
    在settin.py中添加
    
            INSTALLED_APPS = [
                 ...
                'ckeditor',           #注册应用,添加ckeditor富文本编辑器
                ‘ckeditor_uploader',	#文件上传需要
            ]       
    
  • 文件上传配置
    配置MEDIA_URL和MEDIA_ROOT, 上传路径的根目录就是以MEDIA_ROOT
    
    CKEDITOR_UPLOAD_PATH = "uploads/",
    
  • 设置urls.py路径
     re_path(r'^ckeditor/', include('ckeditor_uploader.urls')),
    
  • 在models.py中设置
    content=RichTextUploadingField(verbose_name=’内容‘)
    
    class Article(models.Model):
        title = models.CharField(max_length=100, verbose_name='标题')
        desc = models.CharField(max_length=256, verbose_name='简介')
        content = RichTextUploadingField(verbose_name='内容')
    
  • 迁移和同步
  • 访问:xadmin后台

十三、富文本:ueditor

1、安装方法

* 将github整个源码包下载下来
    git clone https://github.com/cooljacket/DjangoUeditor
* 然后,假设你的python安装目录是PYTHON_ROOT(我的是D:\soft\py3.5),直接复制DjangoUeditor文件夹到PYTHON_ROOT\Lib\site-packages\下就好了,比如我的就是D:\soft\py3.5\Lib\site-packages\
* 之所以不使用原来的setup.py来安装,是因为我发现,用它的setup脚本会改动代码成原来的样子,也没去深究为什么,最后发现只需要直接复制过去就好了,而且卸载也很方便,直接删除就好了,没有什么依赖项和设置!

2.在Django中安装DjangoUeditor

在INSTALL_APPS里面增加DjangoUeditor app,如下:
    INSTALLED_APPS = (
        #........
        'DjangoUeditor',
    )

3、配置urls

url(r'^ueditor/',include('DjangoUeditor.urls' )),

4、在models中的使用

from DjangoUeditor.models import UEditorField
    class Blog(models.Model):
        Name=models.CharField(,max_length=100,blank=True)
        Content=UEditorField(u'内容   ',width=600, height=300, toolbars="full", imagePath="", filePath="", upload_settings={"imageMaxSize":1204000},
                 settings={},command=None,event_handler=myEventHander(),blank=True)
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值