準備css
新建工程html
django-admin startproject BBS前端
新建appnode
python3 manage.py startapp bbspython
設計表結構數據庫
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=Truedjango
django amdin是django提供的一個後臺管理頁面,該管理頁面提供完善的html和css,使得你在經過Model建立完數據庫表以後,就能夠對數據進行增刪改查,而使用django admin 則須要如下步驟:bootstrap
一、建立後臺管理員app
1
|
python manage.py createsuperuser
|
二、配置後臺管理urlpost
1
|
url(r
'^admin/'
, include(admin.site.urls))
|
三、註冊和配置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">«</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