django进阶
django ORM操作
models.py
from django.db import models# Create your models here. class Book(models.Model):name = models.CharField(max_length=128)price = models.PositiveSmallIntegerField(null=True)#正數,null=True不是必填authors = models.ManyToManyField('Author')publisher = models.ForeignKey('Publisher')pub_date = models.DateField()# memo = models.CharField(null=True,max_length=64)數據庫新增字段的時候,需要加上null=True#為了在查詢時顯示對象的名字def __str__(self):return self.nameclass Author(models.Model):name = models.CharField(max_length=32)email = models.EmailField(unique=True)def __str__(self):return self.nameclass Publisher(models.Model):name = models.CharField(max_length=128,unique=True)website = models.URLField(unique=True)def __str__(self):return "%s %s"%(self.name,self.website)terminal下進行數據庫的增刪改查
python3 manage.py shell from app01 import modelsbook表增加數據,關聯author和publisher表,所以先創建author和publisher,創建時不能直接指定author
models.Author.objects.create(name='alex',email='alex3714@126.com') models.Publisher.objects.create(name='tsinghua',website='http://tsinghua.com)b2 = models.Book.objects.create(name='linux',price=55,publisher_id=2,pub_date='2016-01-01')
b2.authors.add(1,2)
b2.authors.all()#查詢這本書的作者,創建完之后是保存在app01_book_authors表中
b2.authors.remove()
b2.publiser.name#查看外鍵關鍵的表的屬性
查
返回列表 models.Book.objects.fliter()
返回單個對象或錯誤,如果get到多條會報錯 models.Book.objects.get()
models.Book.objects.get(pub_date__gt = '2017-01-01')查詢沒有就創建
models.Book.objects.get_or_create(name='java',pub_date='2019-01-01',publisher_id=1)
(<Book: java>, True)
包含(contains,incontains忽略大小寫)
models.Book.objects.filter(name__contains='go')
<QuerySet [<Book: go>]>
查name和price
models.Book.objects.values('name','price')
<QuerySet [{'name': 'python', 'price': 50}, {'name': 'linux', 'price': 55}, {'name': 'go', 'price': 100}, {'name': 'java', 'price': None}]>
查價格不等于50的book
models.Book.objects.exclude(price=50)
<QuerySet [<Book: linux>, <Book: go>, <Book: java>]>
aggregate 聚合
書的平均價格
from django.db.models import Avg,Sum,Max,Min,Count
models.Book.objects.all().aggregate(Avg('price'))
每個出版社出的書和書的平均價格
from django.db.models import Count
models.Book.objects.values('publisher__name').annotate(Count('id'))
models.Book.objects.values('publisher__name').annotate(Avg('price'))
Q
2016或2017出版的書
q = Q(pub_date__year='2016')|Q(pub_date__year='2017')
models.Book.objects.filter(q)
<QuerySet [<Book: python>, <Book: linux>]>
F
自修改
from django.db.models import F
models.Book.objects.update(price=F('price')+10)
本表兩字段比較
from datetime import timedelta
models.Book.objects.filter(pub_date__lt=F('pub_date')+timedelta(days=3))
字段遷移
from django.db.models import F
models.Book.objects.update(memo=F('name'))
通過出版社查詢每個出版社出了多少書
p1 = models.Publisher.objects.all()[1]
p1.book_set.all()
FBV和CBV
function+base+view
class+base+view
- urls.py
- views.py
pass
?
?
?
FORM表單
1、app01下創建文件forms.py
from django import forms from app01 import models FAVORITE_COLORS_CHOICES=(('blue','BLUE'),('green','Green'),('black','Black'), ) BIRTH_YEAR_CHOICES = ('1980','1981','1982') seat_CHOICE = (('1','First',),('2','Second',))import re def mobile_validate(value):mobile_re = re.compile(r'^(13[0-9]|15[012356789]|17[678]|18[0-9]|14[57])[0-9]{8}$')if not mobile_re.match(str(value)):raise forms.ValidationError('手機號碼格式錯誤')class MailSendForm(forms.Form):sender = forms.EmailField()receiver = forms.EmailField()subject = forms.CharField(max_length=12)content = forms.CharField(widget=forms.Textarea(attrs={'cols':100,'class':'font-color','style':'background-color:lightgreen'}))birth_year = forms.DateField(widget=forms.SelectDateWidget(years=BIRTH_YEAR_CHOICES))mobile = forms.IntegerField(validators=[mobile_validate, ],error_messages={'required': '手機不能為空'},widget=forms.TextInput(attrs={'class': 'form-control','placeholder': '手機號碼'}))choice_field = forms.ChoiceField(widget=forms.RadioSelect,choices=seat_CHOICE)favorite_colors = forms.MultipleChoiceField(widget=forms.CheckboxSelectMultiple,choices=FAVORITE_COLORS_CHOICES,)def clean_sender(self):#對哪個字段做認證,就clean_xxprint('validate sender',self.cleaned_data)if self.cleaned_data.get('sender') != 'alex@126.com':self.add_error('sender','only')return self.cleaned_data.get('sender')#不返回的話cleaned_data里面'sender'為Nonedef clean(self):#所有的clean_field都驗證完成后,才會執行print('clean data',self.cleaned_data)sender = self.cleaned_data.get('sender')receiver = self.cleaned_data.get('receiver')if sender == receiver:raise forms.ValidationError('發送者和接受者不能相同')class BookForm(forms.ModelForm):class Meta:model = models.Bookfields = "__all__"exclude = ['memo',]2、views.py
from django.shortcuts import render from app01.forms import MailSendForm from app01.forms import BookForm from django.views import View # Create your views here. def mail(request):if request.method == 'POST':form = MailSendForm(request.POST)if form.has_changed():print('form has changed')if form.is_valid():#驗證表單數據是否合法print('fuck',form.cleaned_data)else:print('error',form.errors)else:form = MailSendForm(initial={'sender':'sb@126.com'})return render(request,'mail_send.html',{'form':form})def book_mgr(request):if request.method == 'POST':form = BookForm(data=request.POST)if form.is_valid():form.save()form = BookForm()else:form = BookForm()return render(request,'book.html',{'form':form}) class BookMgr(View):form_class = BookFormtemplate_name = 'book.html'def get(self,request):print('get',request.GET)form = self.form_class()return render(request,self.template_name,{'form':form})def post(self,request):form = self.form_class(data=request.POST)if form.is_valid():form.save()form = self.form_class()return render(request,self.template_name,{'form':form})3、mail_send.html
<!DOCTYPE html> <html lang="en"> <head><meta charset="UTF-8"><title>Title</title> </head> <body><div><form method="post">{% for item in form %}<div>{{ item.label }} {{ item }}{% if item.errors %}<span style="color: red">{{ item.errors }}</span>{% endif %}</div>{% endfor %}<input type="submit" value="send"/></form></div> </body> </html>modelform
form.py
class BookForm(forms.ModelForm):class Meta:model = models.Bookfields = "__all__"exclude = ['memo',]view.py
def book_mgr(request):if request.method == 'POST':form = BookForm(data=request.POST)if form.is_valid():form.save()form = BookForm()else:form = BookForm()return render(request,'book.html',{'form':form})?
CSRF(Cross Site Request Forgery, 跨站域請求偽造)
CSRF 背景與介紹
CSRF(Cross Site Request Forgery, 跨站域請求偽造)是一種網絡的攻擊方式,它在 2007 年曾被列為互聯網 20 大安全隱患之一。其他安全隱患,比如 SQL 腳本注入,跨站域腳本攻擊等在近年來已經逐漸為眾人熟知,很多網站也都針對他們進行了防御。然而,對于大多數人來說,CSRF 卻依然是一個陌生的概念。即便是大名鼎鼎的 Gmail, 在 2007 年底也存在著 CSRF 漏洞,從而被黑客攻擊而使 Gmail 的用戶造成巨大的損失。
CSRF 攻擊實例
CSRF 攻擊可以在受害者毫不知情的情況下以受害者名義偽造請求發送給受攻擊站點,從而在并未授權的情況下執行在權限保護之下的操作。比如說,受害者 Bob 在銀行有一筆存款,通過對銀行的網站發送請求 http://bank.example/withdraw?account=bob&amount=1000000&for=bob2 可以使 Bob 把 1000000 的存款轉到 bob2 的賬號下。通常情況下,該請求發送到網站后,服務器會先驗證該請求是否來自一個合法的 session,并且該 session 的用戶 Bob 已經成功登陸。黑客 Mallory 自己在該銀行也有賬戶,他知道上文中的 URL 可以把錢進行轉帳操作。Mallory 可以自己發送一個請求給銀行:http://bank.example/withdraw?account=bob&amount=1000000&for=Mallory。但是這個請求來自 Mallory 而非 Bob,他不能通過安全認證,因此該請求不會起作用。這時,Mallory 想到使用 CSRF 的攻擊方式,他先自己做一個網站,在網站中放入如下代碼: src=”http://bank.example/withdraw?account=bob&amount=1000000&for=Mallory ”,并且通過廣告等誘使 Bob 來訪問他的網站。當 Bob 訪問該網站時,上述 url 就會從 Bob 的瀏覽器發向銀行,而這個請求會附帶 Bob 瀏覽器中的 cookie 一起發向銀行服務器。大多數情況下,該請求會失敗,因為他要求 Bob 的認證信息。但是,如果 Bob 當時恰巧剛訪問他的銀行后不久,他的瀏覽器與銀行網站之間的 session 尚未過期,瀏覽器的 cookie 之中含有 Bob 的認證信息。這時,悲劇發生了,這個 url 請求就會得到響應,錢將從 Bob 的賬號轉移到 Mallory 的賬號,而 Bob 當時毫不知情。等以后 Bob 發現賬戶錢少了,即使他去銀行查詢日志,他也只能發現確實有一個來自于他本人的合法請求轉移了資金,沒有任何被攻擊的痕跡。而 Mallory 則可以拿到錢后逍遙法外。
CSRF 攻擊的對象
在討論如何抵御 CSRF 之前,先要明確 CSRF 攻擊的對象,也就是要保護的對象。從以上的例子可知,CSRF 攻擊是黑客借助受害者的 cookie 騙取服務器的信任,但是黑客并不能拿到 cookie,也看不到 cookie 的內容。另外,對于服務器返回的結果,由于瀏覽器同源策略的限制,黑客也無法進行解析。因此,黑客無法從返回的結果中得到任何東西,他所能做的就是給服務器發送請求,以執行請求中所描述的命令,在服務器端直接改變數據的值,而非竊取服務器中的數據。所以,我們要保護的對象是那些可以直接產生數據改變的服務,而對于讀取數據的服務,則不需要進行 CSRF 的保護。比如銀行系統中轉賬的請求會直接改變賬戶的金額,會遭到 CSRF 攻擊,需要保護。而查詢余額是對金額的讀取操作,不會改變數據,CSRF 攻擊無法解析服務器返回的結果,無需保護。
?
防御策略:在請求地址中添加 token 并驗證
CSRF 攻擊之所以能夠成功,是因為黑客可以完全偽造用戶的請求,該請求中所有的用戶驗證信息都是存在于 cookie 中,因此黑客可以在不知道這些驗證信息的情況下直接利用用戶自己的 cookie 來通過安全驗證。要抵御 CSRF,關鍵在于在請求中放入黑客所不能偽造的信息,并且該信息不存在于 cookie 之中??梢栽?HTTP 請求中以參數的形式加入一個隨機產生的 token,并在服務器端建立一個攔截器來驗證這個 token,如果請求中沒有 token 或者 token 內容不正確,則認為可能是 CSRF 攻擊而拒絕該請求。
token 可以在用戶登陸后產生并放于 session 之中,然后在每次請求時把 token 從 session 中拿出,與請求中的 token 進行比對,但這種方法的難點在于如何把 token 以參數的形式加入請求。對于 GET 請求,token 將附在請求地址之后,這樣 URL 就變成 http://url?csrftoken=tokenvalue。 而對于 POST 請求來說,要在 form 的最后加上 <input type=”hidden” name=”csrftoken” value=”tokenvalue”/>,這樣就把 token 以參數的形式加入請求了。但是,在一個網站中,可以接受請求的地方非常多,要對于每一個請求都加上 token 是很麻煩的,并且很容易漏掉,通常使用的方法就是在每次頁面加載時,使用 javascript 遍歷整個 dom 樹,對于 dom 中所有的 a 和 form 標簽后加入 token。這樣可以解決大部分的請求,但是對于在頁面加載之后動態生成的 html 代碼,這種方法就沒有作用,還需要程序員在編碼時手動添加 token。
Django 中使用CSRF
How to use it?
To take advantage of CSRF protection in your views, follow these steps:
The CSRF middleware is activated by default in the?MIDDLEWARE_CLASSES?setting. If you override that setting, remember that?'django.middleware.csrf.CsrfViewMiddleware'?should come before any view middleware that assume that CSRF attacks have been dealt with.
If you disabled it, which is not recommended, you can use?csrf_protect()?on particular views you want to protect (see below).
In any template that uses a POST form, use the?csrf_token?tag inside the?<form>?element if the form is for an internal URL, e.g.:
<form action="" method="post">{% csrf_token %}This should not be done for POST forms that target external URLs, since that would cause the CSRF token to be leaked, leading to a vulnerability.
In the corresponding view functions, ensure that?RequestContext?is used to render the response so that?{%csrf_token?%}?will work properly. If you’re using the?render()?function, generic views, or contrib apps, you are covered already since these all use?RequestContext.
CSRF with AJAX
While the above method can be used for AJAX POST requests, it has some inconveniences:you have to remember to pass the CSRF token in as POST data with every POST request.?For this reason, there is an alternative method: on each XMLHttpRequest, set a custom?X-CSRFToken?header to the value of the CSRF token. This is often easier, because many JavaScript frameworks provide hooks that allow headers to be set on every request.
As a first step, you must get the CSRF token itself. The recommended source for the token is the?csrftokencookie, which will be set if you’ve enabled CSRF protection for your views as outlined above.
?
Acquiring the token is straightforward:
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | // using jQuery function?getCookie(name) { ????var?cookieValue =?null; ????if?(document.cookie && document.cookie !=?'') { ????????var?cookies = document.cookie.split(';'); ????????for?(var?i = 0; i < cookies.length; i++) { ????????????var?cookie = jQuery.trim(cookies[i]); ????????????// Does this cookie string begin with the name we want? ????????????if?(cookie.substring(0, name.length + 1) == (name +?'=')) { ????????????????cookieValue = decodeURIComponent(cookie.substring(name.length + 1)); ????????????????break; ????????????} ????????} ????} ????return?cookieValue; } var?csrftoken = getCookie('csrftoken'); |
The above code could be simplified by using the?JavaScript Cookie library?to replace?getCookie:
| 1 | var?csrftoken = Cookies.get('csrftoken'); |
Finally, you’ll have to actually set the header on your AJAX request, while protecting the CSRF token from being sent to other domains using?settings.crossDomain?in jQuery 1.5.1 and newer:
| 1 2 3 4 5 6 7 8 9 10 11 | function?csrfSafeMethod(method) { ????// these HTTP methods do not require CSRF protection ????return?(/^(GET|HEAD|OPTIONS|TRACE)$/.test(method)); } $.ajaxSetup({ ????beforeSend:?function(xhr, settings) { ????????if?(!csrfSafeMethod(settings.type) && !this.crossDomain) { ????????????xhr.setRequestHeader("X-CSRFToken", csrftoken); ????????} ????} }); |
?
中間件middleware
為了能使用戶對django的request/response請求處理過程及請求數據包進行全局的修改
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','bbs.middleware.SimpleMiddleware', ]
如果要禁用或啟用某個中間件,只需要在settings.py里修改MIDDLEWARE配置
middleware.py
from django.shortcuts import HttpResponseclass SimpleMiddleware(object):
def __init__(self, get_response):
self.get_response = get_response
# One-time configuration and initialization.
def __call__(self, request):
# Code to be executed for each request before
# the view (and later middleware) are called.
response = self.get_response(request)
print("middleware",response)
# Code to be executed for each request/response after
# the view is called.
return response
#views.py執行之前
def process_view(self,request,view_func,view_args,view_kwargs):
print('process view',self,request,view_func,view_args,view_kwargs)
print(request.META.items())
if request.META.get('REMOTE_ADDR') == '127.0.0.1':
return HttpResponse('fobidden')
必須返回 None 或者 HttpResponse 對象
返回None代表django繼續處理該request請求,并執行其他middleware中的process_view
返回HttpResponse django會直接return 不會執行views函數與其他middleware中的process_view
#views.py有異常會觸發
def process_exception(self,request,exception):
print('proces excetion',request,exception)
return HttpResponse('error happend...%s'%exception)
#在views.py執行結束返回之前執行
def process_template_response(self,request,response):
print('process_template_response',request,response)
?
轉載于:https://www.cnblogs.com/hongpeng0209/p/6590886.html
總結
- 上一篇: 理解oauth2.0【转载】
- 下一篇: JFreeChart应用实例-折线图