• 开发BBS论坛


    一、涉及表结构

    webmodel.py(首选需要注意表结构的设计,如果表结构设计出来了,软件的架构也就基本出来了)

    #!/usr/bin/env python
    # _*_ coding:utf-8 _*_
    from django.db import models
    
    # Create your models here.
    from django.contrib.auth.models import User   #导入django自带的用户认证表
    
    class Article(models.Model):
        '''文章帖子'''
        title = models.CharField(u'文章标题',max_length=255,unique=True)    #帖子不可以重名,可以加注释,在admin中展示内容为'文章标题'
        category=models.ForeignKey("Category",verbose_name=u'板块')    #发布板块,必须加引号,因为Category是在下面的,加引号可以通过反射的方式进行查找,不会找不到;如果注释不是放在第一个位置,那么就需要使用verbose_name
        head_img = models.ImageField(upload_to="uploads")   #传文件,默认会传到当前项目的根目录下面,通过upload_to指定传送到的目录
        summary=models.CharField(max_length=255)
        content=models.TextField(u'内容')  #因为文章中会存很多的内容,所以不能够使用charfiled规定最大长度,使用TextField可以不指定长度
        author=models.ForeignKey("UserProfile")
        public_date=models.DateTimeField(auto_now=True)    #自动创建日期,auto_now_add表示每一次更新的时间,auto_now表示每一次创建的时间
        hidden=models.BooleanField(default=True)   #是否影藏
        priority=models.IntegerField(u'优先级',default=1000)   #有些帖子长期可以置顶,通过优先级实现
        def __unicode__(self):    #设置默认返回值,在admin中对于增加的每一条数据就会显示return的结果
            return "<%s,author>%s" %(self.title,self.author)
    
    class Comment(models.Model):
        '''评论'''
        article=models.ForeignKey("Article")
        user = models.ForeignKey("UserProfile")
        parent_comment=models.ForeignKey('self',related_name='p_comment',blank=True,null=True)  #以自己的表为外键关联的表,可以为自己的表名或者为self,django会在自己的表中多创建一个字段,related_name必须给出,否则会报错;
        # blank=True表示admin中可以为空,null=True表示在数据库表中可以为空
        comment=models.TextField(max_length=1000)    #评论的内容,可以有最大数量限制
        date=models.DateTimeField(auto_now=True)
        def __unicode__(self):
            return "<%s,user:%s>" %(self.comment,self.user)
        '''
        parent  self    son
        Null    1       null
        1       2       null
        1       3       null
        2       4       null
        每一条评论只需要关注自己和自己的第一条子评论,就是多了一个字段,SQL不支持,是通过代码级别实现的
        '''
        '''
        python manage.py migrate 只会创建django自己的数据库表
        第二次 会创建用户自定义的数据库表
        '''
    class ThumbUp(models.Model):
        '''点赞'''
        article=models.ForeignKey("Article")
        user=models.ForeignKey("UserProfile")
        date=models.DateTimeField(auto_now=True)
        def __unicode__(self):
            return "<user:%s>" %self.user
    
    class Category(models.Model):
        '''板块'''
        name=models.CharField(max_length=64,unique=True)
        admin=models.ManyToManyField("UserProfile")
        def __unicode__(self):
            return self.name
    
    class UserProfile(models.Model):
        '''账户信息表'''
        user=models.OneToOneField(User)   #继承自带的User表,但是原生的user表中的字段较少,可以继承之后可以扩展字段;
    只能使用onetoone,否则就会使得多个用户同时关联一个账户onetoone是在代码层面进行限制的,其实就是将两张表进行拼接了 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

     使用admin管理数据库

    from django.contrib import admin
    
    # Register your models here.
    class CategroyAdmin(admin.ModelAdmin):
        list_display = ('id','name')
    class CommentAdmin(admin.ModelAdmin):
        list_display = ('id','parent_comment','comment','date')
    class ArticleAdmin(admin.ModelAdmin):
        list_display = ('id','title','author','hidden','public_date')   #注意list_display中的字段。一定需要和数据库张的匹配,否则会报错
    import models
    admin.site.register(models.Article,ArticleAdmin)
    admin.site.register(models.Category,CategroyAdmin)
    admin.site.register(models.Comment,CommentAdmin)
    admin.site.register(models.ThumbUp)
    admin.site.register(models.UserProfile)
    admin.site.register(models.UserGroup)

    显示结果是这样的

    创建两张表

    mysql> show tables;
    +-----------------------------+
    | Tables_in_stupid_jumpserver |
    +-----------------------------+
    | host                        |
    | host_user                   |
    +-----------------------------+
    rows in set (0.00 sec)
    
    mysql> desc host;
    +----------+-------------+------+-----+---------+----------------+
    | Field    | Type        | Null | Key | Default | Extra          |
    +----------+-------------+------+-----+---------+----------------+
    | id       | int(11)     | NO   | PRI | NULL    | auto_increment |
    | hostname | varchar(64) | NO   | UNI | NULL    |                |
    | ip_addr  | varchar(64) | NO   | UNI | NULL    |                |
    | port     | int(11)     | YES  |     | NULL    |                |
    +----------+-------------+------+-----+---------+----------------+
    rows in set (0.00 sec)
    
    mysql> desc host_user;
    +-----------+--------------+------+-----+---------+----------------+
    | Field     | Type         | Null | Key | Default | Extra          |
    +-----------+--------------+------+-----+---------+----------------+
    | id        | int(11)      | NO   | PRI | NULL    | auto_increment |
    | host_id   | int(11)      | YES  | MUL | NULL    |                |
    | auth_type | varchar(255) | YES  |     | NULL    |                |
    | username  | varchar(64)  | NO   | UNI | NULL    |                |
    | password  | varchar(255) | YES  |     | NULL    |                |
    +-----------+--------------+------+-----+---------+----------------+
    rows in set (0.00 sec)
    
    其中:PRI表示主键,MUL表示外键,UNI表示该值是唯一的;
    View Code

    向表中插入数据

    mysql> select * from host;
    +----+-----------+----------+------+
    | id | hostname  | ip_addr  | port |
    +----+-----------+----------+------+
    |  7 | h2        | 10.0.0.2 |   22 |
    |  6 | localhost | 10.0.0.1 |   22 |
    |  8 | h3        | 10.0.0.3 |   22 |
    |  9 | h5        | 10.0.0.5 |   22 |
    +----+-----------+----------+------+
    4 rows in set (0.00 sec)
    
    mysql> select * from host_user;
    +----+---------+-----------+----------+----------+
    | id | host_id | auth_type | username | password |
    +----+---------+-----------+----------+----------+
    |  5 |       7 | ssh       | charles  | 123      |
    |  4 |       6 | ssh       | root     | 123      |
    |  6 |       8 | ssh       | ul       | 123      |
    |  7 |    NULL | ssh       | Rain     | 123      |
    +----+---------+-----------+----------+----------+
    4 rows in set (0.01 sec)
    View Code

    两张表通过外键做关联查询

    inner join表示取两者的交集
    mysql> select * from host_user inner join host on host_user.host_id=host.id;
    +----+---------+-----------+----------+----------+----+-----------+----------+------+
    | id | host_id | auth_type | username | password | id | hostname  | ip_addr  | port |
    +----+---------+-----------+----------+----------+----+-----------+----------+------+
    |  5 |       7 | ssh       | charles  | 123      |  7 | h2        | 10.0.0.2 |   22 |
    |  4 |       6 | ssh       | root     | 123      |  6 | localhost | 10.0.0.1 |   22 |
    |  6 |       8 | ssh       | ul       | 123      |  8 | h3        | 10.0.0.3 |   22 |
    +----+---------+-----------+----------+----------+----+-----------+----------+------+
    rows in set (0.00 sec)
    
    left join
    mysql> select * from host_user left join host on host_user.host_id=host.id; 
    +----+---------+-----------+----------+----------+------+-----------+----------+------+
    | id | host_id | auth_type | username | password | id   | hostname  | ip_addr  | port |
    +----+---------+-----------+----------+----------+------+-----------+----------+------+
    |  5 |       7 | ssh       | charles  | 123      |    7 | h2        | 10.0.0.2 |   22 |
    |  4 |       6 | ssh       | root     | 123      |    6 | localhost | 10.0.0.1 |   22 |
    |  6 |       8 | ssh       | ul       | 123      |    8 | h3        | 10.0.0.3 |   22 |
    |  7 |    NULL | ssh       | Rain     | 123      | NULL | NULL      | NULL     | NULL |
    +----+---------+-----------+----------+----------+------+-----------+----------+------+
    rows in set (0.00 sec)
    
    right join
    mysql> select * from host_user right join host on host_user.host_id=host.id;    
    +------+---------+-----------+----------+----------+----+-----------+----------+------+
    | id   | host_id | auth_type | username | password | id | hostname  | ip_addr  | port |
    +------+---------+-----------+----------+----------+----+-----------+----------+------+
    |    5 |       7 | ssh       | charles  | 123      |  7 | h2        | 10.0.0.2 |   22 |
    |    4 |       6 | ssh       | root     | 123      |  6 | localhost | 10.0.0.1 |   22 |
    |    6 |       8 | ssh       | ul       | 123      |  8 | h3        | 10.0.0.3 |   22 |
    | NULL |    NULL | NULL      | NULL     | NULL     |  9 | h5        | 10.0.0.5 |   22 |
    +------+---------+-----------+----------+----------+----+-----------+----------+------+
    rows in set (0.00 sec)
    View Code

     二、利用admin来管理数据库以及创建数据库表的字段

    from django.contrib import admin
    import models
    # Register your models here.
    class CategroyAdmin(admin.ModelAdmin):
        list_display = ('id','name')
    class ArticleAdmin(admin.ModelAdmin):
        list_display = ('id','title','author','hidden','publish_date')   #创建表字段
    
    class CommentAdmin(admin.ModelAdmin):
        list_display = ('id','parent_comment','comment','date')
    admin.site.register(models.Article,ArticleAdmin)
    admin.site.register(models.Category,CategroyAdmin)
    admin.site.register(models.Comment,CommentAdmin)
    admin.site.register(models.ThumbUp)
    admin.site.register(models.UserProfile)
    admin.site.register(models.UserGroup)
    View Code

    二、静态文件配置

    settings.py

    STATIC_URL = '/static/'    #静态文件的前缀,相当于一个别名,是一个入口的存在,通过这个入口可以找到所有STATICFILES_DIRS中的静态文件
    STATICFILES_DIRS=(               #可以存多个静态文件的路径,在调用静态路径的时候,静态文件都会在指定的各个目录下面找
        "%s%s" %(BASE_DIR,'statics'),
        #os.path.join(BASE_DIR,'static'),
    )

    index.html

        <link href="/static/bootstrap/css/bootstrap.min.css" rel="stylesheet">
    
        <!-- Custom styles for this template -->
        <link href="/static/bootstrap/css/navbar-fixed-top.css" rel="stylesheet">
        <link href="/static/bootstrap/css/custom.css" rel="stylesheet">

    三、利用url传递参数页面的自动切换

    from django.conf.urls import include, url
    from django.contrib import admin
    from web import views
    
    urlpatterns = [
        url(r'^admin/', include(admin.site.urls)),
        url(r'^$',views.index, name="index" ),
        url(r'^category/(d+)/$',views.category,name="category" ),     #通过不同的数字引用不同的urls
        url(r'^article/(d+)/$',views.article_detail,name="article_detail"),      
        url(r'^article/new/$',views.new_article,name="new_article"),
        url(r'account/logout/',views.acc_logout,name='logout'),
        url(r'account/login/',views.acc_login,name='login'),
    ]
    urls
              <ul class="nav navbar-nav">
                <li ><a href="{% url 'index' %}">综合区</a></li>
                <li><a href="{% url 'category' 1 %}">欧美专区</a></li>
                <li><a href="{% url 'category' 2 %}">日韩专区</a></li>
                <li><a href="{% url 'category' 3 %}">河北区</a></li>
    
              </ul>
    index.html

     对于点击的标签,增加active属性

    index.html   对于每一个标签,被选中的时候,应该添加active属性,

            $(document).ready(function(){
                var menus = $("#navbar a[href='{{ request.path }}']")[0];    //返回的是列表,在js中引用template的变量,request.path表示请求的路径,因为在点击的时候回切换页面,如果页面不切换,可以直接找到 #nvabar li来实现
                $(menus).parent().addClass("active");
                $(menus).parent().siblings().removeClass("active");
                //console.log(menus);
            });

    三、实现用户登录和注销

          <ul class="nav navbar-nav navbar-right">
    
                   {% if request.user.is_authenticated %}
                    <li class="dropdown">
                      <a href="http://v3.bootcss.com/examples/navbar-fixed-top/#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false">{{ request.user.userprofile.name }} <span class="caret"></span></a>
                      <ul class="dropdown-menu">
                        <li><a href="{% url 'new_article' %}">发贴</a></li>
                        <li><a href="http://v3.bootcss.com/examples/navbar-fixed-top/#">Another action</a></li>
                        <li><a href="http://v3.bootcss.com/examples/navbar-fixed-top/#">Something else here</a></li>
                        <li role="separator" class="divider"></li>
                        <li class="dropdown-header">Nav header</li>
                        <li><a href="http://v3.bootcss.com/examples/navbar-fixed-top/#">Separated link</a></li>
                        <li><a href="{% url 'logout' %}">注销</a></li>
                      </ul>
                    </li>
                   {% else %}
                     <li><a href="{% url 'login'%}">注册登录</a></li>
                   {% endif %}
              </ul>
    index.html
    from django.conf.urls import include, url
    from django.contrib import admin
    from web import views
    
    urlpatterns = [
        url(r'^admin/', include(admin.site.urls)),
        url(r'^$',views.index, name="index" ),
        url(r'^category/(d+)/$',views.category,name="category" ),
        url(r'^article/(d+)/$',views.article_detail,name="article_detail"),
        url(r'^article/new/$',views.new_article,name="new_article"),
        url(r'account/logout/',views.acc_logout,name='logout'),
        url(r'account/login/',views.acc_login,name='login'),
    ]
    urls
    from django.contrib.auth import authenticate,login,logout
    def acc_logout(request):
        logout(request)     #直接调用django自己的logout函数
        return HttpResponseRedirect('/')     #跳转到首页
    def acc_login(request):
        print(request.POST)
        err_msg =''
        if request.method == "POST":
            print('user authention...')
            username = request.POST.get('username')
            password = request.POST.get('password')
            user = authenticate(username=username,password=password)
            if user is not None:
                login(request,user)
                return HttpResponseRedirect('/')
            else:
                err_msg = "Wrong username or password!"
        return render(request,'login.html',{'err_msg':err_msg})
    views

    views.py

    #!/usr/bin/env python
    #! _*_ coding:utf-8 _*_
    from django.shortcuts import render
    from web import models
    from django.core.exceptions import ObjectDoesNotExist
    from web import forms
    # Create your views here.
    
    def index(request):
        articles=models.Article.objects.all()
        return render(request,'index.html',{'articles':articles})
    
    def category(request,category_id):
        print "-->",category_id
        articles=models.Article.objects.filter(category_id=category_id)    #根据各个板块的id找到各个板块下面的对应的数据
        return render(request,'index.html',{'articles':articles})
    
    def article_detail(request,article_id):
        try:
            article_obj=models.Article.objects.get(id=article_id)
        except ObjectDoesNotExist as e:
            return render(request,'404.html',{'err_msg':u'xxxxx'})
        return render(request,'article.html',{'article_obj':article_obj})
    
    def new_article(request):
        if request.method=='POST':
            print request.POST
            form=forms.ArticleForm(request.POST,request.FILES)
            if form.is_valid():
                print "--form data",form.cleaned_data
                form_data = form.cleaned_data
                form_data['author_id']=request.user.userprofile.id    #author_id必须写,否则数据库会报错,request.user表示当前请求登录的用户
                new_img_path=forms.handle_uploaded_file(request,request.FILES.id)
                form_data['head_img']=new_img_path
                new_article_obj=models.Article(**form_data)
                return render(request,'new_article.html',{'new_article_obj':new_article_obj})
            else:
                print {'err':form.errors}
        category_list=models.Category.objects.all()
        return render(request,'new_article.html',{'category_list':category_list})
    def acc_logout(request):
        pass
    
    def acc_login(request):
        pass

    四、CSRF

    {% extends 'index.html' %}
    
    
    {% block page-container %}
    
    <div class="col-md-4">
        <form class="form-signin" action="{% url 'login' %}" method="post">{% csrf_token %}     //必须加{% csrf_token %}
            <h2 class="form-signin-heading">Please sign in</h2>
            <label for="inputEmail" class="sr-only">用户名</label>
            <input type="text" id="" 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="">
            <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>
            <p style="color:red;">{{ err_msg }}</p>
        </form>
    </div>
    
    
    {% endblock %}
    login.html
    def acc_login(request):
        print(request.POST)
        err_msg =''
        if request.method == "POST":
            print('user authention...')
            username = request.POST.get('username')
            password = request.POST.get('password')
            user = authenticate(username=username,password=password)
            if user is not None:
                login(request,user)
                return HttpResponseRedirect('/')
            else:
                err_msg = "Wrong username or password!"
        return render(request,'login.html',{'err_msg':err_msg})   #使用csrf,视图中必须使用render
    views.py

    五、实现用户登录

    def acc_login(request):
        print(request.POST)
        err_msg =''
        if request.method == "POST":
            print('user authention...')
            username = request.POST.get('username')
            password = request.POST.get('password')
            user = authenticate(username=username,password=password)   #authenticate函数会自动到数据库取用户数据进行验证
            if user is not None:      #函数没有取到值就会返回None
                login(request,user)
                return HttpResponseRedirect('/')
            else:
                err_msg = "Wrong username or password!"
        return render(request,'login.html',{'err_msg':err_msg})   #使用csrf,视图中必须使用render
    View Code

     http://ueditor.baidu.com/website/  百度插件,但是不支持python,网站已经有人通过修改支持django了,可以try一下;

    http://ckeditor.com/demo   非常好用的插件,支持python,使用full featured版本,比较全

     六、后台通过forms对表单进行验证

    def new_article(request):
        if request.method == 'POST':
            print(request.POST)
            form = ArticleForm(request.POST,request.FILES)
            if form.is_valid():
                print("--form data:",form.cleaned_data)
                form_data = form.cleaned_data
                form_data['author_id'] = request.user.userprofile.id
    
                new_img_path = handle_uploaded_file(request,request.FILES['head_img'])
                form_data['head_img'] = new_img_path
                new_article_obj = models.Article(**form_data)     #将数据插入到数据库中,new_article_obj表示文章是否创建成功
                new_article_obj.save()    #这样比model.Article.object.all(**form_data)创建有好处,可以之间通过new_article_obj.元素在html中显示内容是否创建成功
                return  render(request,'new_article.html',{'new_article_obj':new_article_obj})
            else:
                print('err:',form.errors)
        category_list = models.Category.objects.all()
        return render(request,'new_article.html', {'categroy_list':category_list})
    views.py
    {% block page-container %}
       <div class="new-article">
        {% if new_article_obj %}
            <h3>文章<{{ new_article_obj.title }}>已发布,<a href="{% url 'article_detail' new_article_obj.id %}"> 点我查看</a></h3>
        {% else %}
           <form  enctype="multipart/form-data" method="post" action="{% url 'new_article' %}">{% csrf_token %}
            <input name="title" type="text" class="form-control" placeholder="文章标题">
            <select name="categroy_id" class="form-control">
              {% for category in categroy_list %}
                <option value="{{ category.id }}">{{ category.name }}</option>
              {% endfor %}
            </select>
            <input name="summary" type="text" class="form-control" placeholder="一句话文章中心思想...">
            <input type="file" name="head_img">必选文章标题图片
            <textarea id="ck-editor" name="content" class="form-control" rows="3"></textarea>
    
            <br/>
           <button type="submit" class="btn btn-success pull-right">发贴</button>
    
        </form>
        {% endif %}
       </div>
    {% endblock %}
    new_article.html

     forms.py

    #!/usr/bin/env python
    # -*- coding:utf-8 -*-
    from django import forms
    import os
    class ArticleForm(forms.Form):
        title=forms.CharField(max_length=255,min_length=5)
        summary=forms.CharField(max_length=255,min_length=5)
        category_id=forms.ImageField()
        content=forms.CharField(min_length=10)
    
    def handle_uploaded_file(request,f):    #将request.FILES传送进来
        base_img_upload_path='static/img'
        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 destination:
            for chunk in f.chunks():    #chunk内部其实就是yield方法
                destination.write(chunk)
        return "/static/imgs/%s/%s" %(request.user.userprofile.id,f.name)

    七、评论树的实现

    #!/usr/bin/env python
    # -*- coding:utf-8 -*-
    '''通过递归的方式将data中的数据按照层级的关系存入新的字典中'''
    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_dic in d_dic.items():
            if k == parent: #find your parent    #判断第一层是否为父亲
                d_dic[k][son] = {}
                print("find parent of :", son)
                return
            else: # might in the deeper layer   #否则往更深了找
                print("going to furhter layer...")
                tree_search(d_dic[k],parent,son)
    
    
    data_dic = {}
    
    for item in data:   #循环将每一个元素取出来,放入到函数中进行递归处理
        parent,son = item    #item代表两个值
        if parent is None:# has no parent    #判断parents是否为空
            data_dic[son] ={}
        else: #  looking for its parent
            tree_search(data_dic,parent,son)   #递归判断字典中,父亲和儿子
    
    for k,v in data_dic.items():
        print(k,v )
    
    '''
    data_dic = {
        'A': {
            'A1': {
                'A2':{
                    'A3':{
                        'A4':{}
                    }
                },
                'A2-2':{
                    'A3-3':{}
                }
            }
        },
        'B':{
            'B1':{
                'B2':{
                    'B3':{}
                },
                'B2-2':{}
            }
        },
        'C':{
            'C1':{}
        }
    
    }'''
    '''多级评论树的实现,是将data转换为下面类型的字典'''

     对于前段template来说,只能有for循环,无法实现上述的递归,只能通过simple_tag返回html字符串

    custom_tags.py

    #!/usr/bin/env python
    # -*- coding:utf-8 -*-
    from django import template
    
    register = template.Library()
    
    def tree_search(d_dic,comment_obj):
        for k,v_dic in d_dic.items():
            if k == comment_obj.parent_comment: #find parent
                d_dic[k][comment_obj] = {}
                return
            else: #going deeper....;
                tree_search(d_dic[k],comment_obj)
    
    
    def generate_comment_html(sub_comment_dic,margin_left_val):
        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):
        #print("commment_list:",comment_list)
    
        comment_dic = {}
        for comment_obj in comment_list:
            if comment_obj.parent_comment is None:#no parent
                comment_dic[comment_obj] ={}
            else: #has farther ,
                tree_search(comment_dic,comment_obj)
    
        # tree is built
    
        # pin html str
        html = "<div class='comment-box'>"
        margin_left = 0
        for k,v in comment_dic.items():
            print(k,v )
            html  += "<div class='comment-node'>" + k.comment + "</div>"
            html += generate_comment_html(v,margin_left+15)
    
        html += "</div>"
        return html

    aticle.html

    {% extends 'index.html' %}
    {% load custom_tags %}
    
    {% block page-container %}
       <div class="article-detail">
            <h4>{{ article_obj.title }}</h4>
    
            <p>{{ article_obj.content|safe }}</p>
    
            <hr/>
            {%  build_comment_tree article_obj.comment_set.select_related %}   //通过article找到评论表的的评论
       </div>
    {% endblock %}

    index.html

    <!DOCTYPE html>
    <!-- saved from url=(0048)http://v3.bootcss.com/examples/navbar-fixed-top/ -->
    <html lang="zh-CN"><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
        <meta charset="utf-8">
        <meta http-equiv="X-UA-Compatible" content="IE=edge">
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <!-- 上述3个meta标签*必须*放在最前面,任何其他内容都*必须*跟随其后! -->
        <meta name="description" content="">
        <meta name="author" content="">
        <link rel="icon" href="http://v3.bootcss.com/favicon.ico">
    
        <title>Oldboy BBS</title>
    
        <!-- Bootstrap core CSS -->
        <link href="/static/bootstrap/css/bootstrap.min.css" rel="stylesheet">
    
        <!-- Custom styles for this template -->
        <link href="/static/bootstrap/css/navbar-fixed-top.css" rel="stylesheet">
        <link href="/static/bootstrap/css/custom.css" rel="stylesheet">
        {% block head-js %}
        {% endblock %}
      </head>
    
      <body>
    
        <!-- Fixed navbar -->
        <nav class="navbar navbar-default navbar-fixed-top">
          <div class="container">
            <div class="navbar-header">
              <button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#navbar" aria-expanded="false" aria-controls="navbar">
                <span class="sr-only">Toggle navigation</span>
                <span class="icon-bar"></span>
                <span class="icon-bar"></span>
                <span class="icon-bar"></span>
              </button>
              <a class="navbar-brand" href="http://v3.bootcss.com/examples/navbar-fixed-top/#">电影</a>
            </div>
            <div id="navbar" class="navbar-collapse collapse">
              <ul class="nav navbar-nav">
                <li ><a href="{% url 'index' %}">综合区</a></li>
                <li><a href="{% url 'category' 1 %}">电视剧专区</a></li>
                <li><a href="{% url 'category' 2 %}">日韩专区</a></li>
                <li><a href="{% url 'category' 3 %}">河北区</a></li>
    
              </ul>
              <ul class="nav navbar-nav navbar-right">
    
                   {% if request.user.is_authenticated %}
                    <li class="dropdown">
                      <a href="http://v3.bootcss.com/examples/navbar-fixed-top/#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false">{{ request.user.userprofile.name }} <span class="caret"></span></a>
                      <ul class="dropdown-menu">
                        <li><a href="{% url 'new_article' %}">发贴</a></li>
                        <li><a href="http://v3.bootcss.com/examples/navbar-fixed-top/#">Another action</a></li>
                        <li><a href="http://v3.bootcss.com/examples/navbar-fixed-top/#">Something else here</a></li>
                        <li role="separator" class="divider"></li>
                        <li class="dropdown-header">Nav header</li>
                        <li><a href="http://v3.bootcss.com/examples/navbar-fixed-top/#">Separated link</a></li>
                        <li><a href="{% url 'logout' %}">注销</a></li>
                      </ul>
                    </li>
                   {% else %}
                     <li><a href="{% url 'login'%}">注册登录</a></li>
                   {% endif %}
              </ul>
            </div><!--/.nav-collapse -->
          </div>
        </nav>
    
        <div class="container">
         {% block page-container %}
            <div class="row">
                <div class="col-md-8 left-content-panel">
                    <div class="content-box">
                        {% for article in articles reversed %}
                            <div class="article-box row">
                                <div class="article-head-img col-md-3">
                                    <img src="{{ article.head_img }}">
                                </div>
                                <div class="article-summary col-md-8">
                                    <h4><a href="{% url 'article_detail' article.id %}">{{ article.title }}</a></h4>
                                    <div class="article-attr">
                                        <ul  class="list-inline">
                                            <li>{{ article.author.name }}</li>
                                            <li>{{ article.publish_date }}</li>
                                            <li>thumbup:{{ article.thumbup_set.select_related.count }}</li>    //thumbup的article的字段的外键关联到article表,通过
    article.thumbup_set.select_related来反向找到原表的字段(一对多),为列表类型, 
    <li>comments:{{ article.comment_set.select_related.count }}</li> </ul> </div> <p>{{ article.summary }}</p> </div> </div> <hr > {% endfor %} </div> </div> <div class="col-md-4 right-sidebar"> bar </div> </div> {% endblock %} </div> <!-- /container --> <!-- Bootstrap core JavaScript ================================================== --> <!-- Placed at the end of the document so the pages load faster --> <script src="/static/bootstrap/js/jquery-2.1.4.js"></script> <script src="/static/bootstrap/js/bootstrap.min.js"></script> <!-- IE10 viewport hack for Surface/desktop Windows 8 bug --> <script src="/static/bootstrap/js/ie10-viewport-bug-workaround.js"></script> <script type="text/javascript"> $(document).ready(function(){ var menus = $("#navbar a[href='{{ request.path }}']")[0]; //返回的是列表,在js中引用template的变量,request.path表示请求的路径,因为在点击的时候回切换页面,如果页面不切换,可以直接找到 #nvabar li来实现 $(menus).parent().addClass("active"); $(menus).parent().siblings().removeClass("active"); //console.log(menus);  }); </script> {% block bottom-js %} {% endblock %} </body></html>

    new_article.html

    {% extends 'index.html' %}
    {% block head-js %}
       <script src="/static/plugins/ckeditor/ckeditor.js"></script>
    {% endblock %}
    
    {% block page-container %}
       <div class="new-article">
        {% if new_article_obj %}
            <h3>文章<{{ new_article_obj.title }}>已发布,<a href="{% url 'article_detail' new_article_obj.id %}"> 点我查看</a></h3>
        {% else %}
           <form  enctype="multipart/form-data" method="post" action="{% url 'new_article' %}">{% csrf_token %}  //跨站请求伪造
            <input name="title" type="text" class="form-control" placeholder="文章标题">
            <select name="categroy_id" class="form-control">
              {% for category in categroy_list %}
                <option value="{{ category.id }}">{{ category.name }}</option>
              {% endfor %}
            </select>
            <input name="summary" type="text" class="form-control" placeholder="一句话文章中心思想...">
            <input type="file" name="head_img">必选文章标题图片
            <textarea id="ck-editor" name="content" class="form-control" rows="3"></textarea>
    
            <br/>
           <button type="submit" class="btn btn-success pull-right">发贴</button>
    
        </form>
        {% endif %}
       </div>
    {% endblock %}
    
    {% block bottom-js %}
        <script>
             CKEDITOR.replace( 'ck-editor' );
            CKEDITOR.editorConfig = function( config ) {
                //config.language = 'es';
                config.uiColor = '#F7B42C';
                config.height = 500;
                config.toolbarCanCollapse = true;
            };
        </script>
    {% endblock %}

     八、图片文件上传之后无法根据上传的路径显示的问题

    图片会上传到我们指定的upload_to路径下面;

    class Article(models.Model):
        '''文章帖子'''
        title = models.CharField(u'文章标题',max_length=255,unique=True)    #帖子不可以重名,可以加注释,在admin中展示内容为'文章标题'
        category=models.ForeignKey("Category",verbose_name=u'板块')    #发布板块,必须加引号,因为Category是在下面的,加引号可以通过反射的方式进行查找,不会找不到;如果注释不是放在第一个位置,那么就需要使用verbose_name
        head_img = models.ImageField(upload_to="uploads") 

    但是该路径html无法找到,看下图:

    如果在settings中指定该静态文件路径,依然找不到,因为会去/static/uploads/uploads去找,使用下面的路径就可以找到:

    STATICFILES_DIRS=(               #可以存多个静态文件的路径,在调用静态路径的时候,静态文件都会在指定的各个目录下面找
        "%s%s" %(BASE_DIR,'statics'),
        'uploads'
        #os.path.join(BASE_DIR,'static'),
    )

  • 相关阅读:
    delphi res 字符串资源
    delphi label1 文字在窗体上水平来回移动
    delphi Edit
    delphi CoolBar这个怎么弄没了
    delphi Components[i]清除所有edit控件中的内容
    delphi Caption 垂直显示标签文本
    delphi array应用 DayOfWeek星期几判断
    delphi 2010 资源文件使用
    delphi 18 屏蔽和替换 右键菜单
    delphi 16 网页缩放
  • 原文地址:https://www.cnblogs.com/cqq-20151202/p/5631651.html
Copyright © 2020-2023  润新知