Django
创建项目
-
使用虚拟环境
-
pycharm生成django项目
-
安装django
pip install django==1.11.8 # 在虚拟环境中使用
-
pycharm中选择这个刚创建的的虚拟环境
-
-
运行
python manage.py runserver 主机ip:端口
4.创建应用
django-admin startapp name
Setting.py
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) # 动态计算出项目运行路径
DEBUG = True # 是否打开调试模式
ALLOWED_HOSTS = ["*"] # 允许访问的主机IP列表 "*" 允所有, 如果不写只允许本本。
INSTALLED_APPS = [] # 安装应用
MIDDLEWARE = [] # 中间件
ROOT_URLCONF = 'xxx.urls' # url入口
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates', # 模板引擎,还可用jinja2
'DIRS': [], # 模板搜索目录,不写默认使用templates目录
'APP_DIRS': True, # True时,在主的templates找不到时,会到自己应用的templates目录下找
'OPTIONS': {
'context_processors': [
'django.template.context_processors.debug',
'django.template.context_processors.request',
'django.contrib.auth.context_processors.auth',
'django.contrib.messages.context_processors.messages',
],
},
},
]
WSGI_APPLICATION = 'xxxx.wsgi.application' # 安装部署时会用到
# 数据库设置
DATABASES = {
# 默认设置,可以使用多个数据库
'default': {
'ENGINE': 'django.db.backends.mysql', # 数据库引擎,多数况下使用mysql
'NAME': '数据库',
'USER': '登录用户',
'PASSWORD': '登录密码',
'HOST': '数据库所在主机ip',
}
}
AUTH_PASSWORD_VALIDATORS = [] # 权限验证
LANGUAGE_CODE = 'zh-Hans' # 语言编码 'zh-Hans'->中文
TIME_ZONE = 'Asia/Shanghai' # 选择时区 'Asia/Shanghai' -> 北京时间
...
STATIC_URL = '/static/'
STATICFILES_DIRS = [os.path.join(BASE_DIR, 'static')]
urls.py
from django.conf.urls import url, include
from django.contrib import admin
urlpatterns = [
url(r'^admin/', admin.site.urls),
url(r'^', include("应用名.urls")), # 创建分布式路由
]
用法
# 带分组的路由(正则表达式)
url(r'^birthday/(\d{4})/(\d{2}/(\d{2})', views.birthday_view)
# 与之对应的处理函数
def birthday_view(request, year, month, day): # 传过来的参数是字符串
pass
# 命名分组的路由(正则表达式)
url(r'^birthday/(?P<y>\d{4})/(?P<m>\d{2}/(?P<d>\d{2})', views.birthday_view)
# 与之对应的处理函数
def birthday_view(request, y, m, d): # 按命名参数传递
pass
# 给url取别名
url(r'^birthday/(\d{4})/(\d{2}/(\d{2})', views.birthday_view, name='birthday')
# 取了别名之后就可以通过别名反向引得到对应的url
# 1. 在转发时使用
def redirect_to_year(request):
# ...
year = 2006
# ...
return HttpResponseRedirect(reverse('news-year-archive', args=(year,)))
# 2. 在模板中使用
<form action={% url 'birthday' %}, method='get'> # 可以在任何需要url的地方使用它
...
</form>
views.py
view用于处理请求业务
def view_func(request, ...):
return 响应对象
# 生成响应对象方法
# 1. HttpResponst('字符串')
# 2. render(request, 'template', 字典对象)
# 3. JsonResponse(字典对象 , safe=False)
# Request属性方法
request.method -> ['GET','POST']
request.GET # 获取get参数
request.POST # 获取POST参数
GET和POST请求
-
GET
val = request.GET.get('key', defaultVal) # 和字典不同,一个key可以对应多个值 val_list = request.GET.getlist('key')
-
POST
val = request.POST.get('key', default) val_list = request.POST.getlist('key')
-
CSRF验证
post请求参数中必须包含csrf验证码,否则请求会被拒绝。(或者可以把csrf检验的中间件删掉)
-
Django模板
-
在view中给模板传入数据
var = 10 lis = ['hello', 'world'] dic = {'name':'张三丰', 'age': 88} render(request, 'xxx.html', locals())
-
使用变量
<!-- 普通变量 --> {{ var }} <!-- 列表变量 --> {{ lis.0 }} {{ lis.1 }} <!-- 字典变量 --> {{ dic.name }} {{ dic.age }}
-
标签
<!-- if/else --> <!-- condition可以使用 a == b , a != b , a < b , a <= b , a > b, a >= b , x in y --> {% if condition1 and/or not condition2 %} ... display 1 {% elif condition2 %} ... display 2 {% else %} ... display 3 {% endif %} <!-- for --> {% for athlete in athlete_list %} <li>{{ athlete.name }}</li> {% endfor %} <!-- for 反向 --> {% for athlete in athlete_list reversed %} ... {% endfor %} <!-- for...empty --> {% for athlete in athlete_list %} <li>{{ athlete.name }}</li> {% empty %} <li>Sorry, no athletes in this list.</li> {% endfor %} <!-- for循环变量 --> forloop.counter <!-- 从1开始的计数 --> forloop.counter0 <!-- 从0开始的计数 --> forloop.revcounter <!-- 从1开始的反向计数 --> forloop.revcounter0 <!-- 从0开始的反向计数 --> forloop.first <!-- 首次--True --> forloop.last <!-- 最后一次--True --> forloop.parentloop <!-- 外层循环计数 --> <!-- include --> {% include "foo/bar.html" %} <!-- now --> It is {% now "jS F Y H:i" %} <!-- url --> ('^clients/', include('project_name.app_name.urls')) ('^client/([0-9]+)/$', app_views.client, name='app-views-client') {% url 'app-views-client' client.id %} <!-- /clients/client/123/ --> <!-- static --> {% load static %} <img src="{% static "images/hi.jpg" %}" alt="Hi!">
-
过滤器
<!-- 语法 --> {{ value|filter: par | filter1 : par| ... }}
静态文件
# 与静态文件相关的配置
STATIC_URL = '/static/'
STATICFILES_DIRS = [os.path.join(BASE_DIR, 'static')]
<!-- 模板中使用static加载静态资源 -->
{% load static %}
<img src="{% static "images/hi.jpg" %}" alt="Hi!">
ORM基础
-
数据库设置
# 数据库设置 DATABASES = { # 默认设置,可以使用多个数据库 'default': { 'ENGINE': 'django.db.backends.mysql', # 数据库引擎,多数况下使用mysql 'NAME': '数据库', 'USER': '登录用户', 'PASSWORD': '登录密码', 'HOST': '数据库所在主机ip', } }
安装pymysql
pip install pymysql
导入和伪装pymysql
# 应用名包中的 __init__.py import pymysql pymysql.install_as_MySQLdb()
最后一步是在mysql中创建对应的数据库(配置中 NAME指定的名称)
create database 数据库名 default char set utf8;
-
model类
from django.db import models class Person(models.Model): first_name = models.CharField(max_length=30) last_name = models.CharField(max_length=30)
上面的类将会在数据库中创建如下表格
CREATE TABLE myapp_person ( "id" serial NOT NULL PRIMARY KEY, "first_name" varchar(30) NOT NULL, "last_name" varchar(30) NOT NULL );
-
字段类型
Django使用 Filed类型的实例来确定以下事情
- 列类型,告诉数据库使用哪种类型在存储该列数据
- 用什么样的HTML小部件在form表单中渲染它.
- 数据校验,后台管理和自动生成表单
-
字段选项
-
null 字段是否为null, 默认为False
-
blank 字段是否可以为空白(为False时,html表单中的字段必须要填),默认为False
-
choices
from django.db import models class Student(models.Model): FRESHMAN = 'FR' SOPHOMORE = 'SO' JUNIOR = 'JR' SENIOR = 'SR' YEAR_IN_SCHOOL_CHOICES = ( (FRESHMAN, 'Freshman'), (SOPHOMORE, 'Sophomore'), (JUNIOR, 'Junior'), (SENIOR, 'Senior'), ) year_in_school = models.CharField( max_length=2, choices=YEAR_IN_SCHOOL_CHOICES, # 自动生成的表单控件用select表示 default=FRESHMAN, )
-
default 默认值,可以指定一个可调用的对象,在创建时会自动调用.
-
help_text 在表单部件中显示帮助信息
-
primary_key, 如果不指定,Django会自动添加一个int类型的主键
-
unique 唯一约束
-
verbose_name
-
创建索引
-
使用 db_index选项
title = models.CharField(max_length=200, db_index=True)
-
使用 Meta
class Article(models.Model): title = models.CharField(max_length=200,) class Meta: indexes = [ models.Index(fields=['title']), ]
-
-
-
-
数据库迁移
迁移是Django将您对模型做的修改同步到数据库的一种方式.
python manage.py makemigrations # 基于当前的改变,创建新的迁移 python manage.py migrate # 将迁移应用到数据库
-
ORM操作数据库
-
增加
# model.objects.create(字段名=值, ...) Book.objects.create(title='Python', price=20.0, pub='清华大学出版社') # obj.save() abook = Book() abook.title = 'python' abook.price = 20.5 abook.pub = '清华大学出版社' abook.save()
-
- 查询
- all -->返回所有对象
```python
all_entries = Entry.objects.all() # 获取表中的所的数据
-
filter(**kwargs) -->返回符合对象的列表
# 通过 kwargs 指定查询谓记事 Entry.objects.filter(id=0) # select * from table_name where id=0; # 链式调用 Entry.objects. filter(headline__startswith='What'). exclude(pub_date__gte=datetime.date.today()). filter(pub_date__gte=datetime.date(2005, 1, 30) ...
-
get(**kwargs) --> 返回一个对象
# 获取一个对象 # 会引发Entry.DoesNotExist-->没有找到任何记录 # MultipleObjectsReturned --> 返回了多于一条的记录 Entry.objects.get(id=0)
-
values / values_list(字段列表) --> 字典列表或 / 元组列表
-
切片操作实现mysql中的limit 和 offset 语句
# 前5个对象 Entry.objects.all()[:5] # offset 5 limit 5 Entry.objects.all()[5:10] # 指定步长 Entry.objects.all()[:10:2]
-
-
查询谓词
相当于sql中的where子句.
通过关键字传参的方式给查询结果集的方法(filter(), exclude(),get())指定参数
用 filed__lookuptype=value 的格式指定,如:
Entry.objects.filter(pub_date__lte='2006-01-01') # SELECT * FROM xxx WHERE pub_date <= '2006-01-01';
-
exact
Entry.objects.get(headline__exact="Cat bites dog") # 相当于 Entry.objects.get(headline="Cat bites dog")
-
iexact – 大小写敏感
Blog.objects.get(name__iexact="beatles blog")
-
contains / icontains
Entry.objects.get(headline__contains='Lennon') # SELECT ... WHERE headline LIKE '%Lennon%';
-
gt/lt/gte/lte
-
__in = []
-
__range=(a,b)
- 聚合查询
# Sum/Avg/Count/Max/Min from django.db.models import * Book.objects.aggregate(val=Sum('market_price')) # {'val': Decimal('485.00')} # 带分组的聚合查询 # QuerySet.annotate(结果=聚合函数('列')) # 先得到查询集合 qs = Book.objects.values('pub') qs.annotate(count=Count('pub')) # <QuerySet [{'pub': '清华大学出版社', 'count': 1}, {'pub': '机械工业出版社', 'count': 6}]> Book.objects.values('pub').annotate(arr=Avg('price')) # <QuerySet [{'pub': '清华大学出版社', 'arr': 70.0}, {'pub': '机械工业出版社', 'arr': 68.333333}]>
-
修改
通过查询方法找到对象后,修改属性并调用save即可
obj = Entry.objects.get(id=1) obj.title = 'new title' obj.save()
一次性修改多个对象
Entry.objects.filter(pub_date__year=2007).update(headline='Everything is the same')
-
删除
e.delete() # 或者 Entry.objects.filter(pub_date__year=2005).delete()
-
复制实例
blog = Blog(name='My blog', tagline='Blogging is easy') blog.save() # blog.pk == 1 blog.pk = None blog.save() # blog.pk == 2
-
F对象
from django.db.models import F Book.objects.all().update(market_price=F('market_price')-10) # 所有值在原基础上-10
-
Q对象 (可用 & | ~ 连接)
from django.db.models import Q # Q(C1) | Q(C2) , Q(C1) & Q(C2) , Q(C1) &~ Q(C2) Book.objects.filter(Q(market_price__gt=80)|Q(pub='清华大学出版社'))
-
-
原生数据库操作
#Entry.objects.raw('sql') books = Book.objects.raw('select * from bookstore_book;') # 只能执行 select for book in books: pass # cursor 类 from django.db import connection with connect.cursor() as cur: cur.execute('sql') with connection.cursor() as cur: cur.execute('delete from bookstore_book where title="Linux"')
后台管理
-
创建超级用户
python mange.py createsuperuser ...
现在可以通过 http://localhost:8000/admin/ 登录了
-
创建模型类型
class Book(models.Model): title = models.CharField(max_length=120, db_index=True, verbose_name='书名') pub = models.CharField(max_length=120, null=False, default='', verbose_name='出版社') price = models.DecimalField(max_digits=7, decimal_places=2, default=888, verbose_name='定价') market_price = models.DecimalField(max_digits=7, decimal_places=2, default=999, verbose_name='零售价')
-
注册模型
# 两种方式 # 使用用 register函数 admin.site.register(Book) # 使用装饰器 @admin.register(Book) class BookAdmin(admin.ModelAdmin): pass
-
外观定制
-
登录界面定制
# 修改 admin/login/ 的 Django 管理 # index.admin.py中 (可以在任何xxx.admin.py)添加 from django.contrib import admin admin.site.site_header = '站点管理' admin.site.site_title = '测试站点管理'
-
应用信息配置
# app.py # 创建一个类 class xxxAppConfig(AppConfig): name = 'app_name' verbose_name = "xxx" # __init__.py # default_app_config default_app_config = 'appname.apps.xxxAppConfig'
-
实体信息配置
class Book(models.Model): ... class Meta: verbose_name = verbose_name_plural = "xxx"
-
更换模板什么的,属性于高级主题,用到时再说吧
-
显示列表显示
@admin.register(Book) class BookAdmin(admin.ModelAdmin): list_display = ('title', 'market_price', 'price', 'pub')
-
显示列表加强版
# 获取你想在 price 和 market_price 前加上币种,其后加上单位 @admin.register(Book) class BookAdmin(admin.ModelAdmin): list_display = ('title', 'start_market_price_end', 'price', 'pub') def start_market_price_end(self, obj): return "$%s" % obj.market_price start_market_price_end.short_description = '零售价'
-
ORM高级(关系)
-
一对一
# 主表 ->( id = fk[唯一] ) <-从表 class A(model.Model): # 主表 pass class B(model,Model): # 从表 属性 = models.OneToOneField(A)
查询
# models.py class Author(models.Model): name = models.CharField(max_length=120, null=False, verbose_name='姓名') age = models.IntegerField(default=1, null=False, verbose_name='年龄') email = models.EmailField(null=True, verbose_name='邮箱') def __str__(self): return self.name class Meta: verbose_name = verbose_name_plural = '作者' class Wife(models.Model): name = models.CharField(max_length=120, null=False, verbose_name='姓名') age = models.IntegerField(verbose_name='年龄') author = models.OneToOneField(Author, verbose_name='老公') class Meta: verbose_name_plural = verbose_name = '妻子' # 从 -> 主 , 正向 wift = Wife.objects.get(id=1) wift.author # 主 -> 从,反向 author = Author.objects.get(id=1) author.wife # 使用查询谓词关联查询 Author.objects.get(wife__name='百何.白') # 查找老婆为 百何.白 的作者 # 生成的SQL类似于: # select Author.* from Wife inner join Author on Wife.autohr=Author where Wife.name='百何.白' ; Wife.objects.get(author__id=1) # 查找 老公 id 为 1 的 Wife # 生成的SQL类似于: # select Wife.* from Wife inner join Author on Wife.autohr=Author where Author.id=1;
添加
author = Author.objects.get(id=2) wife = Wife() ... wife.author = author wife.save()
-
一对多
# 主表 ->( id = fk ) <-从表(多) class A(model.Model): # 主表 pass class B(model,Model): # 从表 属性 = models.ForeignKey(A)
常用参数
# on_delete --> 主表记录被删除后,从表对应的记录该如何操作 # models.CASCADE # madels.PROTECT # models.SET_NULL # models.SET_DEFAULT
模型数据
class Publisher(models.Model): name = models.CharField(max_length=120, db_index=True, verbose_name='出版社') class Meta: verbose_name = verbose_name_plural = "出版社" class Book(models.Model): title = models.CharField(max_length=120, db_index=True, verbose_name='书名') price = models.DecimalField(max_digits=7, decimal_places=2, default=888, verbose_name='定价') market_price = models.DecimalField(max_digits=7, decimal_places=2, default=999, verbose_name='零售价') publisher = models.ForeignKey(Publisher, on_delete=models.SET_NULL, null=True) class Meta: verbose_name = verbose_name_plural = "图书"
添加记录
# 需要先添加/找到主表的记录 publisher = Publisher.objects.create(name='清华大学出版社') # 添加从表记录 book = Book.objects.create(title='红楼梦', price='45.6', market_price=89, publisher=publisher)
查询
# 从表 --> 主表 book = Book.objects.get(title='红楼梦') pring(book.publisher.name) # 主表 --> 从表 pub = Publisher.objects.get(name='清华大学出版社') for book in pub.book_set.all(): print(book.title) # 使用查询谓词 books = Book.objects.filter(publisher__name='清华大学出版社') # 由清华大学出版社出版的图书 pubs = Publisher.objects.filter(book__title='红楼梦') # 出版了红楼梦的出版社
-
多对多
# 表1->(id = fk1) [多]中间表[多] (fk2 = id) <-表2 class A(model.Model): # 主表 pass class B(model,Model): # 从表 属性 = models.ManyToManyField(A) # models.ManyToManyField 在 B 中添加效果也一样
模型数据
class Book(models.Model): title = models.CharField(max_length=120, db_index=True, verbose_name='书名') price = models.DecimalField(max_digits=7, decimal_places=2, default=888, verbose_name='定价') market_price = models.DecimalField(max_digits=7, decimal_places=2, default=999, verbose_name='零售价') publisher = models.ForeignKey(Publisher, on_delete=models.SET_NULL, null=True) class Meta: verbose_name = verbose_name_plural = "图书"
添加/删除数据
author = Author.objects.create(name='罗贯中') author.books.add(Book.objects.get(title='三国演义')) # 调用之后,立即列新数据库 # 反向 book.author_set.add(author) #删除 使用 remove
数据查询
# 正向 author.books # 反向 book.author_set # 查询谓谓词 Book.objects.filter(author__id=1) Author.objects.filter(books__id=1)
-
多表查询总结
# 使用谓词 # 从表中一般有主表的外键引用 从表.objects.filter(外键__主表字段__查询类型) # 主表引用从表 (全小字的从表名) 主表.objects.filter(从表名__查询类型) # ”__外键“ 可以连续使用,如查找 在清华大学出版社出版过书箱的作者 Author.objects.filter(books__publisher__name='清华大学出版社') # 引用 # 正向 从表.外键名 # 反向 主表.从表(小写)[_set] # 如果从表中有多条记录需要用_set结尾
Cookie和Session
-
Cookie
一种在浏览器客户端以键值对方式存储数据的方式,个请求都会携带与网站相关的cookie,如果携带的数据过大,也会影响请求速度。
- cookie设置
resp = HttpResponse('ok')
resp.set_cookie('var', 100)
return resp
# 设置过期时间 set_cookie(key,val,max_age=None, expires=None)
# max_age 最大存活时间 以 秒为单位
# expires 具体过期时间
# 两个都是None 浏览器关闭时过期
-
删除 cookie
resp.delete_cookie('var')
-
获取 cookie
# 从浏览器获取数据的方式只能通过 request val = request.COOKIES.get(key)
-
session
request.session[key] = val # 像字典一样使用、 # setting.py SESSION_COOKIE_AGE = 60 * 60 * 24 * 7 # s SESSION_EXPIRE_AT_BROWSER_CLOSE = True # 使用session前需要先进行数据库迁移
中间件
-
请求 ----中间-------响应
类class mymiddle(MiddleWareMixin): # 浏览器 --> |process_request| --> urls.py def process_request(self, request): return None # 什么也不做 # url -->|process_view|--> views def process_view(self, request, callback, callback_args, callback_kwargs): return None # 什么也不做 # 响应 --> |process_response| --> 浏览器 def process_response(self, request, response) return response # 必须要返回 # 发生异常 def process_exception(self, request, respoinse): # 调用模板前 def process_template_response(self, request, response):
-
安装中间件
MIDDLEWARE = [ ... 'middleware.mymiddleware.MyMW' ]
Form模块
-
Django的Form模块可以做以下事情
- 自动生成 html 模板
- 验证表单有效性
说实话django自动生成的表单实不怎么好看,不过还好它支持手动渲染
-
定义Form
# forms.py from django import forms class MyForm(forms.Form): my_name = forms.CharField(label='姓名', max_length=100) my_age = forms.IntegerField(min_value=0, max_valu=150)
-
模板渲染 —自动
# views.py def reg2_view(request): myform = MyForm() return render(request, 'user/reg2.html', locals())
<!DOCTYPE html> <html> <head> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <!-- 引入 Bootstrap --> <link href="/static/bootstrap/css/bootstrap.min.css" rel="stylesheet"> </head> <body> <div class="container"> <form action=""> {% csrf_token %} {{ myform.as_p }} </form> </div> <script src="/static/bootstrap/js/jquery-1.11.3.js"></script> <script src="/static/bootstrap/js/bootstrap.min.js"></script> </body> </html>
除 as_p外还支持 as_ul , as_table
自动渲染不灵活,不建使用
-
Form表单验证功能
如果在view中进行表单校验显得代码结构非常混乱,表单数据也有很多相似的地方(如 登录 与 注册),如果把它们封装到类当中,就可以在很多地方进行复用。
# forms.py from django import forms class MyForm(forms.Form): my_name = forms.CharField(label='姓名', max_length=100 ) def clean_my_name(self): name = self.cleaned_data['my_name'] #raise forms.ValidationError('发生错误了') # 如果没有错误需要返回数值 return name # 这是对整个表单的验证 def clean(self): # pwd1 = self.cleaned_data['password'] # pwd2 = self.cleaned_data['password2'] # if pwd1 != pwd2: self.last_error = '两次密码不一样!' # 记录错误信息 raise forms.ValidationError(self.last_error) return self.cleaned_data # 必须返回cleaned_data
# views.py def reg2_view(request): if request.method == 'GET': myform = MyForm() return render(request, 'user/reg2.html', locals()) elif request.method == 'POST': myform = MyForm(request.POST) if myform.is_valid(): return HttpResponse('表单验证成功') else: print(myform.errors.values()) return render(request, 'user/reg2.html', locals())
渲染模板时,只要nane属性与form的字段属性一样,就可以正常使用Form的验证功能。
而且对于每个字段的验证在发季错误时可以用一个独有的字段记录其错误信息,并在模板渲染时显示出来。
-
手动渲染
<!DOCTYPE html> <html> <head> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <!-- 引入 Bootstrap --> <link href="/static/bootstrap/css/bootstrap.min.css" rel="stylesheet"> </head> <body> <div class="container"> <form class="form-horizontal" action="/user/reg2/" method="post"> {% csrf_token %} <div class="form-group"> <label for="id_name" class="control-label col-sm-2"> 姓名: </label> <div class="col-sm-6"> <input class="form-control" name="my_name" type="text"> </div> </div> <div class="col-sm-offset-2"> <input type="submit" class="btn btn-success"> {{ myform.last_error}} </div> </form> </div> <script src="/static/bootstrap/js/jquery-1.11.3.js"></script> <script src="/static/bootstrap/js/bootstrap.min.js"></script> </body> </html>
上传文件
-
模板文件
<!-- file: index/templates/index/upload.html --> <html> <head> <meta charset="utf-8"> <title>文件上传</title> </head> <body> <h3>上传文件</h3> <form method="post" action="/upload" enctype="multipart/form-data"> <input type="file" name="myfile"/><br> <input type="submit" value="上传"> </form> </body> </html>
-
settings.py
# file : settings.py ... MEDIA_ROOT = os.path.join(BASE_DIR, 'static/files')
-
views.py
# file views.py from django.http import HttpResponse, Http404 from django.conf import settings import os def upload_view(request): if request.method == 'GET': return render(request, 'index/upload.html') elif request.method == "POST": a_file = request.FILES['myfile'] print("上传文件名是:", a_file.name) filename =os.path.join(settings.MEDIA_ROOT, a_file.name) with open(filename, 'wb') as f: data = a_file.file.read() f.write(data) return HttpResponse("接收文件:" + a_file.name + "成功") raise Http404
404页面
- 在项目文件的根目录下添加template/404.html
- 如有需要在 views中错发 404异
分页功能
-
views.py
from django.core.paginator import Paginator def book(request): bks = models.Book.objects.all() paginator = Paginator(bks, 10) print('当前对象的总个数是:', paginator.count) print('当前对象的面码范围是:', paginator.page_range) print('总页数是:', paginator.num_pages) print('每页最大个数:', paginator.per_page) cur_page = request.GET.get('page', 1) # 得到默认的当前页 page = paginator.page(cur_page) return render(request, 'bookstore/book.html', locals())
-
template
<html> <head> <title>分页显示</title> </head> <body> {% for b in page %} <div>{{ b.title }}</div> {% endfor %} {# 分页功能 #} {# 上一页功能 #} {% if page.has_previous %} <a href="{% url 'book' %}?page={{ page.previous_page_number }}">上一页</a> {% else %} 上一页 {% endif %} {% for p in paginator.page_range %} {% if p == page.number %} {{ p }} {% else %} <a href="{% url 'book' %}?page={{ p }}">{{ p }}</a> {% endif %} {% endfor %} {#下一页功能#} {% if page.has_next %} <a href="{% url 'book' %}?page={{ page.next_page_number }}">下一页</a> {% else %} 下一页 {% endif %} 总页数: {{ page.len }} </body> </html>
安装部署(NGIX)
- 部署需要分以下步骤进行
- 在安装机器上安装和部署同版本的数据库
- django 项目迁移(在安装机器上安装与开发环境相同的python版本及依赖包)
- 用uwsgi代替 manage.py runserver 方法启动用服务器
- 用nginx配置静态文件路径,解决静态路径问题
-
安装 同版本的数据库
…
-
django项目迁移
-
安装python
sudo install pyton3
-
安装依赖包
-
导出开发环境中的依赖的包
pip freeze > package_list.txt
-
在安装机器上
pip3 install -r package_list.txt
-
将源码复制到运程机器
sudo scp -a /home/django/mysite3/ root@ip:/home/root/xxx # 要输入远程机密码
-
-
WSGI Dango工作环境部署 (ngix + uWSGI )
sudo pip3 install uwsgi # 在线安装 # 离线安装
-
添加配置文件 项目文件夹/uwsgi.ini
[uwsgi] # 套接字方式 的 ip:port # socket=127.0.0.1:8000 # http 通信方式 http=127.0.0.1:8000 # 项目工作目录, 绝路径 chdir=/xxx/xxx/projdct # 项目中wsgi.py文件的目录 ,相对于当前工作目录 wsgi-file=xxx/wsgi.py # 进程个数 process=4 # 每个进程和线程数 thread=2 # 服务的pid记录文件 pidfile=uwsgi.pid # 服务日志文件 daemonize=uwsgi.log
- 修改settings.py将DEBUG=True改为DEBUG=False
-
-
启动/停止 uwsgi
sudo uwsgi --ini mysite3/uwsgi.ini # 查看进程 (uwsgi) ps -aux | grep uwsgi # stop sudo uwsgi --stop uwsgi.pid # uwsgi.pid 在配置文件中指定
-
nginx反向代理,负载均衡
-
安装
sudo apt install nginx
-
配置
# sudo vim /etc/nginx/sites-available/default server { ... location / { uwsgi_pass 127.0.0.1:8000; # 重定向到 include /etc/nginx/uwsgi_params; } ... }
-
重启
sudo /etc/init.d/nginx start|stop|restart|status
-
修改 uwsgi配置
[uwsgi] # 套接字方式 的 ip:port socket=127.0.0.1:8000 # http 通信方式, # http=0.0.0.0:8000 # 项目工作目录, 绝路径 chdir=/root/site/mysite3 # 项目中wsgi.py文件的目录 ,相对于当前工作目录 wsgi-file=mysite3/wsgi.py # 进程个数,cpu的个数 process=4 # 每个进程和线程数 thread=2 # 服务的pid记录文件 pidfile=uwsgi.pid # 服务日志文件 daemonize=uwsgi.log log-maxsize=2048
-
静态文件配置
# sudo vim /etc/nginx/sites-available/default server { ... location / { uwsgi_pass 127.0.0.1:8000; # 重定向到 include /etc/nginx/uwsgi_params; } location /static { root /root/site/mysite3/static; } ... } # 重启 uwsgi, nginx # 如果出现 403 需要 用 root 运行 nginx vi /etc/nginx/nginx.conf # 把首行的用户改成 root ser root; # 如果还是有错,可以通过查看error.log文件查看错误原因,根据具体情况得出解决方案。 sudo vi /var/log/nginx/error.log
-
-
-
Nginx 配置文件
``` # /etc/nginx/nginx.conf events { worker_connections 768; # multi_accept on; } http { ## # Basic Settings ## sendfile on; tcp_nopush on; tcp_nodelay on; keepalive_timeout 65; types_hash_max_size 2048; # server_tokens off; # server_names_hash_bucket_size 64; # server_name_in_redirect off; include /etc/nginx/mime.types; default_type application/octet-stream; ## # SSL Settings ## ssl_protocols TLSv1 TLSv1.1 TLSv1.2; # Dropping SSLv3, ref: POODLE ssl_prefer_server_ciphers on; ## # Logging Settings ## access_log /var/log/nginx/access.log; error_log /var/log/nginx/error.log; ## # Gzip Settings ## gzip on; # gzip_vary on; # gzip_proxied any; # gzip_comp_level 6; # gzip_buffers 16 8k; # gzip_http_version 1.1; # gzip_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript; ## # Virtual Host Configs ## include /etc/nginx/conf.d/*.conf; include /etc/nginx/sites-enabled/*; # 网站的配置 } #mail { # # See sample authentication script at: # # http://wiki.nginx.org/ImapAuthenticateWithApachePhpScript # # # auth_http localhost/auth.php; # # pop3_capabilities "TOP" "USER"; # # imap_capabilities "IMAP4rev1" "UIDPLUS"; # # server { # listen localhost:110; # protocol pop3; # proxy on; # } # # server { # listen localhost:143; # protocol imap; # proxy on; # } #} # include /etc/nginx/sites-enabled/* nginx http 中可以有多个server 块, default 只是其中一个 可以到/etc/nginx/sites-enabled/ 添加一个类似default的配置文件以启用亲服务 ```