最近在学习一些WEB相关知识,这篇博文用于记录一些知识点,基于Django2.2来编写。
初始化
新建虚拟环境
安装virtualenv:
virtualenv使用:
1 2 3 4 5 6
| virtualenv <虚拟环境名称>
activate
deactiavte
|
一键导出/安装扩展
命令提示符下:
1 2
| pip freeze > requirements.txt pip install -r requirements.txt
|
基础知识
新建项目
CMD下输入:django-admin startproject <项目名>
初始化数据库
CMD下输入:python manage.py migrate
启动本地项目
CMD下输入:python manage.py runserver
创建管理员
CMD下输入:python manage.py createsuperuser
创建应用
CMD下输入:python manage.py startapp <应用名>
在app目录下定义models.py,例如:
1 2 3
| class Article(models.Model): title = models.CharField(max_length=30) content = models.TextField()
|
保存后在项目目录下,settings.py注册该应用:
CMD下执行:
basic1 2
| python manage.py makemigrations python manage.py migrate
|
在应用目录下,编辑admin.py:
1 2
| from .models import Article admin.site.register(Article)
|
绑定url
在项目目录下,编辑urls.py,参考注释:
1 2
| Add an import: from my_app import views Add a URL to urlpatterns: path('', views.home, name='home')
|
注意事项
公用全局设置可放在settings中,统一管理
1 2
| from django.conf import settings settings.XXX
|
进阶知识
定制admin后台
在应用目录下,models.py中的类中,增加__str__
方法,例如:
1 2 3 4 5 6 7 8 9
| from django.db import models
class Article(models.Model): title = models.CharField(max_length=30) content = models.TextField() def __str__(self): return "<Article: %s>" % self.title
|
项目目录下的admin.py:
1 2 3 4 5 6 7 8 9 10 11
| from django.contrib import admin from .models import Article
@admin.register(Article) class ArticleAdmin(admin.ModelAdmin): list_display = ('id','title','content') ordering = ('id',)
|
修改模型
模型修改后要重新执行
1 2
| python manage.py makemigrations python manage.py migrate
|
增加其他参数
修改models.py,增加如下内容:
1 2 3 4 5 6 7
| from django.utils import timezone
class Article(models.Model): ...... created_time = models.DateTimeField(auto_now_add=True) last_updated_time = models.DateTimeField(auto_now=True) author = models.ForeignKey(User, on_delete=models.DO_NOTHING,default=1)
|
相应的应于admin中的list_display增加字段。
给类增加默认排序,在父类中增加子类,形如:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| from django.db import models from django.contrib.auth.models import User
class BlogType(models.Model): type_name = models.CharField(max_length=15)
def __str__(self): return self.type_name
class Blog(models.Model): title = models.CharField(max_length=50) blog_type = models.ForeignKey(BlogType,on_delete=models.DO_NOTHING) content = models.TextField() author = models.ForeignKey(User, on_delete=models.DO_NOTHING) created_time = models.DateTimeField(auto_now_add=True) last_updated_time = models.DateTimeField(auto_now=True)
def __str__(self): return "<Blog: %s>" % self.title
class Meta: ordering = ['-created_time']
|
使用Shell命令
命令提示符下输入:
管理博文
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
| >>>from blog.models import Blog >>>from blog.models import BlogType >>>from django.contrib.auth.models import User
>>>Blog.objects.all() >>>BlogType.objects.all() >>>User.objects.all()
>>>blog = Blog() >>>blog.title = 'shell下第1篇' >>>blog.content = 'xxxxxxxxxxxxxxx' >>>blog_type = BlogType.objects.all()[0] >>>blog.blog_type = blog_type >>>user = User.objects.all()[0] >>>blog.author = user
>>>blog.save()
>>>for i in range(1,31): ... blog = Blog() ... blog.title = "for %s" % i ... blog.content = 'xxxx:%s' % i ... blog.blog_type = blog_type ... blog.author = user ... blog.save()
|
网页搭建
使用模版
应用目录下创建文件夹templates,然后创建html文件,编辑view.py,类似以下编辑:
1 2 3 4 5 6 7 8 9 10 11
| from django.shortcuts import render from article.models import Article
def article_detail(request, article_id): try: article = Article.objects.get(id=article_id) context = {} context['article_obj'] = article return render(request, "article_detail.html", context) except Article.DoesNotExist: raise Http404('不存在')
|
也可以使用render_to_response方法:
1 2 3
| from django.shortcuts import render_to_response ...... return render_to_response("article_detail.html", context)
|
还有get_object_or_404方法:
1 2 3 4 5 6 7 8
| from django.shortcuts import render_to_response,get_object_or_404 from article.models import Article
def article_detail(request, article_id): article = get_object_or_404(Article, pk=article_id) context = {} context['article_obj'] = article return render_to_response("article_detail.html", context)
|
html文件类似:
1 2 3 4 5 6 7 8 9
| <html> <head> <body> <h2>{{ article_obj.title }}</h2> <hr> <p>{{ article_obj.content }}</p> </body> </head> </html>
|
创建目录
创建目录html页面,在urls里绑定,使用循环来遍历文章id,使用pk而不是id是更保险的写法。
1 2 3 4 5 6 7 8 9
| <html> <head> <body> {% for article in articles %} <a href="/article/{{ article.pk }}">{{ article.title }}</a> {% endfor %} </body> </head> </html>
|
超链接部分也可以用这种写法:
1
| <a href="{% url 'article_detail' article.pk %}">{{ article.title }}</a>
|
url合并
如果有很多应用,按之前的写法,url会太臃肿,因此可以在应用下新建urls.py:
1 2 3 4 5 6 7
| from django.urls import path from . import views
urlpatterns = [ path('<int:article_id>', views.article_detail, name='article_detail'), path('', views.article_list, name='article_list'), ]
|
相应的,项目下url可改为:
1 2 3 4 5 6 7 8 9
| from django.contrib import admin from django.urls import include,path from . import views
urlpatterns = [ path('admin/', admin.site.urls), path('',views.index), path('article/',include('article.urls')), ]
|
使用html模版
为了减少重复html代码的使用,可以使用block块来标记可替代内容,首先在项目根目录下创建templates文件夹,创建base.html并写入以下内容:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| <!DOCTYPE html> <html lang="zh-cn"> <head> <meta charset="UTF-8"> <title>{% block title %}{% endblock %}</title> </head> <body> <div> <a href="{% url 'home' %}"><h3>个人博客网站</h3></a> </div> <hr> {% block content %}{% endblock %} </body> </html>
|
与之相应地,可以在其他的html文件中,省略这些内容,只需要用extends引用,再到block块中填充即可,例如blog_list.html:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
|
{% extends 'base.html' %}
{# 页面标题 #} {% block title %} 我的网站 {% endblock %}
{# 页面内容 #} {% block content %} {% for blog in blogs %} <a href="{% url 'blog_detail' blog.pk%}"> <h3>{{ blog.title }}</h3> </a> <p>{{ blog.content|truncatechars:30 }}</p> {% empty %} <p>-- 暂无博客,敬请期待 --</p> {% endfor %} <p>一共有{{ blogs|length}}篇文章</p> {% endblock %}
|
然后在项目文件夹中的setting.py中编辑TEMPLATES的DIRS列表,加入os.path.join(BASE_DIR, 'templates')
。
使用css
在项目目录下新建static文件夹,写入base.css文件:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| * { margin: 0; padding: 0; } div.nav { background-color: #eee; border-bottom: 1px solid #ccc; padding: 10px 5px } div.nav a{ text-decoration: none; color:black; padding: 5px 10px; } div.nav a.logo { display: inline-block; font-size: 120%; }
|
然后在项目文件夹中的setting.py中加入:
1 2 3
| STATICFILES_DIRS = [ os.path.join(BASE_DIR, 'static'), ]
|
引用方法:
1 2 3 4 5 6 7
| <link rel="stylesheet" href="/static/base.css">
{% load staticfiles %}
<link rel="stylesheet" href="{% static 'base.css'%}">
|
使用css框架Bootstrap
基础
访问官网,下载新版Bootstrap,保留以下文件,放在项目static的新建的Bootstrap文件夹中:
1 2 3 4 5 6 7
| css bootstrap.min.css bootstrap.min.css.map font all js bootstrap.min.js
|
参考文档,如果需要导入,可按如下代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| {% load staticfiles %} <!DOCTYPE html> <html lang="zh-cn"> <head> <meta charset="utf-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1"> <title>{% block title %}{% endblock %}</title> <link rel="stylesheet" href="{% static 'base.css' %}"> <link rel="stylesheet" href="{% static 'bootstrap-3.3.7/css/bootstrap.min.css' %}"> <script type="text/javascript" src="{% static 'jquery-1.12.4.min.js' %}"></script> <script type="text/javascript" src="{% static 'bootstrap-3.3.7/js/bootstrap.min.js' %}"></script> {% block header_extends %} {% endblock %} </head> <body> </body> </html>
|
栅格系统
类前缀从超小到大分别为.col-xs-、.col-sm-、.col-md-、.col-lg-,也可以使用类如.visible-xs-block、.hidden-xs来显示或者隐藏,使用 例如.col-md-offset- 1类可以将列向右侧偏移。
1 2 3 4
| <div class="row"> <div class="col-md-8">.col-md-8</div> <div class="col-md-4">.col-md-4</div> </div>
|
分页
基础
shell中可以大致了解分页器的功能:
1 2 3 4 5 6 7 8 9 10 11
| >>>from django.core.paginator import Paginator >>>from blog.models import Blog >>>blogs = Blog.objects.all() >>>paginator = Paginator(blogs, 10)
>>>paginator.count >>>paginator.num_pages >>>paginator.page_range
>>>page1 = paginator.page(1) >>>page1.object_list
|
修改views.py
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55
| def blog_list(request): blogs_all_list = Blog.objects.all() paginator = Paginator(blogs_all_list, settings.EACH_PAGE_BLOGS_NUMBER) page_num = request.GET.get("page", 1) page_of_blogs = paginator.get_page(page_num) current_page_num = page_of_blogs.number page_range = [x for x in range(current_page_num-2, current_page_num+3) if (x>0 and x<paginator.num_pages + 1)] if page_range[0] - 1 >= 2: page_range.insert(0,'...') if paginator.num_pages - page_range[-1] >= 2: page_range.append('...') if page_range[0] != 1: page_range.insert(0,1) if page_range[-1] != paginator.num_pages: page_range.append(paginator.num_pages) context = {} context['blogs'] = page_of_blogs.object_list context['page_of_blogs'] = page_of_blogs context['page_range'] = page_range context['blog_types'] = BlogType.objects.all() return render_to_response('blog/blog_list.html',context)
def blogs_with_type(request, blog_type_pk): blog_type = get_object_or_404(BlogType, pk=blog_type_pk) blogs_all_list = Blog.objects.filter(blog_type=blog_type) paginator = Paginator(blogs_all_list, settings.EACH_PAGE_BLOGS_NUMBER) page_num = request.GET.get("page", 1) page_of_blogs = paginator.get_page(page_num) current_page_num = page_of_blogs.number page_range = [x for x in range(current_page_num-2, current_page_num+3) if (x>0 and x<paginator.num_pages + 1)] if page_range[0] - 1 >= 2: page_range.insert(0,'...') if paginator.num_pages - page_range[-1] >= 2: page_range.append('...') if page_range[0] != 1: page_range.insert(0,1) if page_range[-1] != paginator.num_pages: page_range.append(paginator.num_pages) context = {} context['blog_type'] = blog_type context['blogs'] = page_of_blogs.object_list context['page_of_blogs'] = page_of_blogs context['page_range'] = page_range context['blog_types'] = BlogType.objects.all() return render_to_response('blog/blogs_with_type.html',context)
|
修改blog_list.html:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41
| <div class="paginator"> <ul class="pagination"> <li> {% if page_of_blogs.has_previous %} <a href="?page={{ page_of_blogs.previous_page_number }}" aria-label="Previous"> <span aria-hidden="true">«</span> </a> {% else %} <span aria-hidden="true">«</span> {% endif %} </li> {% for page_num in page_range %} {% if page_num == page_of_blogs.number %} <li class='active'><span>{{ page_num }}</span></li> {% else %} {% if page_num == '...' %} <li><span>{{ page_num }}</span></li> {% else %} <li><a href="?page={{ page_num }}">{{ page_num }}</a></li> {% endif %} {% endif %} {% endfor %} <li> {% if page_of_blogs.has_next %} <a href="?page={{ page_of_blogs.next_page_number }}" aria-label="Next"> <span aria-hidden="true">»</span> </a> {% else %} <span aria-hidden="true">»</span> {% endif %} </li> </ul> <p> 共有{{ page_of_blogs.paginator.count}}篇博客, 当前第{{ page_of_blogs.number }}页,共{{ page_of_blogs.paginator.num_pages }}页 </p> </div>
|
上一页/下一页
编辑views.py,其中__gt表示大于,同理lt为小于:
1 2 3 4 5 6 7
| def blog_detail(request,blog_pk): context = {} blog = get_object_or_404(Blog, pk=blog_pk) context['next_blog'] = Blog.objects.filter(created_time__gt=blog.created_time).last() context['previous_blog'] = Blog.objects.filter(created_time__lt=blog.created_time).first() context['blog'] = blog return render_to_response('blog/blog_detail.html',context)
|