• django搭建BBS-表单创建&注册


    django搭建BBS-表单创建&注册

    0824自我总结

    文件结构

    • app 接口

      • migrations
      • __inint__.py
      • admin.py 管理员页面注册表单用
      • apps.py
      • bbsform.py form组件相关设置
      • models.py 模型存放
      • tests.py
      • views.py 业务逻辑
    • avatar 图片文件存储

    • BBS 项目名称以及路由存放

      • __inint__.py
      • settings.py
      • urls.py
      • wsgi.py
    • static

      • bootstrap-3.3.7-dist bootstrap文件网上下载的
      • jquery-3.4.1.min.js jq文件
    • templates 页面文件存放

    一.django相关设置

    settings.py

    """
    Django settings for BBS project.
    
    Generated by 'django-admin startproject' using Django 1.11.22.
    
    For more information on this file, see
    https://docs.djangoproject.com/en/1.11/topics/settings/
    
    For the full list of settings and their values, see
    https://docs.djangoproject.com/en/1.11/ref/settings/
    """
    
    import os
    
    # Build paths inside the project like this: os.path.join(BASE_DIR, ...)
    BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
    
    
    # Quick-start development settings - unsuitable for production
    # See https://docs.djangoproject.com/en/1.11/howto/deployment/checklist/
    
    # SECURITY WARNING: keep the secret key used in production secret!
    SECRET_KEY = 's0x+v@gqeoxs4ruj58cq5&*5#7on_h$n4-$hwb3cr&h(@qcmoc'
    
    # SECURITY WARNING: don't run with debug turned on in production!
    DEBUG = True
    
    ALLOWED_HOSTS = []
    
    
    # Application definition
    
    INSTALLED_APPS = [
        'django.contrib.admin',
        'django.contrib.auth',
        'django.contrib.contenttypes',
        'django.contrib.sessions',
        'django.contrib.messages',
        'django.contrib.staticfiles',
        'app.apps.AppConfig',
    ]
    
    MIDDLEWARE = [
        'django.middleware.security.SecurityMiddleware',
        'django.contrib.sessions.middleware.SessionMiddleware',
        'django.middleware.common.CommonMiddleware',
        'django.middleware.csrf.CsrfViewMiddleware',
        'django.contrib.auth.middleware.AuthenticationMiddleware',
        'django.contrib.messages.middleware.MessageMiddleware',
        'django.middleware.clickjacking.XFrameOptionsMiddleware',
    ]
    
    ROOT_URLCONF = 'BBS.urls'
    
    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',
                ],
            },
        },
    ]
    
    WSGI_APPLICATION = 'BBS.wsgi.application'
    
    
    # Database
    # https://docs.djangoproject.com/en/1.11/ref/settings/#databases
    
    DATABASES = {
        'default': {
            'ENGINE': 'django.db.backends.sqlite3',
            'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
        }
    }
    
    
    # Password validation
    # https://docs.djangoproject.com/en/1.11/ref/settings/#auth-password-validators
    
    AUTH_PASSWORD_VALIDATORS = [
        {
            'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator',
        },
        {
            'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator',
        },
        {
            'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator',
        },
        {
            'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator',
        },
    ]
    
    
    # Internationalization
    # https://docs.djangoproject.com/en/1.11/topics/i18n/
    
    LANGUAGE_CODE = 'en-us'
    
    TIME_ZONE = 'UTC'
    
    USE_I18N = True
    
    USE_L10N = True
    
    USE_TZ = True
    
    
    # Static files (CSS, JavaScript, Images)
    # https://docs.djangoproject.com/en/1.11/howto/static-files/
    
    STATIC_URL = '/static/'
    STATICFILES_DIRS=(
        os.path.join(BASE_DIR,'static'),
    )
    
    #因为我创建模型的时候用到了user的类
    AUTH_USER_MODEL='app.Userinfo'
    

    二.模型的创建&管理页面注册

    models.py

    from django.db import models
    from django.contrib.auth.models import AbstractUser
    
    
    class UserInfo(AbstractUser):
        nid = models.AutoField(primary_key=True)
        # 头像:FileField文件(varchar类型),default:默认值,upload_to上传的路径
        avatar = models.FileField(upload_to='avatar/', default='avatar/default.png')
        #跟blog表一对一
        #OneToOneField本质就是ForeignKey,只不过有个唯一性约束
        blog = models.OneToOneField(to='Blog', to_field='nid',null=True)
        # blog = models.ForeignKey(to='Blog', to_field='nid',null=True,unique=True)
    
        class Meta:
            # db_table='xxxx'
            # 在admin中显示的表名
            verbose_name='用户表'
            #去掉  用户表  后的s
            verbose_name_plural = verbose_name
    
    class Blog(models.Model):
        nid = models.AutoField(primary_key=True)
        #站点名称
        title = models.CharField(max_length=64)
        #站点副标题
        site_name = models.CharField(max_length=32)
        #不同人不同主题
        theme = models.CharField(max_length=64)
        def __str__(self):
            return self.site_name
    #分类表
    class Category(models.Model):
        nid = models.AutoField(primary_key=True)
        #分类名称
        title = models.CharField(max_length=64)
        #跟博客是一对多的关系,关联字段写在多的一方
        #to  是跟哪个表关联   to_field跟表中的哪个字段做关联, null=True 表示可以为空
        blog = models.ForeignKey(to='Blog', to_field='nid', null=True)
        def __str__(self):
            return self.title
    
    class Tag(models.Model):
        nid = models.AutoField(primary_key=True)
        #标签名字
        title = models.CharField(max_length=64)
        # 跟博客是一对多的关系,关联字段写在多的一方
        blog = models.ForeignKey(to='Blog', to_field='nid', null=True)
        def __str__(self):
            return self.title
    
    class Article(models.Model):
        nid = models.AutoField(primary_key=True)
        #verbose_name在admin中显示该字段的中文
        title = models.CharField(max_length=64,verbose_name='文章标题')
        #文章摘要
        desc = models.CharField(max_length=255)
        #文章内容  大文本
        content = models.TextField()
        #DateTimeField 年月日时分秒(注意跟datafield的区别)
        #auto_now_add=True:插入数据会存入当前时间
        #auto_now=True  修改数据会存入当前时间
        create_time = models.DateTimeField(auto_now_add=True)
        commit_num=models.IntegerField(default=0)
        up_num=models.IntegerField(default=0)
        down_num=models.IntegerField(default=0)
    #一对多的关系
        blog = models.ForeignKey(to='Blog', to_field='nid', null=True)
        # 一对多的关系
        category = models.ForeignKey(to='Category', to_field='nid', null=True)
        #多对多关系  through_fields  不能写反了:
        tag = models.ManyToManyField(to='Tag', through='ArticleTOTag', through_fields=('article', 'tag'))
        def __str__(self):
            return self.title+'----'+self.blog.userinfo.username
    
    class ArticleTOTag(models.Model):
        nid = models.AutoField(primary_key=True)
        article = models.ForeignKey(to='Article', to_field='nid')
        tag = models.ForeignKey(to='Tag', to_field='nid')
    
    class Commit(models.Model):
        #谁对那篇文章评论了什么内容
        nid = models.AutoField(primary_key=True)
        user = models.ForeignKey(to='UserInfo', to_field='nid')
        article = models.ForeignKey(to='Article', to_field='nid')
        content = models.CharField(max_length=255)
        #评论时间
        create_time = models.DateTimeField(auto_now_add=True)
        #自关联()
        parent = models.ForeignKey(to='self', to_field='nid',null=True,blank=True)
    
    class UpAndDown(models.Model):
        #谁对那篇文章点赞或点踩
        nid = models.AutoField(primary_key=True)
        user = models.ForeignKey(to='UserInfo', to_field='nid')
        article = models.ForeignKey(to='Article', to_field='nid')
        #布尔类型,本质也还是0和1
        is_up = models.BooleanField()
    
        class Meta:
            #联合唯一,一个用户只能给一片文章点赞或点踩
            unique_together = (('user', 'article'),)
    

    admin.py

    from django.contrib import admin
    
    # Register your models here.
    #先导入模型
    from app import models
    
    #注册表
    admin.site.register(models.UserInfo)
    admin.site.register(models.Blog)
    admin.site.register(models.Category)
    admin.site.register(models.Tag)
    admin.site.register(models.Article)
    admin.site.register(models.ArticleTOTag)
    admin.site.register(models.Commit)
    admin.site.register(models.UpAndDown)
    
    

    三.路由

    urls.py

    from django.conf.urls import url
    from django.contrib import admin
    #主路由导入视图内函数
    from app import views
    urlpatterns = [
        url(r'^admin/', admin.site.urls),
        url(r'^register/', views.register),
    ]
    

    四.form组件

    
    from django import forms
    from django.forms import widgets
    
    from django.core.exceptions import ValidationError
    
    from app import models
    #写一个类,继承Form  没有头像校验的字段
    class Register(forms.Form):
        username=forms.CharField(max_length=18,min_length=3,label="用户名",
                             error_messages={'max_length':'太长了',
                                             'min_length':'太短了',
                                             'required':'不能为空'},
                                widget=widgets.TextInput(attrs={'class':'form-control'}),
                             )
        password=forms.CharField(max_length=18,min_length=3,label="密码",
                             error_messages={'max_length':'太长了',
                                             'min_length':'太短了',
                                             'required':'不能为空'},
                                widget=widgets.PasswordInput(attrs={'class':'form-control'}),
                             )
        re_pwd=forms.CharField(max_length=18,min_length=3,label="确认密码",
                             error_messages={'max_length':'太长了',
                                             'min_length':'太短了',
                                             'required':'不能为空'},
                                widget=widgets.PasswordInput(attrs={'class':'form-control'}),
                             )
        email=forms.EmailField(max_length=18,min_length=3,label="邮箱",
                             error_messages={'max_length':'太长了',
                                             'min_length':'太短了',
                                             'required':'不能为空'},
                                widget=widgets.EmailInput(attrs={'class':'form-control'}),
                             )
        #局部钩子,局部校验
        def clean_username(self):
            #取出name对应的值
            name=self.cleaned_data.get('username')
            # if name.startswith('sb'):
            #     #校验不通过,抛异常
            #     raise ValidationError('不能以sb开头')
            #     #校验通过,直接return name值
            # else:
            #     return name
            user=models.UserInfo.objects.filter(username=name).first()
            if user:
                #用户存在,抛异常
                raise ValidationError('用户已经存在')
            else:
                return name
        #全局钩子,全局校验
    
        def clean(self):
            pwd=self.cleaned_data.get('password')
            r_pwd=self.cleaned_data.get('re_pwd')
            if pwd==r_pwd:
                #校验通过,返回清洗后的数据
                return self.cleaned_data
            else:
                #校验不通过,抛异常
                raise ValidationError('两次密码不一致')
    

    五.业务逻辑&html页面

    1.业务逻辑

    views.py

    from django.shortcuts import render,HttpResponse,redirect
    from django.http import JsonResponse
    #Image导入
    #ImageDraw在图片上写字
    #ImageFont 写字的格式
    from PIL import Image,ImageDraw,ImageFont
    import random
    # 相当于把文件以byte格式存到内存中
    from io import BytesIO
    
    from django.contrib import auth
    
    from app.bbsforms import Register
    from app import models
    
    from django.db.models import Count
    from django.db.models.functions import TruncMonth
    from django.db.models import F
    
    
    
    
    
    # Create your views here.
    def register(request):
        if request.method=='GET':
            form=Register()
            return render(request,'register.html',{'form':form})
        elif request.is_ajax():
            response={'code':100,'msg':None}
            form = Register(request.POST)
            if form.is_valid():
                #校验通过的数据
                clean_data=form.cleaned_data
                #把re_pwd剔除
                clean_data.pop('re_pwd')
                #取出头像
                avatar=request.FILES.get('avatar')
                if avatar:
                    #因为用的是FileField,只需要把文件对象赋值给avatar字段,自动做保存
                    clean_data['avatar']=avatar
                user=models.UserInfo.objects.create_user(**clean_data)
                if user:
                    response['msg'] = '创建成功'
                else:
                    response['code'] = 103
                    # 把校验不通过的数据返回
                    response['msg'] = '创建失败'
            else:
                response['code']=101
                #把校验不通过的数据返回
                response['msg']=form.errors
                print(type(form.errors))
            return JsonResponse(response,safe=False)
    

    2.网页

    常见的几条函数的封装

    jq.html

    <script src="/static/jquery-3.4.1.min.js"></script>
    

    bootstrap.html

    <link rel="stylesheet" href='/static/bootstrap-3.3.7-dist/css/bootstrap.min.css'>
    <script src="/static/bootstrap-3.3.7-dist/js/bootstrap.min.js"></script>
    

    主视图

    register.html

    <!DOCTYPE html>
    <html>
    <head>
        <meta charset="utf-8">
        <title>注册</title>
        {% include 'bootstrap.html' %}
    </head>
    <body>
    <div class="container-fluid">
        <div class="row">
            <div class="col-md-6 col-md-offset-3">
    
                <h1>注册</h1>
                <form id="my_form">
                    {% csrf_token %}
                    {% for foo in form %}
                        <div class="form-group">
                            {#foo.auto_id   就是foo生成的input的id#}
                            <label for="{{ foo.auto_id }}">{{ foo.label }}</label>
                            {{ foo }} <span style="color: red" class="error pull-right"></span>
                        </div>
    
                    {% endfor %}
                    <div class="form-group">
                        <label for="id_file">头像
                            <img src="/static/img/default.png" width="80" height="80" style="margin-left: 20px" id="id_img">
                        </label>
    
    
                        <input type="file" name="file" id="id_file" style="display: none">
                    </div>
                    <input type="button" class="btn btn-success" value="提交" id="id_submit">
                </form>
            </div>
        </div>
    </div>
    </body>
    {% include 'jq.html' %}
    <script>
        //当该控件发生变化,响应该事件
        $("#id_file").change(function () {
            //alert(1)
            //取到文件对象
            var file = $("#id_file")[0].files[0]
            //放到img控件上,借助于filereader 中间的东西,文件阅读器
            //生成一个文件阅读器对象赋值给filereader
            var filereader = new FileReader()
            //把文件读到filereader对象中
            //读文件需要时间,需要文件读完再去操作img
            filereader.readAsDataURL(file)
    
            filereader.onload = function () {
                $("#id_img").attr('src', filereader.result)
            }
    
        })
        $("#id_submit").click(function () {
    
            //ajax 上传文件
    
    
            var formdata = new FormData()
            //一个一个往里添加,稍微复杂,用简便方法
            // formdata.append('name',$("#id_name").val())
            // formdata.append('pwd',$("#id_pwd").val())
    
            //简便方法
            //form 对象的serializeArray,它会把form中的数据包装到一个对象中(不包含文件)
            var my_form_data = $("#my_form").serializeArray()
            //console.log(typeof my_form_data)
            //console.log(my_form_data)
            //jq的循环,传两个参数,第一个是要循环的对象,第二个参数是一个匿名函数
            $.each(my_form_data, function (k, v) {
                {#console.log(k)#}
                {#console.log(v)#}
                formdata.append(v.name, v.value)
            })
            formdata.append('avatar', $("#id_file")[0].files[0])
    
    
            $.ajax({
                url: '/register/',
                type: 'post',
                processData: false, //告诉jQuery不要去处理发送的数据
                contentType: false,// 告诉jQuery不要去设置Content-Type请求头
                data: formdata,
                success: function (data) {
                    //console.log(data)
                    if(data.code==100){
                        location.href='/login/'
                    }else if(data.code==101){
                        $.each(data.msg,function (k,v) {
                            console.log(k)
                            console.log(v)
                            $("#id_"+k).next().html(v[0])
                            if(k=='__all__'){
                                $("#id_re_pwd").next().html(v[0])
                            }
    
                        })
    
                    }
                    //定时器
                    setTimeout(function () {
                        $(".error").html("")
                    },3000)
                }
    
    
            })
        })
    
    
    </script>
    </html>
    
  • 相关阅读:
    【转帖】asp.net mvc与webform区别
    [学习jquery]深入了解jquery(1)jquery对象
    windows ce 4.2/5.0/6.0/windows mobile设备直接连接PC端的SQLserver
    dotNet dispose 和 close的区别
    简易快速理解 ERP
    互联网盈利模式77种创新 [转]
    软件开发的基础知识[1]
    什么是 SHTML
    ASP.NET 2.0:弃用 DataGrid 吧,有新的网格控件了![msdn]
    主页制作五十式[好帖就要转]
  • 原文地址:https://www.cnblogs.com/pythonywy/p/11405681.html
Copyright © 2020-2023  润新知