Django框架基础与项目

一、Django基础

1. 配置静态文件

STATIC_URL = '/static/'   	    # 这个路径访问静态文件
STATICFILESDIRS=(os.path.join(BASEDIR,"static"),)    # 配置静态文件路径

2. APP使用

python3 manage.py startapp 应用名称(必须是标识符命令规则)
INSTALLED_APPS = [ ... ..., '自定义应用名称' ]      #配置app
# 应用的分布式路由:主路由配置:url(r’^music/’,includ(‘music.urls’))

3. 数据库的使用

模型继承于django.db.models.Model。

DATABASE配置mysql相关信息:‘NAME’、‘USER’、‘PASSWORD’、‘HOST’、‘PORT’。

数据类型:DecimalField,Bollean,char,datetime,float,email,integer,url,image保存图片路径,text。

基础操作
#### 查询
MyModel.objects.filter(属性1=1, 属性2=2).get(id=10)
#### 查询返回指定列(元组表示)
MyModel.objects.values_list(...)      # 指定字段查询
books = Book.objects.values_list("title", "pub")
#### 排序查询
MyModel.objects.order_by('-列','列')    # 反向正向排序
#### 实现批量修改
update(属性 =)   
#### 除了符合条件的,其他都需要
MyModel.objects.exclude(条件)
聚合查询
#### 不带分组聚合
result = Book.objects.aggregate(myAvg=Avg('price'))   # 返回结果为字典{"结果变量名": 值}
#### 带分组聚合
pubset = Book.objects.values('pub').annotate(mycount=Count(‘pub’))
查询谓词
__exact:等值匹配			__contains:包含指定值		__startswith:以...开始
__endswith:以...结束		__gt:大于指定值				__gte:大于等于			__lt:小于	
__lte:小于等于		__in:查找数据是否在指定范围内		__range:查找数据是否在指定的区间范围内
F对象

通常是对数据库中的字段值在不获取的情况下进行操作。模型内多字段比较。

from django.db.models import F
F('列名')  
models.Book.objects.all().update(market_price=F('market_price')+10)  # 例子
Q对象

Q对象通常会与另一个Q对象进行比较,使用逻辑或 | 、 逻辑非 ~ 来连接。

models.Book.objects.filter(Q(price__lt=20)|Q(pub="清华大学出版社"))
数据表关联关系映射

一对一关系:

class Author(models.Model):
    '''作家模型类'''
    name = models.CharField('作家', max_length=50)
class Wife(models.Model):
    '''作家妻子模型类'''
  name = models.CharField("妻子", max_length=50)
  author = models.OneToOneField(Author)
#### 创建
author1 = Author.objects.create(name='王老师')
wife1 = Wife.objects.create(name='王夫人', author=author1) 
#### 正向查询
wife = Wife.objects.get(name='王夫人')
#### 反向查询
author1 = Author.objects.get(name='王老师')
wife = author1.wife.name

一对多关系:

class Publisher(models.Model):
    '''出版社'''
    name = models.CharField('名称', max_length=50, unique=True)
class Book(models.Model):
    title = models.CharField('书名', max_length=50)
    publisher = ForeignKey(Publisher)
#### 数据查询
abook = Book.objects.get(id=1)
pub1 = Publisher.objects.get(name='清华大学出版社')
books = pub1.book_set.all()      # 通过book_set 获取pub1对应的多个Book数据对象

多对多映射:

class Author(models.Model):
    ...
class Book(models.Model):
    ...
    authors = models.ManyToManyField(Author)
#### 数据查询
author = book.authors.get() -> 获取book对应的所有的author的信息
author.book_set.all()
author.book_set.create(...)  # 创建新书并关联author
author.book_set.add(book)   # 添加已有的书给当前作者author
author.book_set.clear()  # 删除author所有并联的书

3. Admin后台

创建后台管理账号

创建管理员账号:python3 manage.py createsupperuser

后台管理的登录地址:http://127.0.0.1:8000/admin

$ python3 manage.py createsuperuser
Username (leave blank to use 'tarena'): tarena  # 此处输入用户名
Email address: laowei@tedu.cn  # 此处输入邮箱
Password: # 此处输入密码(密码要复杂些,否则会提示密码太简单)
Password (again): # 再次输入重复密码
Superuser created successfully.
$ 
修改后台Models展现形式

在自定义模型类中重写**__ str __ (self)**方法返回显示文字内容:

class Book(models.Model):
    def __str__(self):
        return "书名" + self.title
模型管理器类

先在<应用app>/admin.py 里定义模型管理器类,再注册管理器与模型类关联。

from django.contrib import admin
from . import models
class BookManager(admin.ModelAdmin):
    list_display = ['id', 'title', 'price', 'market_price']
admin.site.register(models.Book,BookManager) # 注册models.Book 模型类与管理器类BookManager关联

高级管理功能:

  1. list_display去控制哪些字段会显示在Admin 的修改列表页面中。
  2. list_display_links 可以控制 list_display中的字段是否应该链接到对象的“更改”页面。
  3. list_filter 设置激活Admin 修改列表页面右侧栏中的过滤器
  4. search_fields 设置启用Admin 更改列表页面上的搜索框。
  5. list_editable 设置为模型上的字段名称列表,这将允许在更改列表页面上进行编辑。
后台模型名显示
class Book(models.Model):
    title = CharField(....)
    class Meta:
        db_table = '数据表名'    # 该模型所用的数据表的名称。(设置完成后需要立马更新同步数据库)

4. Cookie和Session

cookies:存储在浏览器中。按域存储,彼此隔离,有生命周期。每次访问地址时,只要cookie中有数据,浏览器都会在请求头中都会携带上cookie内容。服务器中添加cookie告知浏览器,触发存储cookies。删除cookie实质是修改cookie有效时间。

HttpResponse.set_cookie(key, value='', max_age=None, expires=None)
# key:cookie的名字
# value:cookie的值
# max_age:cookie存活时间,秒为单位
# expires:具体过期时间
# 当不指定max_age和expires 时,关闭浏览器时此数据失效
HttpResponse.delete_cookie(key)
# 删除指定的key 的Cookie。如果key 不存在则什么也不发生。

session:存储在服务端数据库中,将生成的id加入cookie中发送给浏览器。记住密码,需要在session和cookie中分别加入username,请求时先验证session,再验证cookie。

Django中使用session:在settings.py中INSTALLED_APPS列表中添加应用,MIDDLEWARE列表中添加中间件

INSTALLED_APPS = [ 'django.contrib.sessions' ]    # 启用 sessions 应用
MIDDLEWARE=['django.contrib.sessions.middleware.SessionMiddleware']   # 启用Session中间件
request.session[‘uname’]=uname
VALUE = request.session['KEY']
del request.session['KEY']

5. HttpRequest对象

request.path_info      # 获取URL字符串;
request.scheme         # 获取请求协议('http'/'https')
request.getfullpath()     # 获取请求的完整路径
request.get_host()        # 获取请求的主机
request.META           # 获取请求中的元数据(消息头)
request.META['REMOTE_ADDR']      # 获取客户端IP地址
Request.body      # 获取请求体的内容(POST或PUT),字符串。

6. HttpResponse对象

'text/html'(默认的,html文件)
'text/plain'(纯文本)
'text/css'(css文件)
'text/javascript'(js文件)
'multipart/form-data'(文件提交)
'application/json'(json传输)
'application/xml'(xml文件)
HttpResponse(content = 响应体, content_type = 响应体数据类型, status = 状态码)

7. 缓存

数据库缓存

Django可以将其缓存的数据存储在您的数据库中,需要在settings.py中进行配置。

CACHES = {
    'default': {
        'BACKEND': 'django.core.cache.backends.db.DatabaseCache',
        'LOCATION': 'my_cache_table',
        'TIMEOUT': 300,  #缓存保存时间 单位秒,默认值为300, 
        'OPTIONS':{
            'MAX_ENTRIES': 300, #缓存最大数据条数
            'CULL_FREQUENCY': 2,#缓存条数达到最大值时删除1/2的缓存数据
        }
    }
}

创建缓存表

python manage.py createcachetable
本地内存缓存
CACHES = {
    'default': {
        'BACKEND': 'django.core.cache.backends.locmem.LocMemCache',
        'LOCATION': 'unique-snowflake'
    }
}
使用缓存存储中间值
from django.core.cache import cache
cache.set('my_key', 'myvalue', 30) #30秒
cache.get('my_key','default值')
cache.get_or_set('my_key', 'value', 10)
cache.set_many({'a': 1, 'b': 2, 'c': 3})
cache.get_many(['a', 'b', 'c'])
cache.delete('my_key')
在视图View中使用缓存
from django.views.decorators.cache import cache_page
@cache_page(30)  # ---》 单位s
def my_view(request):
    ...
在路由中使用
from django.views.decorators.cache import cache_page
urlpatterns = [ path('foo/', cache_page(60)(my_view)) ]
自定义缓存方法

通过三次装饰器函数来实现自定义缓存存储。Django.cache会触发浏览器缓存。

像商品细节这种变化多的通过装饰器 @cachecheck(keyprefix=‘gd’, keyparam=‘sku_id’, cache=‘goods_detail’, ex=300)来处理数据缓存。

def cachecheck(**cachekwargs):
    def outter(func):
        def inner(self, request, *args, **kwargs):
            CACHE = caches['default']
            if 'cache' in cachekwargs:
                CACHE = caches[cachekwargs.get('cache')]
            ex = cachekwargs.get('ex', 60)
            keyprefix = cachekwargs.get('keyprefix')
            keyparam = cachekwargs.get('keyparam')
            if keyparam not in kwargs:
                raise
            cachekey = keyprefix + kwargs.get(keyparam)
            res = CACHE.get(cachekey)
            if res:
                return res
            res = func(self, request, *args, **kwargs)
            CACHE.set(cachekey, res, ex)
            return res
        return inner
return outter

8. 中间件

注册中间件:

# file : settings.py
MIDDLEWARE = [
    ...
       ]

使用中间件:

django.utils.deprecation.MiddlewareMixin
# 执行路由之前被调用,在每个请求上调用,返回None或HttpResponse对象 
def process_request(self, request): 
# 调用视图之前被调用,在每个请求上调用,返回None或HttpResponse对象
def process_view(self, request, callback, callback_args, 
                 callback_kwargs): 
# 所有响应返回浏览器  被调用,在每个请求上调用,返回HttpResponse对象
def process_response(self,request, response):
# 当处理过程中抛出异常时调用,返回一个HttpResponse对象
def process_exception(self, request, exception): 
# 在视图刚好执行完毕之后被调用,在每个请求上调用,返回实现了render方法的响应对象
def process_template_response(self, request, response):

9. 分页

视图函数:

from django.core.paginator import Paginator
def book(request):
    bks = Book.objects.all()
    paginator = Paginator(bks, 10)
    cur_page = request.GET.get('page', 1)  # 得到默认的当前页
    page = paginator.page(cur_page)
    return render(request, 'bookstore/book.html', locals())

模板设计:

<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 %}
</body>

10. 文件上传与下载

文件上传必须为POST提交方式。

<form method="post" action="/upload" enctype="multipart/form-data">
   <input type="file" name="myfile"/><br>
   <input type="submit" value="上传">
</form>

Setting中设置:

MEDIA_ROOT = os.path.join(BASE_DIR, 'static/files')

Views中:

a_file = request.FILES['myfile']
filename =os.path.join(
settings.MEDIA_ROOT
, a_file.name)
   with open(filename, 'wb') as f:
         data = a_file.file.read()
         f.write(data)

文件下载通过改变response头的方式。

response = HttpResponse(content_type ='text/csv')
    response['Content-Disposition'] = 'attachment; filename="mybook.csv"'
    all_book = Book.objects.all()
    writer = csv.writer(response)
    writer.writerow(['id', 'title'])
    for b in all_book:    
        writer.writerow([b.id, b.title])
    return response

二、项目

1. Token令牌

为了解决前后端分离后,http无状态,同时web、安卓、苹果能公用一套后台。Cookie是web技术。

base64加密
  1. 将字符串拆成每三个字符一组。

  2. 计算每一个字符对应的ASCII码二进制。

  3. 将8位的二进制码,按照每6位一组重新分组,不足6位的在后面补0。

  4. 计算对应的十进制编码。

  5. 不足四组的,用“=”表示。

生成Token令牌

base64加密:

import base64
s = b'jasonchu'
b_s = base64.b64encode(s) #base64加密
ss = base64.b64decode(b_s) #base64解密

sha256安全散列算法:

import hashlib
s = hashlib.sha256() #创建sha256对象
s.update(b'xxxx')  #添加欲hash的内容,类型为 bytes
s.digest()  #获取最终结果

HMAC-SHA256结合散列与秘钥:

import hmac
#生成hmac对象
#第一个参数为加密的key,bytes类型,
#第二个参数为欲加密的串,bytes类型
#第三个参数为hmac的算法,指定为SHA256
h = hmac.new(key, str, digestmod='SHA256 ') 
h.digest() #获取最终结果

Jwt-token的生成:

import hmac
headers={‘alg’:’HS256’,   # 算法
         ’typ’:’JWT’}     # 类型
payload={   #公有声明
'exp':xxx,  #过期时间的时间戳 
'iss':xxx, #token的签发者 
'aud':xxx,  # token签发面向群体
'iat':xxx  }  # 创建的时间戳 
signature=hmac.new(key,base64后的header+'.'+ base64后的payload) #最后返回三部分拼接出来的字节串。

2. Cors跨域

简单请求:

1.请求方法如下:
GET or HEAD or POST
2.请求头仅包含如下:
		Accept
		Accept-Language
		Content-Language
		Content-Type
3.Content-Type 仅支持如下三种:
		application/x-www-form-urlencoded
		multipart/form-data
		text/plain
步骤:
1.请求:请求头中携带Origin,该字段表明自己来自哪个域。
2.响应:如果请求头中的Origin在服务器接受范围内,则返回如下头:
			Access-Control-Allow-Origin|服务器接受得域

预检请求:

请求头:必须有!!!
    Origin | 表明此请求来自哪个域
    Access-Control-Request-Method|此次请求使用方法
    Access-Control-Request-Headers | 此次请求使用的头
响应头:
    Access-Control-Allow-Origin |同简单请求
    Access-Control-Allow-Methods |告诉浏览器,服务器接受得跨域请求方法
    Access-Control-Allow-Headers | 返回所有支持的头部
    Access-Control-Allow-Credentials |同简单请求 
    Access-Control-Max-Age | OPTION请求缓存时间,单位s 过期时间设定!!!
主请求阶段:
    Origin | 表明此请求来自哪个域
主请求响应阶段:
	Access-Control-Allow-Origin | 当前服务器接受得域。
每次都需要先预检请求,再进行主请求!!!
所以一般设置请求缓存时间为一天。

Django中应用cors:

1. INSTALLED_APPS 中添加 corsheaders 
2. MIDDLEWARE 中添加 corsheaders.middleware.CorsMiddleware,官方建议
   ‘django.middleware.common.CommonMiddleware’ 上方 
3. CORS_ORIGIN_ALLOW_ALL 布尔值 如果为True 白名单不启用 
4. CORS_ORIGIN_WHITELIST =[ "https://example.com" ] 
5. CORS_ALLOW_METHODS = ( 'DELETE', 'GET', 'OPTIONS', 'PATCH', 'POST', 'PUT', ) 
6. CORS_ALLOW_HEADERS = ( 'accept-encoding', 'authorization', 'content-type', 'dnt',
                         'origin', 'user-agent', 'x-csrftoken', 'x-requested-with', )
7. CORS_PREFLIGHT_MAX_AGE 默认 86400s 
8. CORS_EXPOSE_HEADERS [] 
   CORS_ALLOW_CREDENTIALS 布尔值, 默认False

3. Django+redis的使用

# 在settings中配置:导入from django_redis import get_redis_connect
CACHES = {
    "default": {
            "BACKEND": "django_redis.cache.RedisCache",
            "LOCATION": "redis://127.0.0.1:6379",
            "OPTIONS": {
                "CLIENT_CLASS": "django_redis.client.DefaultClient",
            }
        }
}

4. Celery使用

Task就是需要执行的任务,broker消息中间件(RQ,redis),backend用于储存结果,worker消费执行任务。

5. 第三方授权登录

先向授权页面发送请求,再通过后,三方发送过来code,接受到code再组合成固定url,去三方服务器请求数据。

微博授权

配置项:

WEIBO_CLIENT_ID = '415587****'
WEIBO_CLIENT_SECRET = 'cd8f41ba1cb718572386912dd57*****'
# 获取code成功后,跳转的地址
WEIBO_REDIRECT_URI = 'http://127.0.0.1:7000/dadashop/templates/callback.html' 

请求授权code:

params = {'response_type': 'code',
        'client_id': settings.WEIBO_CLIENT_ID,
        'redirect_uri': settings.WEIBO_REDIRECT_URI }
weibo_url = 'https://api.weibo.com/oauth2/authorize?'
url = weibo_url + urlencode(params)

请求数据:

req = {'client_id': settings.WEIBO_CLIENT_ID,
        'client_secret': settings.WEIBO_CLIENT_SECRET,
        'grant_type': 'authorization_code',
        'redirect_uri': settings.WEIBO_REDIRECT_URI,
        'code': code }
response = requests.post('https://api.weibo.com/oauth2/access_token', data=req)

6. 邮件发送

配置:

EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend' # 固定写法
EMAIL_HOST = 'smtp.qq.com' # 腾讯QQ邮箱 SMTP 服务器地址
EMAIL_PORT = 25  # SMTP服务的端口号
EMAIL_HOST_USER = 'xxxx@qq.com'  # 发送邮件的QQ邮箱
EMAIL_HOST_PASSWORD = '******'  # “POP3/IMAP的授权码

View中实现:

from django.core import mail
mail.send_mail( subject,  #题目
                message,  # 消息内容
                from_email,  # 发送者[当前配置邮箱]
                recipient_list=['xxx@qq.com'] )  # 接收者邮件列表

7. 上传图片

# 在debug=True的时候,当请求到达后(127.0.0.1:8000/media/a.jpg),django去media_root配置下找相应的资源文件。
urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)

三、项目上线

1. 项目部署

配置uWSGI:

[uwsgi]
# 套接字方式的 IP地址:端口号
# socket=127.0.0.1:8000
# Http通信方式的 IP地址:端口号
http=127.0.0.1:8000
# 项目当前工作目录
chdir=/home/tarena/.../my_project 这里需要换为项目文件夹的绝对路径
# 项目中wsgi.py文件的目录,相对于当前工作目录
wsgi-file=my_project/wsgi.py
# 进程个数
process=4
# 每个进程的线程个数
threads=2
# 服务的pid记录文件
pidfile=uwsgi.pid
# 服务的目志文件位置
daemonize=uwsgi.log
# 开启主进程管理模式
master=true

settings.py中:

将 DEBUG=True 改为DEBUG=False
将 ALLOWED_HOSTS = [] 改为 ALLOWED_HOSTS = ['网站域名'] 或者 ['服务监听的ip地址']

终端启动、停止、查看

Sudo/uwsgi --ini uwsgi.ini 启动uwsgi
Sudo/uwsgi --stop uwsgi.pip 停止
Ps -aux|grep ‘uwsgi’查看进程情况

2. nginx 配置

每次更改后重启sudo /etc/init.d/nginx start|stop|restart|status

  1. nginx 配置 :
# 修改nginx的配置文件 /etc/nginx/sites-enabled/default
# 在server节点下添加新的location项,指向uwsgi的ip与端口。
server {
    location / {
        uwsgi_pass 127.0.0.1:8000;  # 重定向到127.0.0.1的8000端口
        include /etc/nginx/uwsgi_params; # 将所有的参数转到uwsgi下
    }
}
  1. 修改uWSGI配置,重启uwsgi服务:
[uwsgi]
# http=127.0.0.1:8000
# 改为
socket=127.0.0.1:8000
  1. nginx配置静态文件路径:

(1)创建新路径-主要存放Django所有静态文件如: /home/tarena/项目名_static/

(2)在Django settings.py中添加新配置:

#注意 此配置路径为 存放所有正式环境中需要的静态文件
STATIC_ROOT = '/home/tarena/项目名_static/static

(3)Django项目中执行执行python3 manage.py collectstatic,将项目重所有静态文件复制到 STATIC_ROOT中。

(4)Nginx配置中添加新配置:

# 新添加location/static 路由配置,重定向到指定的第一步创建的路径即可
server {
    location  /static  {
        # root 第一步创建文件夹的绝对路径,如:
         root  /home/tarena/项目名_static;          
    }   
}

3. 邮件告警

当正式服务器上代码运行有报错时,可将错误追溯信息发至指定的邮箱。

配置如下settings.py中:

#在基础邮件配置之后 添加如下
#关闭调试模式
DEBUG = False  
#错误报告接收方
ADMINS = [('jasonchu', 'xxxx@example.com'), ('jasonchu', 'xxxx@example.com')]
#发送错误报告方,默认为 root@localhost账户,多数邮件服务器会拒绝
SERVER_EMAIL = 'email配置中的邮箱'

过滤账号、密码等敏感信息:

1.视图函数中的局部变量

from django.views.decorators.debug import sensitive_variables

@sensitive_variables('user', 'pw', 'cc')
def process_info(user):
    pw = user.pass_word
    cc = user.credit_card_number
    name = user.name
#注意:
#1 若报错邮件中牵扯到user,pw,cc等局部变量的值,则会将其替换成  *****, 而name变量还显示其真实值
#2 多个装饰器时,需要将其放在最顶部
#3 若不传参数,则过滤所有局部变量的值

2.POST提交中的数据

from django.views.decorators.debug import sensitive_post_parameters

@sensitive_post_parameters('password', 'username')
def index(request):
    s = request.POST['username'] + request.POST['abcd']
# 'abcd' 并不存在,此时引发error
# POST中 username 及 password的值会被替换成  ******
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值