一、需求分析

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. 如何将Unicode文本写到日志文件中

    有时为了定位问题,我们需要结合打印日志来处理.特别是较难复现的,一般都需要查看上下文日志才能找出可能存在的问题.考虑到程序要在不同语言的操作系统上运行,程序界面显示要支持Unicode,打印出来的日志 ...

  2. 使用Eclipse的坑

    1.运行Eclipse时突然出现找不到或者无法加载主类,这个问题不解决,下面的学习就无从做起,查了网上的一些资料,无法解决,所以还是有点烦人.如果在解决问题的过程中能够学到点什么,也是很值得的,但是就 ...

  3. spring事务实现原理

    实现原理 本质 如果你用过Spring AOP,那么理解注解事务就十分简单了.事务注解本质上实在事务方法加入一个Around切面,在方法开始前开始事务,在抛出异常后回滚事务.使用简单伪代码可以简单理解 ...

  4. API(三)之Class-based Views

    使用基于类的视图重写API 我们首先将根视图重写为基于类的视图.所有这一切都涉及到重构views.py. from snippets.models import Snippet from snippe ...

  5. C# 各类常见Exception 异常信息

    一直对报错有些迷惑的地方,什么时候try,catch那些Exception更合适,报错信息更能快速定位问题所在... 转载链接← 正文 Exception: 所有异常对象的基类. SystemExce ...

  6. LeetCode 29 - 两数相除 - [位运算]

    题目链接:https://leetcode-cn.com/problems/divide-two-integers/description/ 给定两个整数,被除数 dividend 和除数 divis ...

  7. [No000014E]提问的智慧How To Ask Questions The Smart Way

    原文版本历史 目录 声明 简介 在提问之前 当你提问时 慎选提问的论坛 Stack Overflow 网站和 IRC 论坛 第二步,使用项目邮件列表 使用有意义且描述明确的标题 使问题容易回复 用清晰 ...

  8. [No0000B8]WPF或Winform调用系统Console控制台显示信息

    using System; using System.Collections.Generic; using System.Diagnostics; using System.IO; using Sys ...

  9. spark分组统计及二次排序案例一枚

    组织数据形式: aa 11 bb 11 cc 34 aa 22 bb 67 cc 29 aa 36 bb 33 cc 30 aa 42 bb 44 cc 49 需求: 1.对上述数据按key值进行分组 ...

  10. [knowledge][DPI] kernel bypass 高性能网络包处理的宏观思路

    高性能网络包处理,这个问题的出现,主要原因在于linux内核协议栈的处理能力,已经跟不上日益增长的网卡吞吐量以及数据量. 有关详细的内核协议栈瓶颈的阐述,可以参考如下这篇文章: <Improvi ...