注意:一定要使用pycharm专业版
-------------------------------------------------------------------------
django简介:
M 代表模型(Model): 负责业务对象和数据库的关系映射(ORM)。
T 代表模板 (Template):负责如何把页面展示给用户(html)。
V 代表视图(View): 负责业务逻辑,并在适当时候调用Model和Template。
除了以上三层之外,还需要一个URL分发器,它的作用是将一个个URL的页面请求分发给不同的View处理,View再调用相应的Model和Template
-------------------------------------------------------------------------
如何下载:pip install django==2.0.13
-------------------------------------------------------------------------
查看版本:
方法一:python -m django --version
方法二:import django
django.VERSION
-------------------------------------------------------------------------
二:命令创建项目
django-admin.py startproject mysite #创建mysite项目
python manage.py startapp blog #创建项目功能
python manage.py runserver 8080 #启动项目
manage.py ----- Django项目里面的工具,通过它可以调用django shell和数据库等。
settings.py-----包含了项目的默认设置,包括数据库信息,调试标志以及其他一些工作 的变量。
urls.py ----- 负责把URL模式映射到应用程序。
-------------------------------------------------------------------------
路由分发:如果程序很多的话,记得做路由分发: 在项目下面的urls.py里面
from app1 import views
from django.urls import re_path,include
urlpatterns = [
re_path(r"",include("app1.urls")),
]
-------------------------------------------------------------------------
有名字分组:
urlpatterns = [
re_path(r'^articles/2003/$', views.special_case_2003),
re_path(r'^articles/(?P<year>[0-9]{4})/$', views.year_archive),
re_path(r'^articles/(?P<year>[0-9]{4})/(?P<month>[0-9]{2})/$', views.month_archive),
re_path(r'^articles/(?P<year>[0-9]{4})/(?P<month>[0-9]{2})/(?P<day>[0-9]{2})/$', views.article_detail),
]
-------------------------------------------------------------------------
view试图:
一:
from django.shortcuts import render
def login(request):
name = "wusen"
return render(request,"login.html",locals())
Html:<h1>{{ name }}</h1>
二:
from django.shortcuts import HttpResponse
def login(request):
return HttpResponse("OK")
三:
from django.shortcuts import redirect
def login(request):
return redirect("/url_demo1/")
四:json
from django.http import JsonResponse
def url_demo2(request):
response = {}
response["msg"] = "访问成功"
print(request.POST)
return JsonResponse(response)
也可以自己用import json 效果一样
-------------------------------------------------------------------------
如果想要配置静态文件static必须要在setting配置:
STATIC_URL = '/static/'
# 配置静态文件路径
import os
STATICFILES_DIRS=[
os.path.join(BASE_DIR,"statics")
]
-------------------------------------------------------------------------
最简单的一个Ajax访问:
{% csrf_token %}
<h1 id="ID">{{ name }}</h1>
<script src="/static/js/jquery-3.2.1.min.js"></script>
<script>
$.ajax({
url:"/url_demo2/",
type:"post",
data:{
"csrfmiddlewaretoken":$("[name='csrfmiddlewaretoken']").val()
},
success:function (data){
{#$("#ID").text(data.msg)#}
console.log(data)
}
})
</script>
注意:csrf_token与setting有关:
'django.middleware.csrf.CsrfViewMiddleware',
-------------------------------------------------------------------------
区别:html text val
console.log($("#ID").html()) =html代码
console.log($("#ID").text()) =文本值
console.log($("#ID").val()) =value
-------------------------------------------------------------------------
小记一下:queryset前台识别不了,但是django可以哦。
-------------------------------------------------------------------------
反向解析:
path(r"login/",views.login,name="LG"),
{% url "LG" %}
-------------------------------------------------------------------------
reverse反向解析和命名空间还没有整明白?????????
re_path("",include(("app1.urls","a"),namespace="a")),
-------------------------------------------------------------------------
多个参数:正则匹配需要多练习??????
path(r"article/<int:year>/<int:month>",views.article),
# 文章详情页
re_path('^(?P<username>\w+)/articles/(?P<article_id>\d+)$',views.article_detail),
# 个人站点url
re_path('^(?P<username>\w+)/$',views.home_site),
re_path('^(?P<username>\w+)/(?P<condition>tag|category|archive)/(?P<param>.*)/$',views.home_site),
-------------------------------------------------------------------------
post和get请求参数:
get请求: 浏览器直接方位 和 Ajax
post请求: form提交 和 Ajax
print(request.GET)
print(request.POST)
-------------------------------------------------------------------------
request的一些方法:::::::::::::
1.HttpRequest.GET
一个类似于字典的对象,包含 HTTP GET 的所有参数。详情请参考 QueryDict 对象。
2.HttpRequest.POST
一个类似于字典的对象,如果请求中包含表单数据,则将这些数据封装成 QueryDict 对象。
POST 请求可以带有空的 POST 字典 —— 如果通过 HTTP POST 方法发送一个表单,但是表单中没有任何的数据,QueryDict 对象依然会被创建。
因此,不应该使用 if request.POST 来检查使用的是否是POST 方法;应该使用 if request.method == "POST"
另外:如果使用 POST 上传文件的话,文件信息将包含在 FILES 属性中。
注意:键值对的值是多个的时候,比如checkbox类型的input标签,select标签,需要用:
request.POST.getlist("hobby")
3.HttpRequest.body
一个字符串,代表请求报文的主体。在处理非 HTTP 形式的报文时非常有用,例如:二进制图片、XML,Json等。
但是,如果要处理表单数据的时候,推荐还是使用 HttpRequest.POST 。
4.HttpRequest.path
一个字符串,表示请求的路径组件(不含域名)。
例如:"/music/bands/the_beatles/"
5.HttpRequest.method
一个字符串,表示请求使用的HTTP 方法。必须使用大写。
例如:"GET"、"POST"
6.HttpRequest.encoding
一个字符串,表示提交的数据的编码方式(如果为 None 则表示使用 DEFAULT_CHARSET 的设置,默认为 'utf-8')。
这个属性是可写的,你可以修改它来修改访问表单数据使用的编码。
接下来对属性的任何访问(例如从 GET 或 POST 中读取数据)将使用新的 encoding 值。
如果你知道表单数据的编码不是 DEFAULT_CHARSET ,则使用它。
7.HttpRequest.META
一个标准的Python 字典,包含所有的HTTP 首部。具体的头部信息取决于客户端和服务器,下面是一些示例:
CONTENT_LENGTH —— 请求的正文的长度(是一个字符串)。
CONTENT_TYPE —— 请求的正文的MIME 类型。
HTTP_ACCEPT —— 响应可接收的Content-Type。
HTTP_ACCEPT_ENCODING —— 响应可接收的编码。
HTTP_ACCEPT_LANGUAGE —— 响应可接收的语言。
HTTP_HOST —— 客服端发送的HTTP Host 头部。
HTTP_REFERER —— Referring 页面。
HTTP_USER_AGENT —— 客户端的user-agent 字符串。
QUERY_STRING —— 单个字符串形式的查询字符串(未解析过的形式)。
REMOTE_ADDR —— 客户端的IP 地址。
REMOTE_HOST —— 客户端的主机名。
REMOTE_USER —— 服务器认证后的用户。
REQUEST_METHOD —— 一个字符串,例如"GET" 或"POST"。
SERVER_NAME —— 服务器的主机名。
SERVER_PORT —— 服务器的端口(是一个字符串)。
从上面可以看到,除 CONTENT_LENGTH 和 CONTENT_TYPE 之外,请求中的任何 HTTP 首部转换为 META 的键时,
都会将所有字母大写并将连接符替换为下划线最后加上 HTTP_ 前缀。
所以,一个叫做 X-Bender 的头部将转换成 META 中的 HTTP_X_BENDER 键。
8.HttpRequest.FILES
一个类似于字典的对象,包含所有的上传文件信息。
FILES 中的每个键为<input type="file" name="" /> 中的name,值则为对应的数据。
注意,FILES 只有在请求的方法为POST 且提交的<form> 带有enctype="multipart/form-data" 的情况下才会
包含数据。否则,FILES 将为一个空的类似于字典的对象。
9.HttpRequest.COOKIES
一个标准的Python 字典,包含所有的cookie。键和值都为字符串。
10.HttpRequest.session
一个既可读又可写的类似于字典的对象,表示当前的会话。只有当Django 启用会话的支持时才可用。
完整的细节参见会话的文档。
11.HttpRequest.user(用户认证组件下使用)
一个 AUTH_USER_MODEL 类型的对象,表示当前登录的用户。
如果用户当前没有登录,user 将设置为 django.contrib.auth.models.AnonymousUser 的一个实例。你可以通过 is_authenticated() 区分它们。
例如:
if request.user.is_authenticated():
# Do something for logged-in users.
else:
# Do something for anonymous users.
user 只有当Django 启用 AuthenticationMiddleware 中间件时才可用。
-------------------------------------------------------------------------------------
匿名用户
class models.AnonymousUser
django.contrib.auth.models.AnonymousUser 类实现了django.contrib.auth.models.User 接口,但具有下面几个不同点:
id 永远为None。
username 永远为空字符串。
get_username() 永远返回空字符串。
is_staff 和 is_superuser 永远为False。
is_active 永远为 False。
groups 和 user_permissions 永远为空。
is_anonymous() 返回True 而不是False。
is_authenticated() 返回False 而不是True。
set_password()、check_password()、save() 和delete() 引发 NotImplementedError。
New in Django 1.8:
新增 AnonymousUser.get_username() 以更好地模拟 django.contrib.auth.models.User。
*/
print("--------",request.is_ajax())
print("--------", request.get_full_path())
-------------------------------------------------------------------------
模板:
模板变量:{{ name }}
模板过滤器: {{ name |safe }}
模板标签:{% for %}
-------------------------------------------------------------------------
模板变量:直接就可以点出来
<p>{{ name.upper }}</p>
<p>{{ name.lower }}</p>
-------------------------------------------------------------------------
模板过滤器:
1、add :将value的值增加2。使用形式为:{{ value | add: "2"}}。
2、addslashes:在value中的引号前增加反斜线。使用形式为:{{ value | addslashes }}。
3、capfirst:value的第一个字符转化成大写形式。使用形式为:{{ value | capfirst }}。
4、cut:从给定value中删除所有arg的值。使用形式为:{{ value | cut:arg}}。
5、date: 格式化时间格式。使用形式为:{{ value | date:"Y-m-d H:M:S" }}
6、default:如果value是False,那么输出使用缺省值。使用形式:{{ value | default: "nothing" }}。例如,如果value是“”,那么输出将是nothing
7、default_if_none:如果value是None,那么输出将使用缺省值。使用形式:{{ value | default_if_none:"nothing" }},例如,如果value是None,那么输出将是nothing
8、dictsort:如果value的值是一个字典,那么返回值是按照关键字排序的结果
使用形式:{{ value | dictsort:"name"}},例如,
如果value是:
[{'name': 'python'},{'name': 'java'},{'name': 'c++'},]
那么,输出是:
[{'name': 'c++'},{'name': 'java'},{'name': 'python'}, ]
9、dictsortreversed:如果value的值是一个字典,那么返回值是按照关键字排序的结果的反序。使用形式:与dictsort过滤器相同。
10、divisibleby:如果value能够被arg整除,那么返回值将是True。使用形式:{{ value | divisibleby:arg}},如果value是9,arg是3,那么输出将是True
11、escape:替换value中的某些字符,以适应HTML格式。使用形式:{{ value | escape}}。例如,< 转化为 <> 转化为 >' 转化为 '" 转化为 "
13、filesizeformat:格式化value,使其成为易读的文件大小。使用形式:{{ value | filesizeformat }}。例如:13KB,4.1MB等。
14、first:返回列表/字符串中的第一个元素。使用形式:{{ value | first }}
16、iriencode:如果value中有非ASCII字符,那么将其进行转化成URL中适合的编码,如果value已经进行过URLENCODE,改操作就不会再起作用。使用形式:{{value | iriencode}}
17、join:使用指定的字符串连接一个list,作用如同python的str.join(list)。使用形式:{{ value | join:"arg"}},如果value是['a','b','c'],arg是'//'那么输出是a//b//c
18、last:返回列表/字符串中的最后一个元素。使用形式:{{ value | last }}
19、length:返回value的长度。使用形式:{{ value | length }}
20、length_is:如果value的长度等于arg的时候返回True。使用形式:{{ value | length_is:"arg"}}。例如:如果value是['a','b','c'],arg是3,那么返回True
21、linebreaks:value中的"\n"将被<br/>替代,并且整个value使用</p>包围起来。使用形式:{{value|linebreaks}}
22、linebreaksbr:value中的"\n"将被<br/>替代。使用形式:{{value |linebreaksbr}}
23、linenumbers:显示的文本,带有行数。使用形式:{{value | linenumbers}}
24、ljust:在一个给定宽度的字段中,左对齐显示value。使用形式:{{value | ljust}}
25、center:在一个给定宽度的字段中,中心对齐显示value。使用形式:{{value | center}}
26、rjust::在一个给定宽度的字段中,右对齐显示value。使用形式:{{value | rjust}}
27、lower:将一个字符串转换成小写形式。使用形式:{{value | lower}}
30、random:从给定的list中返回一个任意的Item。使用形式:{{value | random}}
31、removetags:删除value中tag1,tag2....的标签。使用形式:{{value | removetags:"tag1 tag2 tag3..."}}
32、safe:当系统设置autoescaping打开的时候,该过滤器使得输出不进行escape转换。使用形式:{{value | safe}}
33、safeseq:与safe基本相同,但有一点不同的就是:safe是针对字符串,而safeseq是针对多个字符串组成的sequence
34、slice:与python语法中的slice相同。使用形式:{{some_list | slice:"2"}}
37、striptags:删除value中的所有HTML标签.使用形式:{{value | striptags}}
38、time:格式化时间输出。使用形式:{{value | time:"H:i"}}或者{{value | time}}
39、title:转换一个字符串成为title格式。
40、truncatewords:将value切成truncatewords指定的单词数目。使用形式:{{value | truncatewords:2}}。例如,如果value是Joel is a slug 那么输出将是:Joel is ...
42、upper:转换一个字符串为大写形式
43、urlencode:将一个字符串进行URLEncode
46、wordcount:返回字符串中单词的数目
-------------------------------------------------------------------------
模板标签:for if
{% for i in arr %}
<h1>{{ forloop.counter }}----->{{ i }}</h1>
{% endfor %}
记住:if条件的时间一定要遵循p8规范,不然会报错
{% for i in arr %}
{% if i > 5 %}
<h1 style="color: aquamarine">{{ i }}</h1>
{% elif i > 3 %}
<h1 style="color: bisque">{{ i }}</h1>
{% else %}
<h1 style="color: blue">{{ i }}</h1>
{% endif %}
{% endfor %}
这个有点鸡肋,我没试出来什么时候起作用。empty
{% for i in arr %}
<h1>---->{{ i.name }}</h1>
{% empty %}
shabi
{% endfor %}
with:没测试,暂时不知道怎么用,???????
with
使用一个简单地名字缓存一个复杂的变量,当你需要使用一个“昂贵的”方法(比如访问数据库)很多次的时候是非常有用的
例如:
{% with total=business.employees.count %}
{{ total }} employee{{ total|pluralize }}
{% endwith %}
-------------------------------------------------------------------------
自定义标签和过滤器步骤:
1、在settings中的INSTALLED_APPS配置当前app,不然django无法找到自定义的simple_tag.
2、在app中创建templatetags模块(模块名只能是templatetags)
3、创建任意 .py 文件,如:my_tags.py
注意:register = template.Library()
必须是register 还有就是L是大写
html想用的时候先导入,再用
-------------------------------------------------------------------------
自定义模板标签:
@register.simple_tag
def simple_tag_multi1(v1,v2):
return v1 * v2
HTML调用:
{% load my_tags %}
{% simple_tag_multi1 1 2 %}
-------------------------------------------------------------------------
自定义模板过滤器:
from django import template
from django.utils.safestring import mark_safe
register = template.Library()
@register.filter
def filter_mul1(x):
return x*x
@register.filter
def filter_mul2(x,y):
return x*y
HTML调用:
{% load my_tags %}
{{ arr.2|filter_mul1}}
{{ arr.2|filter_mul2:2}}
-------------------------------------------------------------------------
他们的区别:
过滤器和模板标签的区别:
@register.filter
只能传递两个变量,多个的话要用循环
能在%if变量判断时使用 {%if i|myxx1:3 >100%} 可以这样用,我觉得和for一起用的更多
@register.simple)_tag
能传递多个变量
不能在%if变量判断时使用
-------------------------------------------------------------------------
模板继承 (extend):
在base.html里面留个空
{% block content %}
{% endblock %}
然后再子类login.html去继承,去重写空
{% extends "base.html" %}
{% block content %}
<div class="container bg-info">
我不爱你了
</div>
{% endblock %}
-------------------------------------------------------------------------
ORM模型来喽:
首先要写表结构:
from django.db import models
# Create your models here.
# 单表
# class Book(models.Model):
# id=models.AutoField(primary_key=True)
# title=models.CharField(max_length=32)
# state=models.BooleanField()
# pub_date=models.DateField()
# price=models.DecimalField(max_digits=8,decimal_places=2)
# publish=models.CharField(max_length=32)
class Author(models.Model):
nid = models.AutoField(primary_key=True)
name=models.CharField( max_length=32)
age=models.IntegerField()
# 与AuthorDetail建立一对一的关系
authorDetail=models.OneToOneField(to="AuthorDetail",on_delete=models.CASCADE)
class AuthorDetail(models.Model):
nid = models.AutoField(primary_key=True)
birthday=models.DateField()
telephone=models.BigIntegerField()
addr=models.CharField( max_length=64)
class Publish(models.Model):
nid = models.AutoField(primary_key=True)
name=models.CharField( max_length=32)
city=models.CharField( max_length=32)
email=models.EmailField()
class Book(models.Model):
nid = models.AutoField(primary_key=True)
title = models.CharField( max_length=32)
publishDate=models.DateField()
price=models.DecimalField(max_digits=5,decimal_places=2)
comment_num=models.IntegerField(default=0)
read_num = models.IntegerField(default=0)
# 与Publish建立一对多的关系,外键字段建立在多的一方 null=true 2版本用外键一定要加on_delete
publish=models.ForeignKey(to="Publish",to_field="nid",on_delete=models.CASCADE)
# 与Author表建立多对多的关系,ManyToManyField可以建在两个模型中的任意一个,自动创建第三张表
authors=models.ManyToManyField(to='Author')
-------------------------------------------------------------------------
第一步:model.py写表结构
第二步: 配置setting
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.mysql',
'NAME': 'orm', # 要连接的数据库,连接前需要创建好
'USER': 'root', # 连接数据库的用户名
'PASSWORD': '123456', # 连接数据库的密码
'HOST': '127.0.0.1', # 连接主机,默认本级
'PORT': 3306 # 端口 默认3306
}
}
第三步:在项目/项目/init.py下写入
import pymysql
pymysql.install_as_MySQLdb()
第四步:
接下来在ww1窗口命令下执行:数据库迁移
python manage.py makemigrations
python manage.py migrate
第五步:创建一个超级用户
python manage.py createsuperuser
-------------------------------------------------------------------------
如何可以在浏览器通过admin修改数据
需要在 项目/程序/admin.py配置
from django.contrib import admin
from app1 import models
admin.site.register(models.Publish)
admin.site.register(models.Author)
admin.site.register(models.AuthorDetail)
admin.site.register(models.Book)
-------------------------------------------------------------------------
首先说一下登录功能:?????????不知道auth.login是干什么的
from django.contrib import auth
def login(request):
if request.method == "POST":
user = request.POST.get("user")
pwd = request.POST.get("pwd")
user = auth.authenticate(username=user,password=pwd)
if user:
auth.login(request,user)
return render(request, "index.html", locals())
return render(request,"login.html",locals())
-------------------------------------------------------------------------
注册功能:需要自己写form组件
from django.contrib.auth.models import AbstractUser
def register(request):
if request.method == "POST":
user = request.POST.get("user")
pwd = request.POST.get("pwd")
print(user,pwd)
user = auth.models.User.objects.filter(username=user)
print("注册:",user)
if not user:
auth.models.User.objects.create(username=user,password=pwd)
return redirect("/login/")
return render(request, "register.html", locals())
如果自己写组件的话:在程序下创建my_forms.py
from blog.models import UserInfo
from django import forms
from django.forms import widgets
from django.core.exceptions import NON_FIELD_ERRORS,ValidationError
class UserForm(forms.Form):
user = forms.CharField(max_length=32,
error_messages={"required":"用户名你都不写注册个屁"},
label="用户名",
widget=widgets.TextInput(attrs={"class": "form-control"})
)
pwd = forms.CharField(max_length=32,
error_messages={"required": "你不写密码你觉得你很吊?"},
label="密码",
widget=widgets.PasswordInput(attrs={"class": "form-control"})
)
re_pwd = forms.CharField(max_length=32,
error_messages={"required": "让你重复一下密码有那么难?"},
label="重复密码",
widget=widgets.PasswordInput(attrs={"class": "form-control"})
)
email = forms.EmailField(max_length=32,
error_messages={"required": "你不会穷的连QQ邮箱都没有吧"},
label="邮箱",
widget=widgets.EmailInput(attrs={"class": "form-control"})
)
def clean_user(self):
val = self.cleaned_data.get("user")
user = UserInfo.objects.filter(username=val).first()
if not user:
return val
else:
raise ValidationError("该用户已经注册,你来晚啦")
def clean(self):
pwd = self.cleaned_data.get("pwd")
re_pwd = self.cleaned_data.get("re_pwd")
print(pwd,re_pwd)
if pwd and re_pwd:
if pwd == re_pwd:
return self.cleaned_data
else:
raise ValidationError("两次密码不一致")
在视图中:
from blog.my_forms import UserForm
def register(request):
response = {"user": None, "msg": None}
if request.is_ajax():
form = UserForm(request.POST)
print(request.POST.get("user"))
response = {"user": None, "msg": None}
if form.is_valid():
response["user"] = request.POST.get("user")
user = form.cleaned_data.get("user")
pwd = form.cleaned_data.get("pwd")
email = form.cleaned_data.get("email")
avatar_obj = request.FILES.get("avatar")
extra = {}
if avatar_obj:
extra["avatar"] = avatar_obj
UserInfo.objects.create_user(username=user, password=pwd, email=email, **extra)
else:
response["msg"] = form.errors
return JsonResponse(response)
form = UserForm()
return render(request, "register.html", {"form": form})
-------------------------------------------------------------------------
如果想打印mysql语句 需要在setting配置
LOGGING = {
'version': 1,
'disable_existing_loggers': False,
'handlers': {
'console':{
'level':'DEBUG',
'class':'logging.StreamHandler',
},
},
'loggers': {
'django.db.backends': {
'handlers': ['console'],
'propagate': True,
'level':'DEBUG',
},
}
}
-------------------------------------------------------------------------
# 单表::::::::::::::
#增删改查:
## 添加数据
# 添加数据方法一(不推荐使用):
book_obj = models.Book(title="a",price=1,publishDate=datetime.datetime.strptime("2014-11-1","%Y-%M-%d"),publish_id=2)
book_obj.save()
#添加数据方法二:推荐使用
book_obj = models.Book.objects.create(title="a",price=1,publishDate=datetime.datetime.strptime("2014-11-1","%Y-%M-%d"),publish_id=2)
print("插入成功")
# 查询数据
arr = models.Book.objects.all()
arr = models.Book.objects.filter(title="a")
book_obj = models.Book.objects.first()
book_obj = models.Book.objects.get(nid=1)
book_obj = models.Book.objects.last()
book_obj = models.Book.objects.count()
arr = models.Book.objects.exclude(nid=7)
book_obj = models.Book.objects.filter(nid=100).exists()
arr = models.Book.objects.values("nid","title")
arr = models.Book.objects.values_list("nid","title")
arr = models.Book.objects.values("title").distinct()
# 基于双下划线的模糊查询 gt,gte,lt,lte
models.Book.objects.filter(price__in=[100, 200, 300])
models.Book.objects.filter(price__gt=100)
models.Book.objects.filter(price__lt=100)
models.Book.objects.filter(price__range=[100, 200])
models.Book.objects.filter(title__contains="python") 区分大小写
models.Book.objects.filter(title__icontains="python") 不区分大小写
models.Book.objects.filter(title__startswith="py")
models.Book.objects.filter(pub_date__year=2012)
# 删除数据
count = models.Book.objects.filter(title="a").delete()
# 更新数据
book_obj = models.Book.objects.filter(title="撒打算").update(title="书籍C")
-------------------------------------------------------------------------
# 多表操作
# # 一对多:方式一
# models.Publish.objects.create(name="人民出版社",email="2096@qq.com",city="人民战斗机第")
# models.Book.objects.create(title="西游记",price=100,publishDate="2014-1-1",publish_id=3)
# # 一对多 方式二
# p = models.Publish.objects.create(name="人民出版社", email="2096@qq.com", city="人民战斗机第")
# models.Book.objects.create(title="西游记", price=100, publishDate="2014-1-1", publish=p)
#多对多添加数据
book_obj = models.Book.objects.filter(title="书籍C").first()
book_obj.authors.add(2,3) ##nid的值
book_obj.authors.add(author1,author2)
# 解除多对多关系
book_obj.authors.remove(3,5) ##nid的值
book_obj.authors.clear()
多对多反向操作:
author_obj = models.Author.objects.filter(name="作者C").first()
author_obj.book_set.add(4,5)
author_obj.book_set.remove(4, 5)
author_obj.book_set.clear()
-------------------------------------------------------------------------
# ====================跨表查询==============
# 第一种:基于对象的查询 第二种:基于双划线的查询
# 第三种:聚合 和 分组 查询 第四种:F与Q查询
-------------------------------------------------------------------------
第一种:基于对象的查询
# 一对一 正向
author_obj = models.Author.objects.first()
print(author_obj.authorDetail.birthday)
# 一对一 反向
authordetail_obj = models.AuthorDetail.objects.last()
print(authordetail_obj.author.name)
#一对多 正向 书和出版社
book_obj = models.Book.objects.first()
print(book_obj.publish)
# 一对多 反向 书和出版社
publish_obj = models.Publish.objects.filter(nid=2).first()
print(publish_obj.book_set.all())
#多对多 正向 数和作者
book_obj = models.Book.objects.get(nid=2)
print(book_obj.authors)
# 多对多 反向 书和作者
publish_obj = models.Publish.objects.get(nid=2)
print(publish_obj.book_set.all())
-------------------------------------------------------------------------
第二种:基于双划线的查询
# 一对一 正向查询 作者和作者详情表
author_arr = models.Author.objects.all().values("authorDetail__birthday")
print(author_arr)
# 一对一 反向查询 作者和作者详情表
author_arr = models.Author.objects.filter(authorDetail_id=2)
print(author_arr)
# 一对多 正向 书和出版社
book_obj = models.Book.objects.all().values("publish__name")
print(book_obj)
# 一对多 反向 书和出版社
publish_obj = models.Publish.objects.filter(book__title="书籍C")
print(publish_obj)
# 多对多 正向 数和作者
book_obj = models.Book.objects.all().values("authors__name")
print(book_obj)
# 多对多 反向 书和作者
publish_obj = models.Publish.objects.filter(book__title="书籍C")
print(publish_obj)
-------------------------------------------------------------------------
第三种:聚合 和 分组 查询
from django.db.models import Avg, Count, Max, Min
# 书和出版社 通过书的id分组
arr = models.Publish.objects.values("nid").annotate(c=Count("book__nid")).values("name","c")
print(arr)
-------------------------------------------------------------------------
第四种:F与Q查询
from django.db.models import F,Q
arr = models.Book.objects.values(money=F("price")+100)
Book.objects.update(price=F("price")+100)
b1 = Book.objects.filter(comment_num__gt=F("read_num"))
b2 = Book.objects.filter(Q(comment_num=30)&Q(read_num=21))
-------------------------------------------------------------------------
django 查询 排序 orderby
# orderby 升序和降序
arr = models.Book.objects.order_by("nid")
arr = models.Book.objects.order_by("-nid")
-------------------------------------------------------------------------
# 批量插入数据
# book_list = []
# for i in range(100):
# book = Book(title=f"book_{i}",price=i,publishDate="2014-10-11",publish_id=1)
# book_list.append(book)
# Book.objects.bulk_create(book_list)
-------------------------------------------------------------------------
ContentType指的是请求体的编码类型,常见的类型共有3种:
1 application/x-www-form-urlencoded
2 multipart/form-data
3 application/json
-------------------------------------------------------------------------
Ajax与文件上传
HTML:
<input type="file" id="file">
<button class="btn" id="btn_sendfile">文件上传</button>
script:
$("#btn_sendfile").click(function (){
var formdata=new FormData();
formdata.append("user","wusen");
formdata.append("file",$("#file")[0].files[0]);
$.ajax({
url:"",
type:"post",
data: formdata,
processData: false , // 不处理数据
contentType: false, // 不设置内容类型
success:function (data){
console.log("成功")
}
})
})
视图:
if request.is_ajax():
with open("D://a.png","wb") as f:
for line in request.FILES.get("file"):
f.write(line)
-------------------------------------------------------------------------
说一下客户端的头像:
HTMl:
<label for="b" id="a">
<img src="D://a.jpg" id="c">
</label>
<input type="file" name="" id="b">
script:
$("#b").change(function(){
var file_obj = $(this)[0].files[0]
var reader = new FileReader()
reader.readAsDataURL(file_obj)
reader.onload=function(){
$("#c").attr("src",reader.result)
console.log(reader.result)
console.log("结束")
}
})
-------------------------------------------------------------------------
分页器:
# 有一个小知识点 # 不存在的情况下,默认值为11
# request.GET.get("page",11)
from django.core.paginator import Paginator
from django.core.paginator import PageNotAnInteger
from django.core.paginator import EmptyPage
arr = models.Publish.objects.all()
paginator = Paginator(arr,5)
print(paginator.count) # 一共多少条数据
print(paginator.num_pages) # 一共多少条数据
print(paginator.page_range) # 一共多少条数据
arr = paginator.get_page(3)
print(arr.next_page_number())
print(arr.has_next())
print(arr.previous_page_number())
print(arr.has_previous())
-------------------------------------------------------------------------
forms组件
from app1.models import UserInfo
from django import forms
from django.forms import widgets
from django.core.exceptions import NON_FIELD_ERRORS,ValidationError
class UserForm(forms.Form):
user = forms.CharField(max_length=32,
error_messages={"required":"用户名你都不写注册个屁"},
label="用户名",
widget=widgets.TextInput(attrs={"class": "form-control"})
)
pwd = forms.CharField(max_length=32,
error_messages={"required": "你不写密码你觉得你很吊?"},
label="密码",
widget=widgets.PasswordInput(attrs={"class": "form-control"})
)
re_pwd = forms.CharField(max_length=32,
error_messages={"required": "让你重复一下密码有那么难?"},
label="重复密码",
widget=widgets.PasswordInput(attrs={"class": "form-control"})
)
email = forms.EmailField(max_length=32,
error_messages={"required": "你不会穷的连QQ邮箱都没有吧"},
label="邮箱",
widget=widgets.EmailInput(attrs={"class": "form-control"})
)
def clean_user(self): 局部钩子
val = self.cleaned_data.get("user")
user = UserInfo.objects.filter(username=val).first()
if not user:
return val
else:
raise ValidationError("该用户已经注册,你来晚啦")
def clean(self): 全局钩子
pwd = self.cleaned_data.get("pwd")
re_pwd = self.cleaned_data.get("re_pwd")
print(pwd,re_pwd)
if pwd and re_pwd:
if pwd == re_pwd:
return self.cleaned_data
else:
raise ValidationError("两次密码不一致")
-------------------
if request.method == "POST":
form = UserForm(request.POST)
if form.is_valid():
print("此时所有的都通过了校验",form.cleaned_data) # 所有干净的字段以及对应的值
else:
clean_error = form.errors.get("__all__")
print("错误字段",form.errors)
response["msg"] = form.errors
return JsonResponse(response)
form = UserForm()
<div class="container" >
<form id="forms">
{% for f in form %}
<p>{{ f.label }}</p>
<p>{{ f }}
<span class="pull-right"></span>
</p>
{% endfor %}
<button class="btn btn-danger btn_register">提交</button>
</form>
</div>
$(".btn_register").click(function (){
var formdata = new FormData()
var requestData = $("#forms").serializeArray()
$.each(requestData,function (index,data){
console.log(data.name,data.value)
formdata.append(data.name,data.value)
})
$.ajax({
url: "",
data:formdata,
type: "post",
contentType: false,
processData: false,
success:function (data){
$.each(data.msg,function (key,value){
$("#id_"+key).parent().addClass("has-error")
$("#id_"+key).next().text(value)
})
}
})
})
</script>
综上所述:forms组件是用来帮助校验用的,一般用于注册校验。
首先自己写forms组件,定义一个py文件,自己写(此时只用到forms组件)
然后在视图中实例化forms类,你可以直接用,在前端用for标签渲染
用Ajax往这边传数据的时候,如果想传不被序列化的数据时,一定要加上参数
contentType: false,processData: false,
然后视图中分两步:一种是全部通过校验is_valid
否则,干净数据和脏数据分开。
其余有局部钩子和全局钩子。
他会先把forms校验完毕,再去校验全部和局部钩子
局部钩子和全局钩子写功能的时候就可能会用到你的model里面的表喽。
-------------------------------------------------------------------------
cookie和session:
1、cookie 和session的区别是bai:cookie数据保存在客户端,session数据保存在服务器端。
2、两个都可以用来存私密的东西,同样也都有有效期的说法,区别在于session是放在服务器上的,过期与否取决于服务期的设定,cookie是存在客户端的,过去与否可以在cookie生成的时候设置进去。
(1)、cookie数据存放在客户的浏览器上,session数据放在服务器上 ;
(2)、cookie不是很安全,别人可以分析存放在本地的COOKIE并进行COOKIE欺骗,如果主要考虑到安全应当使用session ;
(3)、session会在一定时间内保存在服务器上。当访问增多,会比较占用你服务器的性能,如果主要考虑到减轻服务器性能方面,应当使用COOKIE ;
(4)、单个cookie在客户端的限制是3K,就是说一个站点在客户端存放的COOKIE不能3K;
(5)、所以将登陆信息等重要信息存放为SESSION;其他信息如果需要保留,可以放在COOKIE中。
3、cookie和session的共同之处在于:cookie和session都是用来跟踪浏览器用户身份的会话方式。
4、cookie 是一种发送到客户浏览器的文本串句柄,并保存在客户机硬盘上,可以用来在某个WEB站点会话间持久的保持数据。
怎么用COOKIES
response = HttpResponse()
response = render()
response = redirect()
response.set_cookie("a","aa")
下面这个不是加密,客户端的人会看不懂,相当于加密
response.set_signed_cookie("b","bb")
return response
获取cookie:
request.COOKIES
删除cookie:
response.delete_cookie("cookie_key")
源码:
class HttpResponseBase:
def set_cookie(self, key, 键
value='', 值
max_age=None, 超长时间
cookie需要延续的时间(以秒为单位)
如果参数是\ None`` ,这个cookie会延续到浏览器关闭为止。
expires=None, 超长时间
expires默认None ,cookie失效的实际日期/时间。
path='/', Cookie生效的路径,
浏览器只会把cookie回传给带有该路径的页面,这样可以避免将
cookie传给站点中的其他的应用。
/ 表示根路径,特殊的:根路径的cookie可以被任何url的页面访问
domain=None, Cookie生效的域名
你可用这个参数来构造一个跨站cookie。
如, domain=".example.com"
所构造的cookie对下面这些站点都是可读的:
www.example.com 、 www2.example.com
和an.other.sub.domain.example.com 。
如果该参数设置为 None ,cookie只能由设置它的站点读取。
secure=False, 如果设置为 True ,浏览器将通过HTTPS来回传cookie。
httponly=False 只能http协议传输,无法被JavaScript获取
(不是绝对,底层抓包可以获取到也可以被覆盖)
): pass
SESSION:
第一步需要配置在setting
SESSION_ENGINE = 'django.contrib.sessions.backends.db' # 引擎(默认)
SESSION_COOKIE_NAME = "sessionid" # Session的cookie保存在浏览器上时的key,即:sessionid=随机字符串(默认)
SESSION_COOKIE_PATH = "/" # Session的cookie保存的路径(默认)
SESSION_COOKIE_DOMAIN = None # Session的cookie保存的域名(默认)
SESSION_COOKIE_SECURE = False # 是否Https传输cookie(默认)
SESSION_COOKIE_HTTPONLY = True # 是否Session的cookie只支持http传输(默认)
SESSION_COOKIE_AGE = 1209600 # Session的cookie失效日期(2周)(默认)
SESSION_EXPIRE_AT_BROWSER_CLOSE = False # 是否关闭浏览器使得Session过期(默认)
SESSION_SAVE_EVERY_REQUEST = False # 是否每次请求都保存Session,默认修改之后才保存(默认)
session怎么用呢。。。
django中session语法
1、设置Sessions值
request.session['session_name'] ="admin"
2、获取Sessions值
session_name = request.session["session_name"]
3、删除Sessions值
del request.session["session_name"]
4、flush()
删除当前的会话数据并删除会话的Cookie。
这用于确保前面的会话数据不可以再次被用户的浏览器访问
5、get(key, default=None)
fav_color = request.session.get('fav_color', 'red')
6、pop(key)
fav_color = request.session.pop('fav_color')
7、keys()
8、items()
9、setdefault()
10 用户session的随机字符串
request.session.session_key
# 将所有Session失效日期小于当前日期的数据删除
request.session.clear_expired()
# 检查 用户session的随机字符串 在数据库中是否
request.session.exists("session_key")
# 删除当前用户的所有Session数据
request.session.delete("session_key")
request.session.set_expiry(value)
* 如果value是个整数,session会在些秒数后失效。
* 如果value是个datatime或timedelta,session就会在这个时间后失效。
* 如果value是0,用户关闭浏览器session就会失效。
* 如果value是None,session会依赖全局session失效策略。
-------------------------------------------------------------------------
用户认证组件(这个就是django帮我们封装的,原理是session)
auth_user这个表是django帮我们提供的
from django.contrib import auth
此时只是帮你校验是否存在User。此时用request.user是没有值的
user = authenticate(username='someone',password='somepassword')
此时request.user是全局变量
auth.login()
注销功能
auth.logout()
我们需要功能验证用户是否登录:
from django.contrib.auth.decorators import login_required
1.request.user.is_authenticated 只要不执行login()就是False
2.@login_required 装饰器哦
若用户没有登录,则会跳转到django默认的 登录URL '/accounts/login/ ' (这个值可以在settings文件中配置LOGIN_URL="/login/")。并传递 当前访问url的绝对路径 (登陆成功后,会重定向到该路径)。
创建用户:
from django.contrib.auth.models import User
user = User.objects.create_user(username='',password='',email='')
就是用这个表去操作
修改密码:但是如果用表去更新数据呢!到时候再说
user = User.objects.get(username='')
user.set_password(password='')
user.save
-------------------------------------------------------------------------
中间键:
中间件顾名思义,是介于request与response处理之间的一道处理过程,相对比较轻量级,并且在全局上改变django的输入与输出。因为改变的是全局,所以需要谨慎实用,用不好会影响到性能。
process_request 默认返回值就是return None
process_view
process_exception
process_response
浏览器请求-wsgrief-中间键123-路由控制-数据库-模板-中间键321-wsgrief-浏览器
如果中间键1的request你给返回值,那么他会
浏览器请求-wsgrief-中间键1-中间键1-wsgrief-浏览器
浏览器请求-wsgrief-process_request123-路由控制-process_view123-数据库-模板-process_response321-wsgrief-浏览器
视图报错会触发process_exception
第一步:在setting配置
MIDDLEWARE = [
'django.middleware.security.SecurityMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.common.CommonMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
]
第二步:自己写一个py文件中间键,并且把路径加到setting里面
第三步:没了
from django.utils.deprecation import MiddlewareMixin
class Md1(MiddlewareMixin):
def process_request(self,request):
print("Md1请求")
def process_response(self,request,response):
print("Md1返回")
return response
作为延伸扩展内容,有余力的同学可以尝试着读一下以下两个自带的中间件:
'django.contrib.sessions.middleware.SessionMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
应用:
1、做IP访问频率限制(我觉得用session和cookie做比较好)
某些IP访问服务器的频率过高,进行拦截,比如限制每分钟不能超过20次。
2、URL访问过滤
-------------------------------------------------------------------------
补充:ORM嵌套查询, 每个出版社,最便宜的书籍以及名字
querymin = models.Publish.objects.values("nid").annotate(min_price=Min("book__price")).values("min_price")
ret = models.Publish.objects.filter(book__price__in=querymin).values("nid","book__title","book__price")
print(ret)