• BBS


    准备

      新建工程

        django-admin startproject BBS

      新建app

        python3 manage.py startapp bbs

    设计表结构

    from django.db import models
    
    # Create your models here.
    from django.db import models
    from django.contrib.auth.models import User
    
    # Create your models here.
    
    
    
    class UserProifle(models.Model):
        user = models.OneToOneField(User)
        name = models.CharField(max_length=32)
        def __str__(self):
            return self.name
    
    class Article(models.Model):
        """文章表"""
        title = models.CharField(max_length=128,unique=True)
        author = models.ForeignKey("UserProifle")
        category = models.ForeignKey("Category")
        pub_date = models.DateTimeField(auto_now_add=True,auto_created=True)
        tags = models.ManyToManyField("Tag", null=True)
        body = models.TextField(max_length=100000)
        head_img = models.ImageField(upload_to="uploads")
        status_choices = ((0,'草稿'),(1,'发布'),(2,'隐藏'))
        priority = models.SmallIntegerField(default=1000,verbose_name="优先级")
    
        def __str__(self):
            return self.title
    
    class Category(models.Model):
        """板块"""
        name = models.CharField(max_length=64,unique=True)
        set_as_top_menu = models.BooleanField(default=True)
    
        def __str__(self):
            return self.name
    
    
    class Tag(models.Model):
        """标签表"""
        name = models.CharField(max_length=64, unique=True)
        def __str__(self):
            return self.name
    
    class Comment(models.Model):
        """评论"""
        article = models.ForeignKey("Article")
        p_node = models.ForeignKey("Comment",null=True,blank=True,related_name='my_child_comment')
    
        user = models.ForeignKey("UserProifle")
        date = models.DateTimeField(auto_now_add=True)
        comment = models.TextField(max_length=1024)
    
    
        def __str__(self):
            return self.comment
    
    class Like(models.Model):
        """点赞"""
        article = models.ForeignKey("Article")
        user = models.ForeignKey("UserProifle")
        date = models.DateTimeField(auto_now_add=True)
    
    
    class PrivateMail(models.Model):
        """私信"""
        pass

    评论自关联,需要加上related_name,null=True默认可以为空,但是在django中需要加上blank=True

    admin

    django amdin是django提供的一个后台管理页面,该管理页面提供完善的html和css,使得你在通过Model创建完数据库表之后,就可以对数据进行增删改查,而使用django admin 则需要以下步骤:

    • 创建后台管理员
    • 配置url
    • 注册和配置django admin后台管理页面

    1、创建后台管理员

    1
    python manage.py createsuperuser

    2、配置后台管理url

    1
    url(r'^admin/', include(admin.site.urls))

    3、注册和配置django admin 后台管理页面

    a、在admin中执行如下配置

    1
    2
    3
    4
    5
    6
    7
    8
    from django.contrib import admin
      
    from bbs import  models
      
    admin.site.register(models.UserProfile)
    admin.site.register(models.Article)
    admin.site.register(models.Comments)
    admin.site.register(models.Category)

    b、设置数据表名称

    1
    2
    3
    4
    5
    6
    class UserType(models.Model):
        name = models.CharField(max_length=50)
      
        class Meta:
            verbose_name = '用户类型'
            verbose_name_plural = '用户类型'

    c、打开表之后,设定默认显示,需要在model中作如下配置

    1
    2
    3
    4
    5
    class UserType(models.Model):
        name = models.CharField(max_length=50)
      
        def __unicode__(self):
            return self.name
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    from django.contrib import admin
      
    from app01 import  models
      
    class UserInfoAdmin(admin.ModelAdmin):
        list_display = ('username''password''email')
      
      
    admin.site.register(models.UserType)
    admin.site.register(models.UserInfo,UserInfoAdmin)
    admin.site.register(models.UserGroup)
    admin.site.register(models.Asset)

    d、为数据表添加搜索功能

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    from django.contrib import admin
      
    from app01 import  models
      
    class UserInfoAdmin(admin.ModelAdmin):
        list_display = ('username''password''email')
        search_fields = ('username''email')
      
    admin.site.register(models.UserType)
    admin.site.register(models.UserInfo,UserInfoAdmin)
    admin.site.register(models.UserGroup)
    admin.site.register(models.Asset)

    bootstrap

      bootstrap的三个文件夹css fonts js放入statics目录下

      好看的页面下载全部到本地,会有个文件夹,包含了这个页面所用到的css,js,放入statics下的css和js目录下,下载下来的html页面中的css,js的引用路径需要换一下

    页面有不同的板块,点击板块高亮并且显示对应板块下的文章

    不同板块的都是同一模板html,只是显示的url不同,根据urls.py里面的别名做

    html :{% url 'category' i.id%} --category是urls.py的name

    urls.py: url(r'^category/(d+)/$',views.category,name='category') --前一个category是点击板块时显示的url

    点击板块显示文章并且高亮

    <li><a href="{% url 'category' i.id %}">{{ i.name }}</a></li>
    views.py拿到这个id后去文章表中取出板块对应的文章
    前端页面request.path得到当前页面的地址,通过js加上active,这段js需要写在base.html中

    图标base
    <link href="http://libs.baidu.com/fontawesome/4.0.3/css/font-awesome.css" rel="stylesheet">

    head_img
    simple_tag
    上传的图片找不到需要进行以下步骤
    app下新建templatetags目录
    目录下新建xxoo.py
    from django import template
    
    register = template.Library()
    @register.simple_tag
    
    def truncate_upload_img(img_src):
        return img_src.name.lstrip('/uploads/')

    前端页面引用的时候

    <img src="/static/{% truncate_upload_img i.head_img %}"

    分页

    views.py

    from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger

    paginator = Paginator(articles, 5)  # Show 5 contacts per page
    page = request.GET.get('page')url中传来的?page
    try:
    objs = paginator.page(page)
    except PageNotAnInteger:
    objs = paginator.page(1)
    except EmptyPage:
    objs = paginator.page(paginator.num_pages)
    return render(request,'index.html',{'category':categories,'article':objs})

    simple_tag

    def paginator_btn(article,page):
        current_page = article.number
        if abs(current_page-page)<3:
            ele = """<li><a href="?page={page}">{page}</a></li>""".format(page=page)
            return mark_safe(ele)
        return ''

    html 

                <nav aria-label="...">
                  <ul class="pagination">
                    <li class="disabled"><a href="#" aria-label="Previous"><span aria-hidden="true">&laquo;</span></a></li>
                    {% for page in article.paginator.page_range %}
                      {% if article.number == page %}
                        <li class="active"><a href="?page={{ page }}">{{ page }}<span class="sr-only">(current)</span></a></li>
                        {% else %}
                            {% paginator_btn article page %}
                        {% endif %}
                    {% endfor %}
                  </ul>
                </nav>
    发布文章ckeditor
    用modelform
    forms.py

    from django import forms
    from app01 import models
    
    class NewArticleForm(forms. ModelForm):
      #修改modelform的new方法,给字段加样式
    def __new__(cls, *args, **kwargs): for field_name in cls.base_fields: field = cls.base_fields[field_name] attr_dic = {'class':'form-control'} field.widget.attrs.update(attr_dic) return forms.ModelForm.__new__(cls)#还需要在调用下modelform原来的new方法 class Meta: model = models.Article fields = "__all__" exclude = ('priority','author')

    html
    因为有图片,所以form里面加上enctype='multipart/form-data'
    {% extends 'index.html' %}
    {% block extra_source %}
        <script src="/static/plugins//ckeditor/ckeditor.js"></script>
    {% endblock %}
    {% block container %}
        <form method="post" enctype="multipart/form-data">
    
            {% for field in form %}
                <div class="form-group">
                    <label  class="col-sm-2 control-label">{{ field.name }}</label>
                    <div class="col-sm-10">
                      {{ field }}
                        <span style="color: red">{{ field.errors }}</span>
                      <span style="color: red">{{ field.errors }}</span>
                    </div>
                </div>
    
            {% endfor %}
            <input type="submit" class="col-lg-offset-5 btn btn-sm btn-success" value="提交">
        </form>
    
                <script>
                    // Replace the <textarea id="editor1"> with a CKEditor
                    // instance, using default configuration.
                    CKEDITOR.replace( 'id_body' );
                </script>
    {% endblock %}

    views.py

    def new_article(request):
        if request.method == 'POST':
            form = forms.NewArticleForm(data=request.POST,files=request.FILES)
    
            if form.is_valid():
                print(request.user.id)
                form.cleaned_data['author_id'] = request.user.id
                tags = form.cleaned_data.pop('tags')
                obj = models.Article(**form.cleaned_data)
                obj.save()
                obj.tags.add(*tags)
                obj.save()
                return HttpResponse('''<h3><a href="/article/%s/">%s</a></h3>''' % (obj.id,obj.title) )
        elif request.method == 'GET':
            form = forms.NewArticleForm()
        return render(request,'new_article.html',{'form':form})

    *文章和tag是多对多的关系,只能先create对象,再add tags

    *因为添加modelform中去了author,所以只能在form.cleaned_data字典里面加上author_id,request.user.id就是当前用户的id

    *{{article.body | safe}}

    用户登录认证

    from django.contrib.auth import authenticate,login,logout
    from django.contrib.auth.decorators import login_required#django自带的装饰器

    def account(request):
    error={}
    if request.method == 'GET':
    return render(request,'login.html')
    if request.method == 'POST':
    username = request.POST.get('username')
    password = request.POST.get('password')
    user = authenticate(username=username,password=password)
      #如果认证成功,user是个对象
    if user:
    login(request,user)#如果认证成功,需要再login一下才能显示当前用户
    return redirect(request.GET.get('next') or '/category/all')
    else:
    error = {'error':'wrong username or password'}
    return render(request,'login.html',error)

    login.html

    {% extends "base.html" %}
    
    
    {% block body %}
    
        <div class="container">
          <div class="col-lg-3 col-lg-offset-4">
              <form class="form-signin" method="post"> {% csrf_token %}
                    <h2 class="form-signin-heading">1024黄鳝社区</h2>
                    <label for="inputEmail" class="sr-only">Username</label>
                    <input type="text" name="username" class="form-control" placeholder="username" required autofocus>
                    <label for="inputPassword" class="sr-only">Password</label>
                    <input type="password"  name="password" id="inputPassword" class="form-control" placeholder="Password" required>
    
                    <span style="color: red">{{ error }}</span>
                    <div class="checkbox">
                      <label>
                        <input type="checkbox" value="remember-me"> Remember me
                      </label>
                    </div>
                    <button class="btn btn-lg btn-primary btn-block" type="submit">Sign in</button>
              </form>
    
          </div>
    
    
        </div>
    
    
    {% endblock %}

    html

    <ul class="nav navbar-nav navbar-right">
                 <li class=""><a href="{% url 'new_article'  %}">发帖</a></li>#只有登录了,才能发帖,views.py里会验证
                 {% if request.user.is_authenticated %}
              #只有认证了,才显示当前用户
                     <li class="dropdown">
                      <a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false">{{ request.user }} <span class="caret"></span></a>
                      <ul class="dropdown-menu">
                        <li><a href="{% url 'logout' %}">Logout</a></li>
                      </ul>
                     </li>
                 {% else %}
                    <li class=""><a href="{% url 'login'  %}">登录</a></li>#这里默认会是accounts/login,需要在settings.py中修改,写上LOGIN_URL ="/account/login/"
     {% endif %} </ul>

    退出

    def acc_logout(request):
        logout(request)
        return redirect('/login')

    多级评论

    #1.把数据库里所有的这篇文章的评论查出来,转成字典

    #2.递归循环字典,生成html

    在文章html页加

        <div style="border: 1px dashed red">
        {% load_comments article%}
        </div>

    通过simple_tag业务逻辑全写在bbs_tags.py中

    from  django.template import Library
    from django.utils.safestring import mark_safe
    
    register = Library()
    
    @register.simple_tag
    def load_comments(article):
        comment_dic = {}#评论存在字典中
        comment_objs = article.comment_set.all().order_by('date')#通过文章反查comment
        for obj in comment_objs:
            if not obj.p_node:#就是顶级评论
                comment_dic[obj] = {}
            else:#不是顶级评论
                build_comment_tree(comment_dic,obj)
        comment_list = sorted(comment_dic.items(),key=lambda x:x[0].date)#按时间顺序排列
        print(comment_dic)
        return(comment_dic)
    def build_comment_tree(comment_dic,obj):
        for k,v in comment_dic.items():
            if obj.p_node == k:找到父级评论
                comment_dic[k][obj]={}
            else:#开始深度查找
                build_comment_tree(comment_dic[k],obj)

    字典转换成html格式

    @register.simple_tag
    def load_comments(article):
        comment_dic = {}
        comment_objs = article.comment_set.all().order_by('date')
        for obj in comment_objs:
            if not obj.p_node:
                comment_dic[obj] = {}
            else:
                build_comment_tree(comment_dic,obj)
        comment_list = sorted(comment_dic.items(),key=lambda x:x[0].date)
        print(comment_list)
        comment_html = """"""
        for comment_branch in comment_list:
            margin=0
            html_ele = """<div style="border:1px dashed red">{user}--{date}--{comment}</div>"""
                .format(user=comment_branch[0].user,
                        date=comment_branch[0].date.strftime('%Y-%M-%D %H:%M:%S'),
                        comment = comment_branch[0].comment)
            comment_html += html_ele
            comment_html += build_comment_html(comment_branch[1],margin+20)
    
        return mark_safe(comment_html)
    
    def build_comment_tree(comment_dic,obj):
        for k in comment_dic:
            if obj.p_node == k:
                comment_dic[k][obj]={}
            else:
                build_comment_tree(comment_dic[k],obj)
    def build_comment_html(comment_branch,margin):
        comment_ele = """"""
        for k,v in comment_branch.items():
            comment_ele += """<div style="border:1px dashed red;margin-left:{margin}px">{user}--{date}--{comment}</div>""" 
                .format(margin=margin,
                        user=k.user,
                        date=k.date.strftime('%Y-%M-%D %H:%M:%S'),
                        comment=k.comment,
                        )
            if v:
                comment_ele += build_comment_html(comment_branch[k],margin+20)
        return comment_ele
  • 相关阅读:
    python学习笔记(33)pycharm中使用git
    VUE基础3-过滤器与生命周期
    VUE基础2-双向数据绑定
    VUE基础1方法与指令
    HTML基础之JS
    HTML基础之DOM操作
    HTML基础之CSS
    HTML基础之HTML标签
    python学习笔记(32)多线程&多进程
    python学习笔记(30)深拷贝、浅拷贝
  • 原文地址:https://www.cnblogs.com/hongpeng0209/p/6593143.html
Copyright © 2020-2023  润新知