day72-bbs-2

數據庫表建立及同步

"""
因爲django自帶的sqlite數據庫對日期不敏感,因此咱們換成MySQL
"""
from django.db import models

# Create your models here.
"""
先寫普通字段
以後再寫外鍵字段
"""
from django.contrib.auth.models import AbstractUser


class UserInfo(AbstractUser):
    phone = models.BigIntegerField(verbose_name='手機號',null=True)
    # 頭像
    avatar = models.FileField(upload_to='avatar/',default='avatar/default.png',verbose_name='用戶頭像')
    """
    給avatar字段傳文件對象 該文件會自動存儲到avatar文件下 而後avatar字段只保存文件路徑avatar/default.png
    """
    create_time = models.DateField(auto_now_add=True)

    blog = models.OneToOneField(to='Blog',null=True)


class Blog(models.Model):
    site_name = models.CharField(verbose_name='站點名稱',max_length=32)
    site_title = models.CharField(verbose_name='站點標題',max_length=32)
    # 簡單模擬 帶你認識樣式內部原理的操做
    site_theme = models.CharField(verbose_name='站點樣式',max_length=64)  # 存css/js的文件路徑


class Category(models.Model):
    name = models.CharField(verbose_name='文章分類',max_length=32)
    blog = models.ForeignKey(to='Blog',null=True)


class Tag(models.Model):
    name = models.CharField(verbose_name='文章標籤',max_length=32)
    blog = models.ForeignKey(to='Blog', null=True)


class Article(models.Model):
    title = models.CharField(verbose_name='文章標題',max_length=64)
    desc = models.CharField(verbose_name='文章簡介',max_length=255)
    # 文章內容有不少 通常狀況下都是使用TextField
    content = models.TextField(verbose_name='文章內容')
    create_time = models.DateField(auto_now_add=True)

    # 數據庫字段設計優化
    up_num = models.BigIntegerField(verbose_name='點贊數',default=0)
    down_num = models.BigIntegerField(verbose_name='點踩數',default=0)
    comment_num = models.BigIntegerField(verbose_name='評論數',default=0)

    # 外鍵字段
    blog = models.ForeignKey(to='Blog', null=True)
    category = models.ForeignKey(to='Category',null=True)
    tags = models.ManyToManyField(to='Tag',
                                  through='Article2Tag',
                                  through_fields=('article','tag')
                                  )


class Article2Tag(models.Model):
    article = models.ForeignKey(to='Article')
    tag = models.ForeignKey(to='Tag')


class UpAndDown(models.Model):
    user = models.ForeignKey(to='UserInfo')
    article = models.ForeignKey(to='Article')
    is_up = models.BooleanField()  # 傳佈爾值 存0/1


class Comment(models.Model):
    user = models.ForeignKey(to='UserInfo')
    article = models.ForeignKey(to='Article')
    content = models.CharField(verbose_name='評論內容',max_length=255)
    comment_time = models.DateTimeField(verbose_name='評論時間',auto_now_add=True)
    # 自關聯
    parent = models.ForeignKey(to='self',null=True)  # 有些評論就是根評論

註冊功能

"""
咱們以前是直接在views.py中書寫的forms組件代碼
可是爲了接耦合 應該將全部的forms組件代碼單獨寫到一個地方

若是你的項目至始至終只用到一個forms組件那麼你能夠直接建一個py文件書寫便可
    myforms.py
可是若是你的項目須要使用多個forms組件,那麼你能夠建立一個文件夾在文件夾內根據
forms組件功能的不一樣建立不一樣的py文件
    myforms文件夾
        regform.py
        loginform.py
        userform.py
        orderform.py
        ...
"""
def register(request):
    form_obj = MyRegForm()
    if request.method == 'POST':
        back_dic = {"code": 1000, 'msg': ''}
        # 校驗數據是否合法
        form_obj = MyRegForm(request.POST)
        # 判斷數據是否合法
        if form_obj.is_valid():
            # print(form_obj.cleaned_data)  # {'username': 'jason', 'password': '123', 'confirm_password': '123', 'email': '123@qq.com'}
            clean_data = form_obj.cleaned_data  # 將校驗經過的數據字典賦值給一個變量
            # 將字典裏面的confirm_password鍵值對刪除
            clean_data.pop('confirm_password')  # {'username': 'jason', 'password': '123', 'email': '123@qq.com'}
            # 用戶頭像
            file_obj = request.FILES.get('avatar')
            """針對用戶頭像必定要判斷是否傳值 不能直接添加到字典裏面去"""
            if file_obj:
                clean_data['avatar'] = file_obj
            # 直接操做數據庫保存數據
            models.UserInfo.objects.create_user(**clean_data)
            back_dic['url'] = '/login/'
        else:
            back_dic['code'] = 2000
            back_dic['msg'] = form_obj.errors
        return JsonResponse(back_dic)
    return render(request,'register.html',locals())

  
<script>
    $("#myfile").change(function () {
        // 文件閱讀器對象
        // 1 先生成一個文件閱讀器對象
        let myFileReaderObj = new FileReader();
        // 2 獲取用戶上傳的頭像文件
        let fileObj = $(this)[0].files[0];
        // 3 將文件對象交給閱讀器對象讀取
        myFileReaderObj.readAsDataURL(fileObj)  // 異步操做  IO操做
        // 4 利用文件閱讀器將文件展現到前端頁面  修改src屬性
        // 等待文件閱讀器加載完畢以後再執行
        myFileReaderObj.onload = function(){
             $('#myimg').attr('src',myFileReaderObj.result)
        }
    })

    $('#id_commit').click(function () {
        // 發送ajax請求     咱們發送的數據中即包含普通的鍵值也包含文件
        let formDataObj = new FormData();
        // 1.添加普通的鍵值對
        {#console.log($('#myform').serializeArray())  // [{},{},{},{},{}]  只包含普通鍵值對#}
        $.each($('#myform').serializeArray(),function (index,obj) {
            {#console.log(index,obj)#}  // obj = {}
            formDataObj.append(obj.name,obj.value)
        });
        // 2.添加文件數據
        formDataObj.append('avatar',$('#myfile')[0].files[0]);

        // 3.發送ajax請求
        $.ajax({
            url:"",
            type:'post',
            data:formDataObj,

            // 須要指定兩個關鍵性的參數
            contentType:false,
            processData:false,

            success:function (args) {
                if (args.code==1000){
                    // 跳轉到登錄頁面
                    window.location.href = args.url
                }else{
                    // 如何將對應的錯誤提示展現到對應的input框下面
                    // forms組件渲染的標籤的id值都是 id_字段名
                    $.each(args.msg,function (index,obj) {
                        {#console.log(index,obj)  //  username        ["用戶名不能爲空"]#}
                        let targetId = '#id_' + index;
                        $(targetId).next().text(obj[0]).parent().addClass('has-error')
                    })
                }
            }
        })
    })
    // 給全部的input框綁定獲取焦點事件
    $('input').focus(function () {
        // 將input下面的span標籤和input外面的div標籤修改內容及屬性
        $(this).next().text('').parent().removeClass('has-error')
    })
</script>
              
# 擴展
"""
通常狀況下咱們在存儲用戶文件的時候爲了不文件名衝突的狀況
會本身給文件名加一個前綴    
    uuid
    隨機字符串
    ...
"""

登錄功能

"""
img標籤的src屬性
    1.圖片路徑
    2.url
    3.圖片的二進制數據

咱們的計算機上面致全部可以輸出各式各樣的字體樣式
內部其實對應的是一個個.ttf結尾的文件

http://www.zhaozi.cn/ai/2019/fontlist.php?ph=1&classid=32&softsq=%E5%85%8D%E8%B4%B9%E5%95%86%E7%94%A8
"""


"""
圖片相關的模塊
    pip3 install pillow
"""
from PIL import Image,ImageDraw,ImageFont
"""
Image:生成圖片
ImageDraw:可以在圖片上亂塗亂畫
ImageFont:控制字體樣式
"""
from io import BytesIO,StringIO
"""
內存管理器模塊
BytesIO:臨時幫你存儲數據 返回的時候數據是二進制
StringIO:臨時幫你存儲數據 返回的時候數據是字符串
"""
import random
def get_random():
    return random.randint(0,255),random.randint(0,255),random.randint(0,255)
def get_code(request):
    # 推導步驟1:直接獲取後端現成的圖片二進制數據發送給前端
    # with open(r'static/img/111.jpg','rb') as f:
    #     data = f.read()
    # return HttpResponse(data)

    # 推導步驟2:利用pillow模塊動態產生圖片
    # img_obj = Image.new('RGB',(430,35),'green')
    # img_obj = Image.new('RGB',(430,35),get_random())
    # # 先將圖片對象保存起來
    # with open('xxx.png','wb') as f:
    #     img_obj.save(f,'png')
    # # 再將圖片對象讀取出來
    # with open('xxx.png','rb') as f:
    #     data = f.read()
    # return HttpResponse(data)

    # 推導步驟3:文件存儲繁瑣IO操做效率低  藉助於內存管理器模塊
    # img_obj = Image.new('RGB', (430, 35), get_random())
    # io_obj = BytesIO()  # 生成一個內存管理器對象  你能夠當作是文件句柄
    # img_obj.save(io_obj,'png')
    # return HttpResponse(io_obj.getvalue())  # 從內存管理器中讀取二進制的圖片數據返回給前端


    # 最終步驟4:寫圖片驗證碼
    img_obj = Image.new('RGB', (430, 35), get_random())
    img_draw = ImageDraw.Draw(img_obj)  # 產生一個畫筆對象
    img_font = ImageFont.truetype('static/font/222.ttf',30)  # 字體樣式 大小

    # 隨機驗證碼  五位數的隨機驗證碼  數字 小寫字母 大寫字母
    code = ''
    for i in range(5):
        random_upper = chr(random.randint(65,90))
        random_lower = chr(random.randint(97,122))
        random_int = str(random.randint(0,9))
        # 從上面三個裏面隨機選擇一個
        tmp = random.choice([random_lower,random_upper,random_int])
        # 將產生的隨機字符串寫入到圖片上
        """
        爲何一個個寫而不是生成好了以後再寫
        由於一個個寫可以控制每一個字體的間隙 而生成好以後再寫的話
        間隙就無法控制了
        """
        img_draw.text((i*60+60,-2),tmp,get_random(),img_font)
        # 拼接隨機字符串
        code += tmp
    print(code)
    # 隨機驗證碼在登錄的視圖函數裏面須要用到 要比對 因此要找地方存起來而且其餘視圖函數也能拿到
    request.session['code'] = code
    io_obj = BytesIO()
    img_obj.save(io_obj,'png')
    return HttpResponse(io_obj.getvalue())
  
  
  
  
  
  <script>
    $("#id_img").click(function () {
        // 1 先獲取標籤以前的src
        let oldVal = $(this).attr('src');
        $(this).attr('src',oldVal += '?')
    })
</script>
本站公眾號
   歡迎關注本站公眾號,獲取更多信息