寫蠻好的一篇博客:https://www.cnblogs.com/Kingfan1993/p/9936541.html
1.表內自關聯是指表內數據相關聯的對象和表是相同字段,這樣咱們就直接用表內關聯將外鍵關聯設置成自身表的字段html
2.例如,對於微博評論,每條評論均可能有子評論,但每條評論的字段內容應該都是相同的,而且每條評論都只有一個父評論,這就知足了一對多的情形,父評論id爲關聯字段,能夠對應多個子評論python
3.外鍵關聯是在子評論中,有關聯字段的是子評論,子評論查父評論是正向,父評論查子評論是反向web
4.一對多的自關聯能夠應用在BBS論壇的留言功能中數據庫
# models.py中 # 文章表 """ id title content 1 'hello' 'nihao....' 2 'world' 'shijie....' """ class Article(models.Model): title = models.CharField(max_length=32) content = models.CharField(max_length=500) # 評論表 """ id article_id content reply_id(自關聯,做爲外鍵關聯自身表的主鍵id) uid 1 1 'cool' 0 (不是任何評論的回覆) 2 1 'hehe' 0 3 1 'wtf' 1 (表示的是這條評論是回覆id爲1的評論) 4 1 'how' 0 5 2 'haha' 0 6 1 'wow' 1 (也是回覆的第一條評論) 7 2 'Um' 5 (回覆第五條評論) 8 1 'aha' 3 (回覆第三條評論) """ class Comment(models.Model): article = models.ForeignKey("Article") content = models.CharField(max_length=255) reply = models.ForeignKey("Comment", default=0)
1.例如,創建一張相親對象表,裏面有男有女,咱們就能夠經過自關聯來創建多對多的關係django
2.經過ManyToManyField將外鍵關聯自身的主鍵idcookie
# models.py中 class User(models.Model): name = models.CharField(max_length=32) gender_list = [ (1, "男"), (2, "女"), ] gender = models.IntegerField(choices=gender_list,default=1) r = models.ManyToManyField("User")
3.經過python3 manage.py makemigrations
和python3 manage.py migrate
提交建表模型以後,會生成兩個表,一個是主表,另外一個是從表session
app_user表 和 app_user_r表
4.從表中的的兩個字段,一個是 from_主表名_id,一個是 to_主表名_idapp
5.當咱們經過 from_主表名_id 相關聯的對象查與 to_主表名_id相關聯的對象時,能夠直接經過 '主表對象.關係表(從表)' 查詢函數
# views.py中 # 查詢和jojo的女生 res = models.User.objects.filter(name='jojo', gender=1).first() #print(res) # object objs = res.m.all() for obj in objs: print(obj.name) ''' 對應的SQL語句: 1. select * from app01_user_m where from_user_id = 1; 獲得的結果就是對應到app_user_r表中的數據時:to_user_id=[3,4] 所對應的對象 2. select * from app01_user where id in (3,4); '''
6.當咱們 經過 to_主表名_id相關聯的對象查 from_主表名_id 相關聯的對象時,則須要經過 '主表對象.關係表_set' 進行查詢ui
# views.py中 # 查詢和 fanbingbing 約會的男生 res = models.User.objects.filter(name='fanbingbing', gender=2).first() objs = res.user_set.all() for obj in objs: print(obj.name) ''' 對應的SQL語句: 1. select * from app01_user_m where to_user_id = 3; 獲得的結果就是對應到app_user_r表中的數據時:from_user_id=[1,2] 所對應的對象 2. select * from app01_user where id in (1,2); '''
1.執行數據庫遷移的那兩條命令時,即便咱們沒有建表,django是否是也會建立好多張表?咱們建立以後去看一下里面的一個叫auth_user表,既然是表,那確定應該有對應的操做改表的方法
2.auth_user表的記錄的添加:建立超級用戶,不能夠手動插入,由於密碼是加密的,手動添加的明文密碼沒有意義
3.咱們能夠在pycharm中使用導航欄中的Tools裏的run manage.py Task 中輸入createsuperuser
# views.py 中 # 就可使用auth認證了,作一個簡單的登錄 from django.contrib import auth def test(request): if request.method == "GET": return render(request,"test.html") else: name = request.POST.get("user") psw = request.POST.get("psw") myuser = auth.authenticate(request,username=name,password=psw) # 若是auth_user表中有這條記錄,則返回一個user對象(通常就是用戶名) if myuser: auth.login(request,myuser) # 會產生一個user對象,能夠在任何視圖函數中調用 """ 給當前成功登錄的用戶保存登錄狀態,以前是經過cookie或者session,如今經過auth; request.session["name"] = name等價於:auth.login(request,myuser) """ return HttpResponse("success") else: return redirect("/test/") # 在其餘視圖函數中演示 def other(request): print(request.user) print(request.user.is_authenticated) return HttpResponse("ok")
# 總結: # 1.只要登錄成功執行了auth.login(request,user) # 以後在其餘任意的視圖函數中均可以經過request.user獲取當前登錄用戶對象 # 2.當沒有執行auth.login,request.user打印出來的是匿名用戶。將session表數據刪除便可演示該效果 # 3.如何判斷request.user用戶是否經過auth.login登錄呢?request.user.is_authenticated,打印:print(request.user.is_authenticated) # 爲什麼執行auth.login以後,其餘視圖函數中就能夠經過request.user拿到當前登錄對象呢? # django的中間件中有沒有一個叫 'django.contrib.auth.middleware.AuthenticationMiddleware'的中間件,它幹了件什麼事,能不能推導一下? # 在web端取出session去django_session表裏面查相應的數據
4.註銷
auth.logout(request) # 等價於刪除session數據request.session.flush()
# 裝飾器校驗是否登錄及跳轉 from django.contrib.auth.decorators import login_required @login_required(login_url='/login/',redirect_field_name='old') # 沒登錄會跳轉到login頁面,而且後面會拼接上你上一次想訪問的頁面路徑/login/?old=/my_view/,能夠經過redirect_field_name參數修改next鍵名(若是不寫這個參數,則爲127.0.0.1:8090/login/?old=/my_view/,再無啥用了) def my_view(request): return HttpResponse("ok")
若是我全部的視圖函數都須要裝飾並跳轉到login頁面,那麼會很繁瑣,咱們能夠在項目下的settings.py文件中進行配置
# settings.py # 能夠在配置文件中指定auth校驗登錄不合法統一跳轉到某個路徑 LOGIN_URL = '/login/' # 既能夠全局配置,也能夠局部配置
1.咱們除了經過命令行輸入,還能夠經過auth提供的其餘方法,對auth_user表進行數據的添加
# app的views.py文件中 from django.contrib.auth.models import User def register(request): if request.method == "GET": return render(request, "register.html") else: user_name = request.POST.get("username") psw = request.POST.get("psw") # User.objects.create() # 不能用這個,由於密碼是明文 User.objects.create_user(username=user_name,password=psw) # 建立普通用戶 # User.objects.create_superuser(username=user_name,password=psw,email=233@qq.com) # 建立超級用戶
def modify(request): if request.method=='GET': return render(request, 'modify.html') else: oldpsw = request.POST.get('oldpsw') newpsw = request.POST.get('newpsw') res = request.user.check_password(oldpsw) # 獲取密碼 print(res) if res: request.user.set_password(newpsw) request.user.save() return HttpResponse('ok') else: return render(request, 'modify.html')
1.擴張auth_user表
2.一對一關聯(不推薦)
from django.contrib.auth.model s import User class UserDetail(models.Models): phone_number = models.CharField(max_length=11) user = models.OnoToOneField(to=User)
3.面向對象的繼承
# settings.py中 """ 1.指定我再也不使用默認的auth_user表而是使用我本身建立的Userinfo表 2.自定義認證系統默認使用的數據表以後,咱們就能夠像使用默認的auth_user表那樣使用咱們的UserInfo表了 3.庫裏面也沒有auth_user表了,原來auth表的操做方法,如今所有用自定義的表都可實現 """ # AUTH_USER_MODEL = "app名.models裏面對應的模型表名" AUTH_USER_MODEL = "app01.User"
# models.py中 from django.contrib.auth.models import User,AbstractUser # 繼承了auth中的user表 class UserInfo(AbstractUser): phone_number = models.CharField(max_length=32)
1.auth登陸 obj = auth.authenticate(username, password) if obj: auth.login(request, obj) 2.業務邏輯函數驗證: - request.user.is_authenticated() - from django.contrib.auth.decorators import login_required @login_required() 3.auth註冊: 本質就是向auth_user表添加數據 - createsuperuser - models.User.objects.create_user() - models.User.objects.create_superuser() 4.auth的密碼更該: auth.checkpassword() : 驗證原來的密碼是否正確 auth.setpassword() : 設置新的密碼 auth.save() 5.註銷(登出) auth.logout(request) 本質上就是刪除django_session中所對應的的記錄 6.auth_user表的擴展: - onetoonefield - 繼承子 AbstractUser 類