一、需求分析

1.首页(显示文章)

文章详情

点赞,点踩

文章评论(子评论,评论的展示)

登录功能(图片验证码)

注册功能(基于form验证,ajax)

个人站点(不同人不同样式,文章过滤)

后台管理(文章展示)

新增文章(富文本编辑器)

2.设计程序(框架,数据库设计)

UserInfo用户表

blog个人站点表

Aticle文章表

commit评论表

upanddown点赞点踩表

category文章分类表

tag文章标签表

表关系

userinfo跟blog一对一

article跟blog一对多

article跟category一对多

article跟tag多对多

commit跟article一对多

upanddown跟article一对多

user跟commit一对多

user跟upanddown一对多

category跟blog一对多

tag跟blog一对多

二、settings配置和models里建表

settings配置

#设置LANGUAGE_CODE = 'zh-hans',则后台管理变成中文
LANGUAGE_CODE = 'zh-hans'
#设置时区
TIME_ZONE = 'Asia/Shanghai'

USE_I18N = True

USE_L10N = True
#不用UTC时间
USE_TZ = False

# 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'),
]

#auth模块未登录时转到的路由
LOGIN_URL='/login/'
#舍弃系统给的user表,自定义auth认证的userinfo表
AUTH_USER_MODEL='blog.UserInfo'

EMAIL_HOST='smtp.qq.com'#设置以什么邮箱发送
EMAIL_PORT=465#端口号
EMAIL_HOST_USER='1500519302@qq.com'#发送者邮箱账号
EMAIL_HOST_PASSWORD='odokxrzlfejkcbbh'#授权码
DEFAULT_FROM_EMAIL=EMAIL_HOST_USER#显示收件人
EMAIL_USE_SSL=True#使用ssl加密,qq邮箱只支持这个

#  avatar = models.FileField(upload_to='avatar/', default='/static/img/default.png')
#如果不配置MEDIA_ROOT,和MEDIA_URL,默认会存到avatar
#如果不配置MEDIA_ROOT,和MEDIA_URL,默认会存到media/avatar
MEDIA_URL='/media/'
MEDIA_ROOT=os.path.join(BASE_DIR,'media')
MEDIA_BBS=os.path.join(BASE_DIR,'BBS')

models建表

from django.db import models
from django.contrib.auth.models import AbstractUser

# Create your models here.
# UserInfo这个表,继承AbstractUser,因为要用auth组件

class UserInfo(AbstractUser):
    nid = models.AutoField(primary_key=True)

    # username=models.CharField(max_length=32,unique=True)
    # 该字段可以为空,为该字段设置默认值,default='123455666'
    # blank=True  只是admin中表单提交的时候,做校验,如果设置成True,就是不校验了
    phone = models.CharField(max_length=32,null=True,blank=True)
    # upload_to需要传一个路径(avatar文件夹会自动创建)
    avatar = models.FileField(upload_to='avatar/', default='avatar/default.png')
    # 如果avatar用charfield,如何处理?
    #  一对一关联blog表,to_field如果不写,默认主键
    # blog_id字段存的数据是什么?blog表的---nid这个字段
    blog = models.OneToOneField(to='Blog', to_field='nid',null=True)

    class Meta:
        # admin中显示表名
        verbose_name='用户表'
        # admin中表名s去掉
        verbose_name_plural = verbose_name

    # user表
    #     id name  blog_id
    #     1  111    1
    #     2  111    1
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)
    # ForeignKey跟OneToOneField的区别?
    #OneToOneField unique=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)
    # 大文本TextField()
    content = models.TextField()
    # 存时间类型,auto_now_add每插入一条数据,时间自动写入当前时间,
    # auto_now,这条数据修改的时候,会更新成当前时间
    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应该怎么写?
    # 中介模型,手动创建第三张表,through是通过哪个表跟Tag建立关系,through_fields为了查询用的
    tag = models.ManyToManyField(to='Tag', through='ArticleTOTag', through_fields=('article', 'tag'))
    # 这样写,会自动创建第三张表
    # tag = models.ManyToManyField(to='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')
    # article和tag应不应该联合唯一?

    # article_id  1
    # tag_id     1

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_id=models.IntegerField()
    # 自关联
    # parent_id=models.ForeignKey(to='Commit',to_field='nid')
    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')
    is_up = models.BooleanField()

    class Meta:
        # 写这些,只是为了不写脏数据,联合唯一
        unique_together = (('user', 'article'),)

models中 class Meta 定义的是元数据的属性,不会生成字段

建表时,一对多关系可以这么理解:找出哪个是一,哪个是多。在多的那个对象建表,然后建字段

django中的orm自关联:表内自关联是指表内数据相关联的对象和表是相同字段,这样我们就直接用表内关联将外键关联设置成自身表的字段。比如:微博评论,每条评论都可能有自评论,但每条子评论都只有一个父评论,这就满足了,一对多的情形。父评论为关联字段,可以对应多个子评论,这就是一对多的自关联。

parent = models.ForeignKey(to='self', to_field='nid',null=True,blank=True)

三、生成图片验证码

首先要下载Pillow

后台代码如下

def login(request):
    if request.method=='GET':
        return render(request,'login.html')
    elif request.is_ajax():
        response={'user':None,'msg':None}
        name=request.POST.get('name')
        password=request.POST.get('password')
        valid_code=request.POST.get('valid_code')
        ret=request.session.get('valid_session')
        print(ret)
        if valid_code.upper()==request.session.get('valid_session').upper():
            user=auth.authenticate(request,username=name,password=password)
            #这里auth.authenticate如果没有登录成功,user是None。如果登录成功,user则是登录的user对象
            if user:
                # print(user)
                #ajax请求,不能再返回
                #校验通过,一定要登录
                auth.login(request,user)
                response['user']=name
                response['msg']='登录成功'
            else:
                # print(user)
                response['msg']='用户名或密码错误'
        else:
            response['msg']='验证码错误'
        return JsonResponse(response)

def get_random_color():
    return (random.randint(0,255),random.randint(0,255),random.randint(0,255))

def get_valid_code(request):
    #图片验证码
    # 第一种方式,直接用服务器的图片
    # with open('static/media/img/315557.jpg','rb') as f:
    #     data=f.read()
    # return HttpResponse(data)

    #第二种方式
    #生成一张图片,第一个参数是模式:'rgb',第二个参数是图片大小(宽,高),第三个参数是图片颜色
    # img=Image.new('RGB',(200,35),color=get_random_color())
    # with open('valid_code.png','wb') as f:
    #     #img直接封装了保存图片的方法
    #     img.save(f,'png')
    # with open('valid_code.png','rb') as f:
    #     data=f.read()
    # return HttpResponse(data)
    #第二种方式有个漏洞,它要将随机生成的图片保存在服务器,这不合理,因此不用第二种方法

    #第三种方式
    # 在内存中生成一个空文件(把它想象成 open('valid_code.png', 'wb') as f:)
    # 一个是在硬盘上,一个是在内存中
    #先导入io模块,用内存生成文件
    # from io import BytesIO
    # img=Image.new('RGB',(200,35),color=get_random_color())
    # f=BytesIO()
    # #把图片保存到f中,
    # #放到内存中,存取比较快,而且有自动清理
    # img.save(f,'png')
    # data=f.getvalue()
    # return HttpResponse(data)

    #然后再第三种模式的基础上,再在生成的图片上进行写出随机字符串
    # img=Image.new('RGB',(200,35),color=get_random_color())
    # img_draw=ImageDraw.Draw(img)
    # #生成一个字体对象,第一个参数是字体文件的路径,第二个参数是大小
    # font=ImageFont.truetype('static/font/ss.TTF',size=25)
    # #第一个参数:xy(x,y)的坐标,第二个参数:要写的文字,第三个参数:写文字的颜色,第四个参数:字体
    # img_draw.text((0,0),'python',get_random_color(),font=font)
    # f=BytesIO()
    # img.save(f,'png')
    # data=f.getvalue()
    # return HttpResponse(data)

    #终极版本
    img=Image.new('RGB',(200,35),color=get_random_color())
    img_draw=ImageDraw.Draw(img)
    font=ImageFont.truetype('static/font/ss.TTF',size=25)
    random_code=''
    for i in range(5):
        char_num=random.randint(0,9)
        char_lower=chr(random.randint(97,122))
        char_upper=chr(random.randint(65,90))
        char_str=str(random.choice([char_num,char_lower,char_upper]))
        img_draw.text((i*30+20,0),char_str,get_random_color(),font=font)
        random_code+=char_str
    #在图片上画线画点画圆等
    # width = 200
    # height = 35
    # for i in range(2):
    #     x1 = random.randint(0, width)
    #     x2 = random.randint(0, width)
    #     y1 = random.randint(0, height)
    #     y2 = random.randint(0, height)
    #     # 在图片上画线。x1,y1表示起始坐标,x2,y2表示终止坐标
    #     img_draw.line((x1, y1, x2, y2), fill=get_random_color())
    #
    # for i in range(5):
    #     # 画点
    #     img_draw.point([random.randint(0, width), random.randint(0, height)], fill=get_random_color())
        # x = random.randint(0, width)
        # y = random.randint(0, height)
        # # 画弧形
        # img_draw.arc((x, y, x + 4, y + 4), 0, 90, fill=get_random_color())

    #把验证码保存到session中。验证码需要保存
    print(random_code)
    request.session['valid_session']=random_code
    f=BytesIO()
    img.save(f,'png')
    data=f.getvalue()
    return HttpResponse(data)

前台代码如下

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <script src="/static/jquery-3.3.1.js"></script>
    <link rel="stylesheet" href="/static/bootstrap-3.3.7-dist/css/bootstrap.css">
    <title>登录页面</title>
    <style>
        .img {
            height: 35px;
            width: 200px;
        }
    </style>
</head>
<body>
<div class="container-fluid">
    <div class="row">
        <div class="col-md-6 col-md-offset-3">
            <form action="">
                <div class="form-group">
                    <label for="name">用户名</label>
                    <input type="text" id="name" class="form-control">
                </div>
                <div class="form-group">
                    <label for="password">密码</label>
                    <input type="text" id="password" class="form-control">
                </div>
                <div class="form-group">
                    <label for="valid_code">验证码</label>
                    <div class="row">
                        <div class="col-md-6">
                            <input type="text" id="valid_code" class="form-control">
                        </div>
                        {#img的src指向的可以是一个路由#}
                        <img src="/get_valid_code/" alt="" id="img_code" class="img">
                    </div>
                </div>
            </form>
            <button class="btn" id="btn">提交</button><span style="color: red" id="error"></span>
        </div>
    </div>
</div>
</body>
<script>
    $('#img_code').click(function () {
        //每点击一次,在路径后面加一个?,其实就是每点击一次刷新一次的意思
        $('#img_code')[0].src += '?';
    });
    $('#btn').click(function () {
        $.ajax({
            url: '/login/',
            type: 'post',
            data: {
                'name': $('#name').val(),
                'password': $('#password').val(),
                'valid_code': $('#valid_code').val(),
                'csrfmiddlewaretoken': '{{ csrf_token }}'
            },
            success: function (data) {
                console.log(data);
                if (data.user) {
                    location.href = '/index/'
                } else {
                    $('.error').html(data.msg)
                }
            }
        })
    })
</script>
</html>

四、注册功能

注册功能用ajax进行提交,要有局部刷新功能,使用forms组件对前台进行校验

前端html中,accept要配合input file联用,表示接收哪种格式文件

前端代码如下

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <script src="/static/jquery-3.3.1.js"></script>
    <link rel="stylesheet" href="/static/bootstrap-3.3.7-dist/css/bootstrap.css">
    <title>注册</title>
    <style>
        .img {
            height: 70px;
            width: 70px;
        }

        #my_file {
            display: none
        }
    </style>
</head>
<body>
<div class="container-fluid">
    <div class="row">
        <div class="col-md-6 col-md-offset-3">
            <form action="" id="form">
                {% for foo in my_form %}
                    <div class="form-group">
                        {# 这里循环时,forms组件会自动为其加上一个id,可以取前端看一看,在这里可以用{{ foo.auto_id }}当做id #}
                        <label for="{{ foo.auto_id }}">{{ foo.label }}</label>
                        {{ foo }}<span style="color: red" class="error"></span>
                    </div>
                {% endfor %}
                {# 加一个上传文件的控件,上传头像 #}
                <div class="form-group">
                    <label for="my_file">头像
                        <img src="/static/img/default.png" alt="" id="img_file" class="img">
                    </label>
                    {# accpet表示可以接收哪种格式文件,只能与input file联用 #}
                    <input type="file" id="my_file" accept="image/*"><span class="error" style="color: red;"></span>
                </div>
            </form>
            <button class="btn" id="btn">提交</button>
        </div>
    </div>
</div>
</body>
<script>
    //捕捉上传图片后,头像有预览功能
    $('#my_file').change(function () {
        //先取出文件(图片)
        var file_obj = $('#my_file')[0].files[0];
        //生成一个文件阅读器对象,把图片放到img标签上
        //生成一个阅读器对象
        var filereader = new FileReader();
        //把图片对象,读到filereader对象中
        filereader.readAsDataURL(file_obj);
        //filereader.result这是filereader对象的值
        //把文件对象渲染到img标签上(这样不行,需要加载完成才能操作,因为文件可能过大)
        {#$('#img_file').attr('src',filereader.result)#}
        //等加载完成,再操作
        filereader.onload = function () {
            $('#img_file').attr('src', filereader.result)
        }
    });

    $('#btn').click(function () {
        //因为要上传文件,所以要生成formdata对象
        var formdata = new FormData();
        //要把所有的值都加进去
        //第一种方式,这样太麻烦了
        {#formdata.append('name',$('#id_username').val());#}
        {#formdata.append('password',$('#id_password').val());#}
        {# 下面几个是自定义的form字段,原生表里并没有的字段,故不会智能拼写 #}
        {#formdata.append('re_password',$('#id_re_password').val());#}
        {#formdata.append('email',$('#id_email').val());#}
        {#formdata.append('csrfmiddlewaretoken','{{ csrf_token }}');#}
        {#formdata.append('my_file',$('#my_file')[0].files[0]);#}

        //第二种方式
        //$('#form').serializeArray()把form表单打包,转成对象(列表套字典)
        var arr = $('#form').serializeArray();
        {#console.log(arr);{# 可以打印一下看看是什么内容 #}
        //jquery循环,传参数,第一个参数是要循环的对象,第二个参数是一个匿名函数。经测试,不能提交文件对象
        $.each(arr, function (key, obj) {
            //key对应的是0,1,2,3,4,...
            //obj对应的是:{name:"name",value:"sfdaq"}
            {#console.log(key);#}
            {#console.log(obj);#}
            formdata.append(obj.name, obj.value);
            formdata.append('csrfmiddlewaretoken', '{{ csrf_token }}');
        });
        formdata.append('my_file', $('#my_file')[0].files[0]);
        $.ajax({
            url: '/register/',
            type: 'post',
            processData: false,
            contentType: false,
            data: formdata,
            success: function (data) {
                if (data.status == 100) {
                    location.href = data.url
                } else {
                    //先清掉错误信息
                    $('.form-group').removeClass('has-error');
                    $('.error').html('');
                    //循环错误信息
                    $.each(data.msg, function (key, value) {
                        //处理两次密码不一致的情况
                        if (key == '__all__') {
                            $('#id_re_password').next().html(value[0])
                        }
                        //让错误信息显示
                        $('#id_' + key).next().html(value[0]).parent().addClass('has-error')
                    })
                }
            }
        });
        //设置定时器,清理掉显示错误的信息,个人认为不要清的好
        {#setTimeout(function () {#}
        {#    //清楚掉父div的has-error#}
        {#    //清除掉错误信息(span中的内容)#}
        {#    $('.form-group').removeClass('has-error');#}
        {#    $('.error').html('')#}
        //},3000)
    });

    $('#id_username').blur(function () {
        $.ajax({
            url: '/check_username/',
            type: 'post',
            data: {'name': $('#id_username').val(), 'csrfmiddlewaretoken': '{{ csrf_token }}'},
            success: function (data) {
                if (data.status == 101) {
                    $('#id_username').next().html(data.msg).parent().addClass('has-error')
                }
            }
        })
    })

    //name,发ajax请求校验用户是否存在
    //blur表示焦点移除
</script>
</html>

后台代码如下

def register(request):
    if request.method=='GET':
        my_form=myforms.MyForm()
        return render(request,'register.html',locals())
    elif request.is_ajax():
        print(request.POST)
        response={'status':100,'msg':None}
        my_form=myforms.MyForm(request.POST)#校验POST里的所有数据,forms可以直接接字典
        if my_form.is_valid():
            dic=my_form.cleaned_data
            dic.pop('re_password')
            my_file=request.FILES.get('my_file')
            #如果上传的文件为空,这个字段不穿,数据库里存默认值。
            if my_file:
                dic['avatar']=my_file
            user=models.UserInfo.objects.create_user(**dic)
            #看看存没存进去
            print(user.username)
            #要跳转的路径
            response['url']='/login/'
        else:
            response['status']=101
            response['msg']=my_form.errors
        return JsonResponse(response)

def check_username(request):
    response={'status':100,'msg':None}
    name=request.POST.get('name')
    user=models.UserInfo.objects.filter(username=name).first()
    if user:
        response['status']=101
        response['msg']='用户名已被占用'
    return JsonResponse(response)

五、admin表配置

要在app下的admin.py进行配置注册一下,这样就能控制相应的表了

from django.contrib import admin
from blog import models
# Register your models here.

admin.site.register(models.UserInfo)
admin.site.register(models.Blog)
admin.site.register(models.Article)
admin.site.register(models.Tag)
admin.site.register(models.Category)
admin.site.register(models.Commit)
admin.site.register(models.UpAndDown)
admin.site.register(models.ArticleTOTag)

六、meida路径配置

用户上传的文件最好配置一个文件夹,在路由层做一下配置。

可以可以把导入的serve当一个views函数,就是帮meidia开了一个路由接口,path分组是serve函数必须传的一个参数

from django.views.static import serve
from ff188 import settings
urlpatterns = [
    url(r'^admin/', admin.site.urls),
    url(r'^login/', views.login),
    url(r'^get_valid_code/', views.get_valid_code),
    url(r'^make/', views.make),
    url(r'^register/', views.register),
    url(r'^check_username/', views.check_username),
    url(r'^index/', views.index),
    url(r'^logout/', views.logout),
    #url第一个参数,正则表达式,第二个参数是函数的内存地址,第三个参数是一个字典,它会以关键字参数的形式传到第二个参数中,第四个参数是名字,反向解析用
    #当进行这些设置后,就可以访问media下的资源了
    url(r'^media/(?P<path>.*)', serve,{'document_root':settings.MEDIA_ROOT}),
]

七、个人主页

在static文件夹下创建css文件夹,把所有用户自定义的css样式都保存进去

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>{{ username }}的个人博客</title>
    <script src="/static/jquery-3.3.1.js"></script>
    <script src="/static/bootstrap-3.3.7-dist/js/bootstrap.js"></script>
    <link rel="stylesheet" href="/static/bootstrap-3.3.7-dist/css/bootstrap.css">
    <link rel="stylesheet" href="/static/css/{{ blog.theme }}">
    <style>
    </style>
</head>
<body>
<div class="head">
    <h4>{{ blog.title }}</h4>
</div>
<div class="container-fluid">
    <div class="row">
        <div class="col-md-3">
            <div class="panel panel-primary">
                <div class="panel-heading">我的分类</div>
                <div class="panel-body">
                    <p>请联系:199999999</p>
                    年入60w
                </div>
            </div>
            <div class="panel panel-primary">
                <div class="panel-heading">随笔档案</div>
                <div class="panel-body">
                    <a href="http://www.baidu.com">请点击</a>
                </div>
            </div>
        </div>
        <div class="col-md-9"></div>
    </div>
</div>

</body>
</html>

八、文章归类

#所有分类对应文章数
    category_num=models.Category.objects.all().filter(blog=blog).annotate(coun=Count('article__title')).values('title','coun')
    #所有标签对应文章数
    tag_num=models.Tag.objects.all().filter(blog=blog).annotate(coun=Count('article__title')).values('title','coun')
    #按日期分类
    from django.db.models.functions import TruncMonth
    #切分时间
    #这样查询到的y_m是一个datetime对象,到前端用date过滤即可
    time_article=models.Article.objects.filter(blog=blog).annotate(y_m=TruncMonth('create_time')).values('y_m').annotate(coun=Count('y_m')).values('y_m','coun')

这里补充一下ajax中$(this)的意思,像面向对象语言(如JAVA),简单的说,谁在调用它,它就代表谁

$("#btnConfirm").click(function(){
alert($(this).val()); //看这里,this代表的其实就是这个ID为btnConfirm的按钮,因为你现在点击的是ID为btnConfirm的按钮,那么this就是它
});

jquery中html(),text(),val()是有一些区别的

html就是可以对添加了<a></a>,<p></p>等设置值

val()是只有有value属性的才能取到或设置值

text()方法设置或返回被选元素的文本内容

BBS项目的更多相关文章

  1. BBS项目详解(forms快速创建登陆页面,登陆验证、通过阅读器进行头像上传的预览、内存管理器)

    BBS项目涉及的知识点 django中知识点 钩子函数(局部钩子和全局钩子) 1.局部钩子就是用来做合法性校验,比如用户名有没有被使用等 2.全局的就是用来做对比校验,比如两次输入的密码是否一致 3. ...

  2. BBS项目部署

    1.准备 项目架构为:LNM+Python+Django+uwsgi+Redis   (L:linux,N:nginx,M:mysql) 将bbs项目压缩上传到:  /opt 在shell中直接拖拽 ...

  3. auth复习和BBS项目的登录(1)

    auth复习 auth组件 验证:authenticate(request,username='andy',password='123) 登录:login(request,user) 注销:login ...

  4. python 自动化之路 day 20 Django进阶/BBS项目【一】

    一.django进阶 1.django orm 增删改查 1.1.创建表: 1 2 3 >>> from blog.models import Blog >>> b ...

  5. BBS项目知识点汇总

    目录 bbs项目知识点汇总 一. JavaScript 1 替换头像 2 form表单拿数据 3 form组件error信息渲染 4 添加html代码 5 聚焦操作 二 . html在线编辑器 三 . ...

  6. BBS项目-01

    目录 BBS项目 BBS开发流程: BBS表格创建: BBS项目 BBS开发流程: BBS项目: 开发流程: 需求分析 草拟一些项目的大致技术点和流程 架构设计 架构师(框架 语言 数据库 缓存数据库 ...

  7. 小福bbs—项目系统设计与数据库设计

    这个作业属于哪个课程 班级链接 这个作业要求在哪里 作业要求的链接 团队名称 小福bbs 这个作业的目标 实现对校园论坛软件的制作,使其能够发布帖子,查看信息等 作业的正文 小福bbs--项目需求分析 ...

  8. 小福bbs——项目需求分析

    # 一.简单了解 这个作业属于哪个课程 班级链接 这个作业要求在哪里 作业要求的链接 团队名称 小福bbs 这个作业的目标 第一个版本,根据项目预期情况形成 作业的正文 小福bbs--项目需求分析 其 ...

  9. day75 bbs项目☞后台管理+修改头像

    目录 一.后台管理之添加文章 二.修改用户头像 bbs项目总结 一.后台管理之添加文章 添加文章有两个需要注意的问题: 文章的简介切取,应该想办法获取到当前文章的文本内容后再截取字符 XSS攻击,由于 ...

  10. nginx之location、inmp架构详解、BBS项目部署

    本期内容概要 location lnmp架构 部署BBS项目 内容详细 1.location 使用Nginx Location可以控制访问网站的路径 但一个server可以有多个location配置 ...

随机推荐

  1. 技巧:Vim 的纵向编辑模式

    https://www.ibm.com/developerworks/cn/linux/l-cn-vimcolumn/ 开始之前 人类大脑对文字的处理是平面式的,所以我们浏览文章.查找资料或者重构代码 ...

  2. 精心收集的 48 个 JavaScript 代码片段,仅需 30 秒就可理解

    原文:Chalarangelo  译文:IT168 https://github.com/Chalarangelo/30-seconds-of-code#anagrams-of-string-with ...

  3. css---计算页面的的宽度和长度

    我们在写前端页面的时候,会遇到这样的情况,就是一个div设置宽度100%,设置左右边距10像素,这样的布局,在里面嵌套的div的宽度设置100%,这样写的话,里面的宽度是和外面的宽度一致的,同样是10 ...

  4. mui---自定义页面打开的方向

    在使用MUI做APP的时候,会考虑对页面的打开方向做规定,MUI也给我们提供了很多种页面的打开方式. 具体参考: http://ask.dcloud.net.cn/question/174 MUI做A ...

  5. ABP之展现层(Datatables分页)

    在前面的随笔中,已经介绍了ABP的增删改查的操作,但是对于查询的数据并没有进行分页,只是进行粗糙的展示,今天的随笔中将摸索进行分页展示.这里打算使用的分页插件是DataTables,这是一款比较强大的 ...

  6. Django----ModelFrom

    ModelForm a. class Meta: model, # 对应Model的 fields=None, # 字段 exclude=None, # 排除字段 labels=None, # 提示信 ...

  7. C# 调用存储过程 Sql Server存储过程 存储过程报错,程序中的try

    C#程序调用Sql Server存储过程,存储过程中报错情况,返回值... 0.SQL存储过程 USE [Opos] GO /****** Object: StoredProcedure [dbo]. ...

  8. eclipse安装Hadoop-0.20.2插件

    因为在使用Hadoop-0.20.2这个古董,需要使用它自带的eclipse插件,而我最初安装的是现代的eclipse4.10.0. 在经历两天,以及以下种种尝试之后,均以失败告终: 1.网上找适合的 ...

  9. nowcoder 206A - Birthday - [最小费用最大流]

    题目链接:https://www.nowcoder.com/acm/contest/206/A 题目描述 恬恬的生日临近了.宇扬给她准备了一个蛋糕.正如往常一样,宇扬在蛋糕上插了n支蜡烛,并把蛋糕分为 ...

  10. [No000016B]清华maven库配置settings.xml

    路径:"C:\Users\%USERNAME%\.m2\settings.xml" <settings xmlns="http://maven.apache.org ...