开发一个简单的BBS论坛

项目需求:

 整体参考“抽屉新热榜” + “虎嗅网”
 实现不同论坛版块
 帖子列表展示
 帖子评论数、点赞数展示
 在线用户展示
 允许登录用户发贴、评论、点赞
 允许上传文件
 帖子可被置顶
 可进行多级评论

知识必备:(注:没有必备下面知识的同学,请返回去看会之后再看下面的内容防止蒙了~~!

 Django
 HTML\CSS\JS
 BootStrap
 Jquery

设计表结构

1、表结构重要性

在开发任何项目的时候,设计到数据库,第一个事情要做的是设计表结构。表结构设计不好就不要写代码,表结构是体现了你业务逻辑关系的。你的数据都要往数据库里存,其实表结构你要理清了你的架构也就出来了!

2、设计表

#!/usr/bin/env python
#-*- coding:utf-8 -*-

from __future__ import unicode_literals
from django.db import models
from django.contrib.auth.models import User

# Create your models here.

class Article(models.Model):
    '''
    帖子表
    '''
    #标题最大长度255,不能重名
    title = models.CharField(u'文章标题',max_length=255,unique=True)
    #发布办款-使用外键关联Category
    category = models.ForeignKey("Category",verbose_name='板块名称')
    '''
    这里在admin中,title默认是显示英文的,我们可以在他的最前面加要给字段,在admin中就可以显示中文,他和verbose_name一样,什么时候必须使用
    verbose_name呢?比如上面的{category = models.ForeignKey("Category",verbose_name='板块名称')} 这个字段第一个字段是关联的类,这里
    就必须使用verbose_name
    '''
    #上传文件
    head_img = models.ImageField(upload_to="uploads")
    #文章内容(文章内容可能有很多,所以我们就不用"CharField"来写了,我们用TextField,不用规定他多长了,为可扩展长度)
    content = models.TextField(u"内容")
    #文章作者
    author = models.ForeignKey("UserProfile",verbose_name="作者")
    #发布日期
    publish_date = models.DateTimeField(auto_now=True,verbose_name="发布日期")
    #是否隐藏
    hidden = models.BooleanField(default=False,verbose_name="是否隐藏")
    #帖子的优先级
    priority = models.IntegerField(default=1000,verbose_name="优先级")

    def __unicode__(self):
        return "<%s,author:%s>" % (self.title,self.author)

class Comment(models.Model):
    '''
    评论表
    '''
    #评论是基于文章的,并且一条评论只属于一个文章!对多的关系
    #一个文章可以有多个评论,一个评论只属于一个文章
    #评论文章
    article = models.ForeignKey("Article")
    #评论用户
    user = models.ForeignKey("UserProfile")
    #评论内容
    comment = models.TextField(max_length=1000)
    #评论时间
    date = models.DateTimeField(auto_now=True)

    #多级评论,是不是评论评论的当前的表(自己表),所以就得和自己做一个关联!
    #这里在关联自己的时候必须设置一个related_name否则会报错冲突
    #这里parent_comment,必须设置为可以为空,因为如果他是第一评论他是没有父ID的
    parent_comment = models.ForeignKey("self",related_name='p_comment',blank=True,null=True)
    '''
    prent self
    Null    1
    1       2
    1       3
    2       4
    通过上面的这种方法来记录,评论的级别关系!
    '''
    def __unicode__(self):
        return "<user:%s>" %(self.user)
class ThumbUp(models.Model):
    '''
    点赞
    '''
    #给那个文章点的
    article = models.ForeignKey('Article')
    #用户名
    user = models.ForeignKey('UserProfile')
    #时间
    date = models.DateTimeField(auto_now=True)

class Category(models.Model):
    '''
    板块表
    '''
    #板块名称
    name = models.CharField(max_length=64,unique=True,verbose_name="板块名称")
    #板块管理员
    admin = models.ManyToManyField("UserProfile",verbose_name="模块管理员")
    def __unicode__(self):
        return self.name

class UserProfile(models.Model):
    '''
    用户表
    '''
    #使用Django提供的用户表,直接继承就可以了.在原生的User表里扩展!(原生的User表里就有用户名和密码)
    #一定要使用OneToOne,如果是正常的ForeignKey的话就表示User中的记录可以对应UserProfile中的多条记录!
    #并且OneToOne的实现不是在SQL级别实现的而是在代码基本实现的!
    user = models.OneToOneField(User)
    #名字
    name = models.CharField(max_length=32)
    #属组
    groups = models.ManyToManyField("UserGroup")

    def __unicode__(self):
        return self.name

class UserGroup(models.Model):
    '''
    用户组表
    '''
    name = models.CharField(max_length=64,unique=True)
    def __unicode__(self):
        return self.name

配置Django Admin

配置admin注册model,不要忘记创建Django 管理员用户

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

admin.site.register(models.Article)
admin.site.register(models.Category)
admin.site.register(models.Comment)
admin.site.register(models.ThumbUp)
admin.site.register(models.UserProfile)
admin.site.register(models.UserGroup)

我创建了几个板块,我在板块中查看的时候。只能看到下面简单的信息:

这里我想看到板块中的ID或其他信息怎么办?

#!/usr/bin/env python
#-*- coding:utf-8 -*-

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

#给某个表专门的定制的类
class CategoryAdmin(admin.ModelAdmin):
    list_display = ('id','name')

class ArticleAdmin(admin.ModelAdmin):
    list_display = ('id','title','author','hidden','publish_date')

admin.site.register(models.Article,ArticleAdmin) #把自定义的类绑定到注册的类中
admin.site.register(models.Category,CategoryAdmin)  #把自定义的类绑定到注册的类中
admin.site.register(models.Comment)
admin.site.register(models.ThumbUp)
admin.site.register(models.UserProfile)
admin.site.register(models.UserGroup)

效果如下:

前端页面&URLorViews配置

1、url别名使用

url里配置别名

url(r'^category/(\d+)/$',views.category,name='category'),

html里配置的时候就只认那个别名了

          <li role="presentation"><a href="{% url 'category' 1 %}">欧美专区</a></li>
          <li role="presentation"><a href="{% url 'category' 2 %}">日韩专区</a></li>
          <li role="presentation"><a href="{% url 'category' 3 %}">印度专区</a></li>

别名的好处:如果说那天想修改url里的这个url名称了,是不是所有前端都得修改!并且在有好几层的时候怎么改使用别名就会非常方便了!

2、前端页面写完之后发现图片无法正常显示

出现这个问题的原因:他能找到uploads这个目录吗?他能直接访问这个目录吗?他不能直接访问不了!

  • 一个是在Linux环境下做一个软连接连接过去

如果在settings里加入uploads这个目录,但是这个方法还是有问题!他会去找/static/uploads/uploads目录,看下面的图!

但是通过下面的方式就可以访问(原因就是因为:他去/static/uploads/uploads目录找了)

2.2、我们自己写上传的方法

定义form表单认证

#!/usr/bin/env python
#-*- coding:utf-8 -*-
# Tim Luo  LuoTianShuai

from django import forms

class ArticleForm(forms.Form):
    title = forms.CharField(max_length=255,min_length=5)
    summary = forms.CharField(max_length=255,min_length=5)
    head_img = forms.ImageField()
    content = forms.CharField(min_length=10)
    category_id = forms.IntegerField()

定义上传方法

#!/usr/bin/env python
#-*- coding:utf-8 -*-
# Tim Luo  LuoTianShuai
import os

def handle_upload_file(f,request):  #f这里获取到文件句柄
    base_img_upload_path = 'static/Uploads'
    user_path = "%s/%s" % (base_img_upload_path,request.user.userprofile.id)
    if not os.path.exists(user_path):
        os.mkdir(user_path)
    with open('%s/%s'% (user_path,f.name),'wb+') as destinations:
        for chunk in f.chunks():
            destinations.write(chunk)
        #为了防止用户传送图片进行冲突,我们为每个用户进行创建用户

    return "/static/Uploads/%s/%s" % (request.user.userprofile.id,f.name)

定义views

def new_article(request):
    category_list = models.Category.objects.all()
    if request.method == 'POST':
        form = ArticleForm(request.POST,request.FILES)
        if form.is_valid():
            form_data = form.cleaned_data
            form_data['author_id'] = request.user.userprofile.id

            #自定义图片上传
            new_img_path = handle_upload_file(request.FILES['head_img'],request)
            #但是在views也保存了一份,我们给他改掉改成我们自己的就行了
            form_data['head_img'] = new_img_path

            #create只能返回成功失败,我想在创建完成之后返回文章的ID,直接下面那么写就可以
            print form_data
            new_article_obj = models.Article(**form_data)
            new_article_obj.save()#这个对象就直接返回了
            return render(request,'new_article.html',{'new_article_obj':new_article_obj}) #如果没有这个变量说明是创建新文章呢
        else:
            print form.errors

    return render(request,'new_article.html',{'category_list':category_list})

多级评论实现

用户可以直接对贴子进行评论,其它用户也可以对别的用户的评论再进行评论,也就是所谓的垒楼,如下图:

所有的评论都存在一张表中, 评论与评论之前又有从属关系,如何在前端 页面上把这种层级关系体现出来?

首先咱们在存储数据的时候是怎么来实现记录层级关系的呢?(下面的图是经过简化的把其他列隐藏了)

我们在上面创建数据库表结构的时候,就定义了一个外键为他们自己(parent_comment_id),如果他没有父级别的ID说明他们是第一层,如果有说明他包含在一个评论之内!(仔细看上面的表结构)

先把评论简化成一个这样的模型:

data = [
    (None,'A'),
    ('A','A1'),
    ('A','A1-1'),
    ('A1','A2'),
    ('A1-1','A2-3'),
    ('A2-3','A3-4'),
    ('A1','A2-2'),
    ('A2','A3'),
    ('A2-2','A3-3'),
    ('A3','A4'),
    (None,'B'),
    ('B','B1'),
    ('B1','B2'),
    ('B1','B2-2'),
    ('B2','B3'),
    (None,'C'),
    ('C','C1'),

]

转换为字典之后:

data_dic = {
    'A': {
        'A1': {
            'A2':{
                'A3':{
                    'A4':{}
                }
            },
            'A2-2':{
                'A3-3':{}
            }
        }
    },
    'B':{
        'B1':{
            'B2':{
                'B3':{}
            },
            'B2-2':{}
        }
    },
    'C':{
        'C1':{}
    }

}

看上面的字典,我们能通过for循来获取他有多少层吗?当然不行,我们不知道他有多少层就没有办法进行找,或者通过while循环,最好是用递归进行一层一层的查找

我们在前端展示的时候需要知道,那条数据是那一层的,不可能是垒下去的!因为他们是有层级关系的!

我们用后端来实现:咱们给前端返回一个字典这样是不行的,咱们在后端把层级关系建立起来~返回的时候直接返回一个完整的HTML

转换为字典之后就有层级关系了我们可以通过递归来实现了!上面再没有转换为字典的时候层级关系就不是很明确了!

在循环的过程中不断的创建字典,先建立最顶级的,然后在一层一层的建立

先通过一个简单的例子看下:

#!/usr/bin/env python
#-*- coding:utf-8 -*-
# Tim Luo  LuoTianShuai

data = [
    (None,'A'),
    ('A','A1'),
    ('A','A1-1'),
    ('A1','A2'),
    ('A1-1','A2-3'),
    ('A2-3','A3-4'),
    ('A1','A2-2'),
    ('A2','A3'),
    ('A2-2','A3-3'),
    ('A3','A4'),
    (None,'B'),
    ('B','B1'),
    ('B1','B2'),
    ('B1','B2-2'),
    ('B2','B3'),
    (None,'C'),
    ('C','C1'),

]

def tree_search(d_dic,parent,son):
    #一层一层找,先拨第一层,一层一层往下找
    for k,v in d_dic.items():
        #举例来说我先遇到A,我就把A来个深度查询,A没有了在找B
        if k == parent:#如果等于就找到了parent,就吧son加入到他下面
            d_dic[k][son] = {} #son下面可能还有儿子
            #这里找到就直接return了,你找到就直接退出就行了
            return
        else:
            #如果没有找到,有可能还有更深的地方,的需要剥掉一层
            tree_search(d_dic[k],parent,son)

data_dic = {}

for item in data:
    # 每一个item代表两个值一个父亲一个儿子
    parent,son = item
    #先判断parent是否为空,如果为空他就是顶级的,直接吧他加到data_dic
    if parent is None:
        data_dic[son] = {}  #这里如果为空,那么key就是他自己,他儿子就是一个空字典
    else:
        '''
        如果不为空他是谁的儿子呢?举例来说A3他是A2的儿子,但是你能直接判断A3的父亲是A2你能直接判断他是否在A里面吗?你只能到第一层.key
        所以咱们就得一层一层的找,我们知道A3他爹肯定在字典里了,所以就得一层一层的找,但是不能循环找,因为你不知道他有多少层,所以通过递归去找
        直到找到位置
        '''
        tree_search(data_dic,parent,son) #因为你要一层一层找,你的把data_dic传进去,还的把parent和son传进去

for k,v in data_dic.items():
    print(k,v)

执行结果:(完美)

('A', {'A1': {'A2': {'A3': {'A4': {}}}, 'A2-2': {'A3-3': {}}}, 'A1-1': {'A2-3': {'A3-4': {}}}})
('C', {'C1': {}})
('B', {'B1': {'B2-2': {}, 'B2': {'B3': {}}}})

2、前端返回

当咱们把这个字典往前端返回的时候,前端模板里是没有一个语法递归的功能的,虽然咱们的层级关系已经出来了!所以咱们需要自定义一个模板语言然后拼成一个html然后返回给前端展示!

2.1、配置前端吧数据传给simple_tag

{% load custom_tags %}

{% build_comment_tree article_obj.comment_set.select_related %}

2.2、simple_tag获取数据然后把用户穿过来的数据进行转换为字典

#!/usr/bin/env python
# -*- coding:utf-8 -*-
from django import template
from django.utils.safestring import mark_safe

register = template.Library()

def tree_search(d_dic,comment_obj):#这里不用传附近和儿子了因为他是一个对象,可以直接找到父亲和儿子
    for k,v_dic in d_dic.items():
        if k == comment_obj.parent_comment:#如果找到了
            d_dic[k][comment_obj] = {} #如果找到父亲了,你的把自己存放在父亲下面,并把自己当做key,value为一个空字典
            return
        else:#如果找不到递归查找
            tree_search(d_dic[k],comment_obj)

@register.simple_tag
def build_comment_tree(comment_list):
    '''
    把评论传过来只是一个列表格式(如下),要把列别转换为字典,在把字典拼接为html
    [<Comment: <A,user:罗天帅>>, <Comment: <A2-1,user:罗天帅>>, <Comment: <A3-1,user:罗天帅>>, <Comment: <A2-2,user:罗天帅>>,
    <Comment: <A4-1,user:罗天帅>>, <Comment: <A4-2,user:罗天帅>>, <Comment: <A5-1,user:罗天帅>>, <Comment: <A3-2,user:罗天帅>>,
     <Comment: <B2,user:罗天帅>>, <Comment: <B2-1,user:罗天帅>>]
    :param comment_list:
    :return:
    '''
    comment_dic = {}
    #print(comment_list)
    for comment_obj in comment_list: #每一个元素都是一个对象
        if comment_obj.parent_comment is None: #如果没有父亲
            comment_dic[comment_obj] = {}
        else:
            #通过递归找
            tree_search(comment_dic,comment_obj)

    # #测试:
    # for k,v in comment_dic.items():
    #     print(k,v)

    # 上面完成之后开始递归拼接字符串

2、3生成html标签

#!/usr/bin/env python
# -*- coding:utf-8 -*-
from django import template
from django.utils.safestring import mark_safe

register = template.Library()

def tree_search(d_dic,comment_obj):#这里不用传附近和儿子了因为他是一个对象,可以直接找到父亲和儿子
    for k,v_dic in d_dic.items():
        if k == comment_obj.parent_comment:#如果找到了
            d_dic[k][comment_obj] = {} #如果找到父亲了,你的把自己存放在父亲下面,并把自己当做key,value为一个空字典
            return
        else:#如果找不到递归查找
            tree_search(d_dic[k],comment_obj)

def generate_comment_html(sub_comment_dic):
    #先创建一个html默认为空
    html = ""
    for k,v_dic in sub_comment_dic.items():#循环穿过来的字典
        html += "<div  class='comment-node'>"  + k.comment + "</div>"
        #上面的只是把第一层加了他可能还有儿子,所以通过递归继续加
        if v_dic:
            html += generate_comment_html(v_dic)
    return html

@register.simple_tag
def build_comment_tree(comment_list):
    '''
    把评论传过来只是一个列表格式(如下),要把列别转换为字典,在把字典拼接为html
    [<Comment: <A,user:罗天帅>>, <Comment: <A2-1,user:罗天帅>>, <Comment: <A3-1,user:罗天帅>>, <Comment: <A2-2,user:罗天帅>>,
    <Comment: <A4-1,user:罗天帅>>, <Comment: <A4-2,user:罗天帅>>, <Comment: <A5-1,user:罗天帅>>, <Comment: <A3-2,user:罗天帅>>,
     <Comment: <B2,user:罗天帅>>, <Comment: <B2-1,user:罗天帅>>]
    :param comment_list:
    :return:
    '''
    comment_dic = {}
    #print(comment_list)
    for comment_obj in comment_list: #每一个元素都是一个对象
        if comment_obj.parent_comment is None: #如果没有父亲
            comment_dic[comment_obj] = {}
        else:
            #通过递归找
            tree_search(comment_dic,comment_obj)

    # #测试:
    # for k,v in comment_dic.items():
    #     print(k,v)

    # 上面完成之后开始递归拼接字符串

    #div框架
    html = "<div class='comment-box'>"
    margin_left = 0
    for k,v in comment_dic.items():
        #第一层的html
        html += "<div class='comment-node'>" + k.comment + "</div>"
        #通过递归把他儿子加上
        html += generate_comment_html(v)
    html += "</div>"
    return mark_safe(html)

效果如下:

2.4、上面的看起来不是很好看怎么办?给他增加一个margin-left让他来显示层级效果,每次进行递归的时候给他加一个值!

#!/usr/bin/env python
# -*- coding:utf-8 -*-
from django import template
from django.utils.safestring import mark_safe

register = template.Library()

def tree_search(d_dic,comment_obj):#这里不用传附近和儿子了因为他是一个对象,可以直接找到父亲和儿子
    for k,v_dic in d_dic.items():
        if k == comment_obj.parent_comment:#如果找到了
            d_dic[k][comment_obj] = {} #如果找到父亲了,你的把自己存放在父亲下面,并把自己当做key,value为一个空字典
            return
        else:#如果找不到递归查找
            tree_search(d_dic[k],comment_obj)

def generate_comment_html(sub_comment_dic,margin_left_val):
    #先创建一个html默认为空
    html = ""
    for k,v_dic in sub_comment_dic.items():#循环穿过来的字典
        html += "<div style='margin-left:%spx'  class='comment-node'>" % margin_left_val + k.comment + "</div>"
        #上面的只是把第一层加了他可能还有儿子,所以通过递归继续加
        if v_dic:
            html += generate_comment_html(v_dic,margin_left_val+15)
    return html

@register.simple_tag
def build_comment_tree(comment_list):
    '''
    把评论传过来只是一个列表格式(如下),要把列别转换为字典,在把字典拼接为html
    [<Comment: <A,user:罗天帅>>, <Comment: <A2-1,user:罗天帅>>, <Comment: <A3-1,user:罗天帅>>, <Comment: <A2-2,user:罗天帅>>,
    <Comment: <A4-1,user:罗天帅>>, <Comment: <A4-2,user:罗天帅>>, <Comment: <A5-1,user:罗天帅>>, <Comment: <A3-2,user:罗天帅>>,
     <Comment: <B2,user:罗天帅>>, <Comment: <B2-1,user:罗天帅>>]
    :param comment_list:
    :return:
    '''
    comment_dic = {}
    #print(comment_list)
    for comment_obj in comment_list: #每一个元素都是一个对象
        if comment_obj.parent_comment is None: #如果没有父亲
            comment_dic[comment_obj] = {}
        else:
            #通过递归找
            tree_search(comment_dic,comment_obj)

    # #测试:
    # for k,v in comment_dic.items():
    #     print(k,v)

    # 上面完成之后开始递归拼接字符串

    #div框架
    html = "<div class='comment-box'>"
    margin_left = 0
    for k,v in comment_dic.items():
        #第一层的html
        html += "<div class='comment-node'>" + k.comment + "</div>"
        #通过递归把他儿子加上
        html += generate_comment_html(v,margin_left+15)
    html += "</div>"
    return mark_safe(html)

效果如下:

Python之路【第十八篇】Django小项目简单BBS论坛部分内容知识点的更多相关文章

  1. Python之路【第八篇】:堡垒机实例以及数据库操作

    Python之路[第八篇]:堡垒机实例以及数据库操作   堡垒机前戏 开发堡垒机之前,先来学习Python的paramiko模块,该模块机遇SSH用于连接远程服务器并执行相关操作 SSHClient ...

  2. Python开发【第十八篇】Web框架之Django【基础篇】

    一.简介 Python下有许多款不同的 Web 框架,Django 是重量级选手中最有代表性的一位,许多成功的网站和APP都基于 Django. Django 是一个开放源代码的Web应用框架,由 P ...

  3. Python自动化 【第十八篇】:JavaScript 正则表达式及Django初识

    本节内容 JavaScript 正则表达式 Django初识 正则表达式 1.定义正则表达式 /.../  用于定义正则表达式 /.../g 表示全局匹配 /.../i 表示不区分大小写 /.../m ...

  4. Python之路【第八篇】python实现线程池

    线程池概念 什么是线程池?诸如web服务器.数据库服务器.文件服务器和邮件服务器等许多服务器应用都面向处理来自某些远程来源的大量短小的任务.构建服务器应用程序的一个过于简单的模型是:每当一个请求到达就 ...

  5. Python开发【第十八篇】:MySQL(二)

    视图 视图是一个虚拟表(非真实存在),其本质是[根据SQL语句获取动态的数据集,并为其命名],用户使用时只需使用[名称]即可获取结果集,并可以将其当作表来使用. SELECT * FROM ( SEL ...

  6. 【Python之路】第八篇--Python基础之网络编程

    Socket socket通常也称作"套接字",用于描述IP地址和端口,是一个通信链的句柄,应用程序通常通过"套接字"向网络发出请求或者应答网络请求. sock ...

  7. Python之路【第十八篇】:Web框架们

    Python之路[第十八篇]:Web框架们   Python的WEB框架 Bottle Bottle是一个快速.简洁.轻量级的基于WSIG的微型Web框架,此框架只由一个 .py 文件,除了Pytho ...

  8. Python开发【第二十二篇】:Web框架之Django【进阶】

    Python开发[第二十二篇]:Web框架之Django[进阶]   猛击这里:http://www.cnblogs.com/wupeiqi/articles/5246483.html 博客园 首页 ...

  9. Python之路【第十七篇】:Django【进阶篇 】

    Python之路[第十七篇]:Django[进阶篇 ]   Model 到目前为止,当我们的程序涉及到数据库相关操作时,我们一般都会这么搞: 创建数据库,设计表结构和字段 使用 MySQLdb 来连接 ...

随机推荐

  1. sysv-rc-conf管理Ubuntu server开机启动服务

    在RedHat中,都是使用chkconfig来管理服务的,但是在Ubuntu Server中,却有一个更好的工具,chkconfig也是可以使用的.今天来说一下sysv-rc-conf sysv-rc ...

  2. iOS.Animation.Math-behind-CATransform3D

    iOS CoreAnimation: Math behind CATransform3D 1. What's CATransform? Matrix Transform: "User spa ...

  3. [转]Snappy压缩库安装和使用之一

    Snappy压缩库安装和使用之一 原文地址:http://blog.csdn.net/luo6620378xu/article/details/8521223 近日需要在毕业设计中引入一个压缩库,要求 ...

  4. Python 5 —— OOP

    OOP class MyClass: y = None def __init__(self,x,y): self.__x = x self.y = y def getx(self): return s ...

  5. caffe 在window下编译(windows7, cuda8.0,matlab接口编译)

    1. 环境:Windows7,Cuda8.0,显卡GTX1080,Matlab2016a,VS2013 (ps:老板说服务器要装windows系统,没办法,又要折腾一番,在VS下编译好像在cuda8. ...

  6. mysql的collation

    mysql的collation大致的意思就是字符序.首先字符本来是不分大小的,那么对字符的>, = , < 操作就需要有个字符序的规则.collation做的就是这个事情,你可以对表进行字 ...

  7. 《精通CSS网页布局》读书报告 ----2016-12-5补充

    第一章:CSS布局基础 1.CSS的精髓是布局,而不是样式哦!  (定要好好的研究布局哦,尤其配合html5) 2. html标签的语义性,要好好的看看哦! 3.DTD:文档类型定义. 4.内联--& ...

  8. Odoo 配置快速创建编辑按钮

    对于Man2one类型的数据,我们知道,form view中总会显示出一个尾巴似的"create and edit"和一个快速创建的机制,有时候业务人员一不小心就容易创建一个新的行 ...

  9. Log4j2常见使用示例及Syslog/Syslog-ng

    准备工作 打开http://logging.apache.org/log4j/,点击左侧Download,我下载的是Apache Log4j 2 binary (zip),目前是2.0.2版本.解压后 ...

  10. mysql toolkit 用法[备忘] (转)

    命令列表 /usr/bin/pt-agent /usr/bin/pt-align /usr/bin/pt-archiver /usr/bin/pt-config-diff /usr/bin/pt-de ...