python 博客開發之散亂筆記

博客開發之旅:javascript

# 回滾,數據存儲失敗時,還原修改操做
from django.db import transaction
    with transaction.atomic():
        do...
...

# ==========自定義form表單驗證----------====
# 自定義驗證規則
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(value):
        raise ValidationError('手機號碼格式錯誤')
# 使用自定義驗證規則
    phone = fields.CharField(validators=[mobile_validate, ],
                            error_messages={'required': '手機不能爲空'},
                            widget=widgets.TextInput(attrs={'class': "form-control",
                                                          'placeholder': u'手機號碼'}))
 
# 多選        
course_id = fields.MultipleChoiceField(
        choices=models.Course.objects.all().values_list('id','title'),
        widget=widgets.SelectMultiple(attrs={'class':'form-control'})
    )
        
View Code

 

#+============+++++++++++==擴展Django自帶的用戶認證表=========+++++++++++++===css

from django.contrib.auth.models import AbstractUser

class UserInfo(AbstractUser):
    """
    用戶信息表
    """
    nid = models.AutoField(primary_key=True)
    phone = models.CharField(max_length=11, null=True, unique=True)
    avatar = models.FileField(upload_to="avatars/", default="avatars/default.png", verbose_name="頭像")
    create_time = models.DateTimeField(auto_now_add=True)

    blog = models.OneToOneField(to="Blog", to_field="nid", null=True,on_delete=models.CASCADE)

    def __str__(self):
        return self.username
        
# 在settings中告訴Django項目用哪張表作認證
AUTH_USER_MODEL = 'app01.UserInfo'

from django.contrib import auth

user = authenticate(username='theuser',password='thepassword')
# 即驗證用戶名以及密碼是否正確,通常須要username 、password兩個關鍵字參數。
# 若是認證成功(用戶名和密碼正確有效),便會返回一個 User 對象。


user = authenticate(username=username, password=password)
if user is not None:
    login(request, user)
# 該函數接受一個HttpRequest對象,以及一個通過認證的User對象。
# 該函數實現一個用戶登陸的功能。它本質上會在後端爲該用戶生成相關session數據。


from django.contrib.auth import logout
def logout_view(request):
    logout(request)
# 該函數接受一個HttpRequest對象,無返回值。
# 當調用該函數時,當前請求的session信息會所有清除。該用戶即便沒有登陸,使用該函數也不會報錯。


if not request.user.is_authenticated():
    pass
# is_authenticated()    
# 用來判斷當前請求是否經過了認證。


# auth 給咱們提供的一個裝飾器工具,用來快捷的給某個視圖添加登陸校驗。
from django.contrib.auth.decorators import login_required
@login_required
def my_view(request):
    pass
# 若用戶沒有登陸,則會跳轉到django默認的 登陸URL '/accounts/login/ ' 並傳遞當前訪問url的絕對路徑
 (登錄成功後,會重定向到該路徑)。LOGIN_URL = '/login/'  # 這裏配置成你項目登陸頁面的路由


# create_user()
# auth 提供的一個建立新用戶的方法,須要提供必要參數(username、password)等。
from django.contrib.auth.models import User
user = User.objects.create_user(username='用戶名',password='密碼',email='郵箱',...)


# create_superuser()
# auth 提供的一個建立新的超級用戶的方法,須要提供必要參數(username、password)等。
from django.contrib.auth.models import User
user = User.objects.create_superuser(username='用戶名',password='密碼',email='郵箱',...)


# check_password(password)
# auth 提供的一個檢查密碼是否正確的方法,須要提供當前請求用戶的密碼。密碼正確返回True,不然返回False。
ok = user.check_password('密碼')


# set_password(password)
# auth 提供的一個修改密碼的方法,接收 要設置的新密碼 做爲參數。
注意:設置完必定要調用用戶對象的save方法!!!
user.set_password(password='')
user.save()


    
    
    
極驗: https://docs.geetest.com/install/deploy/server/python
pip install geetest
View Code

 

# +++++++++++++++++++++++文件上傳++++++++++++++++++++html

views
from django.views.decorators.csrf import csrf_exempt

@csrf_exempt
def upload(request):
    if request.method == 'POST':
        file_obj = request.FILES.get('file')
        with open('upload/'+file_obj.name,'wb')as f:
            for i in file_obj.chunks():
                f.write(i)
    return render(request,'upload.html')

html
<form action="/upload/" method="post" enctype="multipart/form-data">
    <input type="file" name="file"/>
    <input type="submit" value="提交"/>
</form>
View Code

 

#++++++++++++==文檔加載完以後才執行 JS 的三種方式===++++++++++++前端

<script src="/static/jquery-3.3.1.js"></script>
<script>
    window.onload = function () {
        var a = document.getElementById('username');
        alert(a);
    };
    $(document).ready(function () {
        var a = document.getElementById('default_avatar');
        alert(a);
    });
    $(function () {
        var a = document.getElementById('default_avatar');
        alert(a);
    })
</script>
View Code

 

#+++++++++++++++++====頭像預覽====++++++++++++++++java

<div class="form-group">
    <label class="col-sm-4 control-label">選擇頭像</label>
    <div class="col-sm-8">
        <label for="id_avatar">
            <img id="default_avatar" src="/static/img/hmbb.png" alt="默認頭像"/>
        </label>
        <input type="file" id="id_avatar" name="avatar" style="display: none"/>
        # <input accept="image/*" type="file" id="avatar" name="avatar" style="display: none"/>
    </div>
</div>
<script src="/static/jquery-3.3.1.js"></script>
<script>
    $('#id_avatar').change(function () {
        // 建立一個讀取文件的對象
        var fileReader = new FileReader();
        // 讀取到當前選中的文件
        // console.log(this.files[0]);
        fileReader.readAsDataURL(this.files[0]);
        fileReader.onload = function () {
            $('#default_avatar').attr('src',fileReader.result);
        }
    })
</script>
View Code

 

#-------------Form表單驗證在渲染成HTML標籤時顯示錯誤信息----------------python

<div class="form-group">
    <label for="{{ obj.username.id_for_label }}" class="col-sm-4 control-label">
        {{ obj.username.label }}
    </label>
    <div class="col-sm-8">
        {{ obj.username }}{{ obj.errors.username.0 }}            
    </div>
</div>
{% for row in obj %}
    <div class="form-group">
        <label for="{{ row.id_for_label }}" class="col-sm-4 control-label">
            {{ row.label }}
        </label>
        <div class="col-sm-8">
            {{ row }}{{ row.errors.0 }}
        </div>
    </div>
{% endfor %}
View Code

 

# +++++++++++++++++++全局鉤子驗證密碼一致性 以及實時跟新數據+++++++++++++++++++++mysql

class RegForm(Form):
    ...
    re_password = fields.CharField(
        min_length=6,
        label="確認密碼",
        widget=widgets.PasswordInput(
            attrs={"class": "form-control"},
            render_value=True,
        ),
        error_messages={
            "min_length": "確認密碼至少要6位!",
            "required": "確認密碼不能爲空",
        }
    )
    
    user_type = fields.ChoiceField(
        choices=models.UserType.objects.values_list('id','caption')
    )
    
    
    # 重寫全局的鉤子函數,對確認密碼作校驗
    def clean(self):
        password = self.cleaned_data.get('password')
        re_password = self.cleaned_data.get('re_password')

        if re_password and password != re_password:
            self.add_error('re_password',ValidationError('兩次密碼不一致!'))

        else:
            return self.cleaned_data    # 注意返回
            
    # 在使用選擇標籤時,須要注意choices的選項能夠從數據庫中獲取,可是因爲是靜態字段
    # ***獲取的值沒法實時更新***,那麼須要自定義構造方法從而達到此目的。
    def __init__(self, *args, **kwargs):
        super(RegForm,self).__init__(*args, **kwargs)
        self.fields['user_type'].choices = models.UserType.objects.values_list('id','caption')
View Code

 

# ++++==+++__++===-+_+_===# 本身生成驗證碼圖片 # ++++==+++__++===-+_+_===#jquery

from PIL import Image, ImageDraw, ImageFont

img_obj = Image.new('RGB',(220,40),random_color())    # 圖片對象
draw_obj = ImageDraw.Draw(img_obj)                    # 畫筆對象
font_obj = ImageFont.truetype('static/fonts/kumo.ttf', 40)    # 字體對象
char_list = random_char()                            # 驗證碼字符串
request.session["code_img"] = "".join(char_list)    # 將字符串保存到session會話
for i in range(len(char_list)):                        # 將字符畫到圖片上
    draw_obj.text((10+50*i,0),char_list[i],fill=random_color(),font=font_obj)
    
# draw_obj.line((begin,end),fill=random_color(),width=random.randint(1,4))    # 畫線條
# draw_obj.point(width, height, fill=random_color())                        # 畫點 
draw_obj.arc((x, y, x+z, y+z), 0, 360, fill=random_color())                    # 畫弧線 圓

from io import BytesIO
io_obj = BytesIO()            # 將生成的圖片數據保存在io對象中
img_obj.save(io_obj, "png")    # 從io對象裏面取上一步保存的數據
data = io_obj.getvalue()
return HttpResponse(data)

++++
<img id="get_code" src="/get_code_img/" alt="驗證碼加載失敗">
$('#get_code').click(function () {
    // 點擊圖片刷新驗證碼
    $(this)[0].src += "?";
});
++++
View Code

 

#+==================# 重寫局部鉤子函數,對用戶名作校驗和ajax實時檢驗===========================+git

class RegForm(Form):
    username = fields.CharField(
            max_length=16,
            label="用戶名",
            error_messages={
                "max_length": "用戶名最長16位",
                "required": "用戶名不能爲空",
            },
            widget=widgets.TextInput(
                attrs={"class": "form-control"},
            )
        )

    def clean_username(self):
        username = self.cleaned_data.get('username')
        is_exist = models.UserInfo.objects.filter(username=username)
        if is_exist:
            self.add_error('username',ValidationError('用戶名已存在'))
        else:    # 重寫的是局部鉤子,因此返回檢驗的字段
            return username
            

# username輸入框失去焦點,使用ajax檢驗用戶名是否存在
@csrf_exempt
def check_username_exist(request):
    ret = {'status':False,'msg':None}
    is_exist = models.UserInfo.objects.filter(username=request.POST.get('username'))
    if is_exist:
        ret['status']=True
        ret['msg']='用戶名已存在'
        return HttpResponse(json.dumps(ret))
    return HttpResponse(json.dumps(ret))

# <form autocomplete="off">    #取消瀏覽器自動匹配
# $('#id_username').on('input',function () {    # 內容變更就提交
$('#id_username').blur(function () {
    $.ajax({
        url: '/check_username_exist/',
        data: {'username': $(this).val()},
        method: 'post',
        dataType: 'json',
        success: function (data) {
            if (data.status) {
                $('#id_username').next().text(data.msg);
                console.log(data.msg);
            }
        }
    })
})



# Django admin 使用
# 在app/admin.py文件中註冊表
from django.contrib import admin
from app01 import models
admin.site.register(models.UserInfo)
admin.site.register(models.Blog)
# 在settings配置顯示中文
LANGUAGE_CODE = 'zh-hans'
class UserInfo():
    ...
    class Meta:
        verbose_name = '用戶' # 給表起名
        verbose_name_plural = verbose_name  # 顯示覆數也用'用戶'來顯示
在admin後臺中顯示中文表名
View Code

 

#=========== # Django用戶上傳的都叫media文件==================
# setting.py
# media配置,用戶上傳的文件都默認放在這個文件夾下
MEDIA_ROOT = os.path.join(BASE_DIR,"media")
MEDIA_URL = "/media/"
# urls.py
from django.views.static import serve
from django.conf import settings
re_path('media/(?P<path>.*)$',serve,{"document_root":settings.MEDIA_ROOT}),

# 作了media配置,用戶上傳文件都會在media/xx中。
View Code
# _+_+_+_+_+_+_+_+_+_+_+導入Django,單獨測試某個功能_+_+_+_+_+_+_+_+_+_+_+_+_+
test.py
import os
if __name__ == '__main__':
    os.environ.setdefault('DJANGO_SETTINGS_MODULE', '博客.settings')
    import django
    django.setup()
    from app01 import models
    obj = models.UserInfo.objects.all()
    print(obj.query)
View Code

 

# -=======----博客文章-=======----ajax

<div class="article">
    <h4><a href="">{{ article.title }}</a></h4>
    <div class="media">
        <div class="media-left">
            <a href="#">
                <img id="user_avatar" class="media-object" src="/media/{{ article.user.avatar }}"alt="...">
            </a>
        </div>
        <div class="media-body">
            <p>{{ article.desc }}</p>
        </div>
    </div>
    <div class="article_footer">
        <span><a href="">{{ article.user.username }}</a></span>發佈於
        <span>{{ article.create_time|date:'Y-m-d H:i:s' }}</span>
        <span class="glyphicon glyphicon-comment">評論({{ article.comment_set.count }})</span>
        <span class="glyphicon glyphicon-thumbs-up">點贊({{ article.articleupdown_set.count }})</span>
    </div>
</div>


分組和聚合  https://www.cnblogs.com/liwenzhou/p/8660826.html
    1. 分組
        ORM中values或者values_list 裏面寫什麼字段,就至關於select 什麼字段
        ret = models.Employee.objects.all().values("dept", "age")
        至關於:
        SELECT `employee`.`dept`, `employee`.`age` FROM `employee` LIMIT 21; args=()
        
    2. ORM中 annotate 前面是什麼就按照什麼分組!
        from django.db.models import Avg
        ret = models.Employee.objects.values("province").annotate(a=Avg("salary")).values("province", "a")
        至關於:
        SELECT `employee`.`province`, AVG(`employee`.`salary`) AS `a` FROM `employee` GROUP BY `employee`.`province` ORDER BY NULL LIMIT 21; args=()

    3. extra  --> 在執行ORM查詢的時候執行額外的SQL語句
        # 查詢person表,判斷每一個人的工資是否大於2000
        ret = models.Person.objects.all().extra(
            select={"gt": "salary > 2000"}
        )
        至關於:
        SELECT (salary > 2000) AS `gt`, `person`.`id`, `person`.`name`, `person`.`salary`, `person`.`dept_id` FROM `person` LIMIT 21; args=()

    4. 直接執行原生的SQL語句,相似pymysql的用法
        from django.db import connection
        cursor = connection.cursor()  # 獲取光標,等待執行SQL語句
        cursor.execute("""SELECT * from person where id = %s""", [1])
        row = cursor.fetchone()
        print(row)


# =====++++++建立數據庫表,插入時間++++++=======
mysql>create table test(d date, dt datetime, t time);
mysql>insert into test(d,dt,t) values(now(),now(),now());
mysql>select date_format(dt,'%Y-%m') from test;    # 格式化,只看年月
        
        
        
View Code

 

#=++++++++++++==========+++++母板,子板,自定義templates+++====+++++++++++===========

母板
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>{{ blog.title }}</title>
    <link rel="stylesheet" href="/static/bootstrap-3.3.7-dist/css/bootstrap.min.css">
    <link rel="stylesheet" href="/static/fontawesome/css/font-awesome.min.css">
    <link rel="stylesheet" href="/static/commons.css"/>
    <link rel="stylesheet" href="/static/theme/{{ blog.theme }}"/>
</head>
<body>
<div class="blog">
    <div class="header">
        <div>{{ blog.title }}</div>
    </div>
    <div class="container">
        <div class="col-md-3">
            {% load my_tags %}
                                                # 在這使用自定義templates
            {% get_left_menu username %}
        </div>
        <div class="col-md-8">
            {% block page-main %}

            {% endblock %}
        </div>
    </div>
</div>
<script src="/static/jquery-3.3.1.js"></script>
<script src="/static/bootstrap-3.3.7-dist/js/bootstrap.min.js"></script>
</body>
</html>

子板
{% extends 'base.html' %}

{% block page-main %}
    <div class="article">
        {% for article in article_list %}
            。。。。。。。
        {% endfor %}
    </div>
{% endblock %}

自定義templates
在app下新建目錄templatetags,在新建目錄下新建文件my_tags.py
from django import template
from app01 import models
from django.db.models import Count

register = template.Library()    # 固定寫法
@register.inclusion_tag("left_menu.html")
def get_left_menu(username):
    user = models.UserInfo.objects.filter(username=username).first()
    blog = user.blog
    # 查詢文章分類及對應的文章數
    category_list = models.Category.objects.filter(blog=blog)
    # 查文章標籤及對應的文章數
    tag_list = models.Tag.objects.filter(blog=blog).annotate(c=Count("article")).values("title", "c")
    # 按日期歸檔
    # archive_list = models.Article.objects.filter(user=user).extra(
    #     select={"archive_ym": "date_format(create_time,'%%Y-%%m')"}
    # ).values("archive_ym").annotate(c=Count("nid")).values("archive_ym", "c")

    return {
        "category_list" :category_list,
        "tag_list": tag_list,
    }

建立left_menu.html
<div class="panel panel-primary">
    <div class="panel-heading">文章分類</div>
    <div class="panel-body">
        {% for category in category_list %}
            <p>{{ category.title }}({{ category.article_set.all.count }})</p>
        {% endfor %}
    </div>
</div>
<div class="panel panel-primary">
    <div class="panel-heading">標籤分類</div>
    <div class="panel-body">
        {% for tag in tag_list %}
            <p>{{ tag.title }}({{ tag.c }})</p>
        {% endfor %}
    </div>
</div>
View Code

 

# ===========-----====-----====-------點贊 js-------======-----======-----=============

def dianzan_up_down(request):
    ret = {'status':False,'msg':None}
    article_id = request.POST.get('article_id')
    is_up = json.loads(request.POST.get('is_up'))
    user = request.user
    if user:
        try:
            models.ArticleUpDown.objects.create(user=user,article_id=article_id,is_up=is_up)
            models.Article.objects.filter(nid=article_id).update(up_count=F('up_count')+1)
            ret['status'] = True
            ret['is_up'] = is_up
            return HttpResponse(json.dumps(ret))
        except Exception as e:
            is_up = models.ArticleUpDown.objects.filter(user=user,article_id=article_id).first().is_up
            ret['first_action']=is_up
            return HttpResponse(json.dumps(ret))
    ret['msg'] = '請先登陸'
    return HttpResponse(json.dumps(ret))
    
<div class="dianzan_up_down">
    <div id="div_digg">
        <div class="diggit action">
            <span class="diggnum" id="digg_count">{{ article.up_count }}</span>
        </div>
        <div class="buryit action">
            <span class="burynum" id="bury_count">{{ article.down_count }}</span>
        </div>
        <div class="clear"></div>
        <div class="diggword" id="digg_tips" style="color: red;"></div>
    </div>

    {% csrf_token %}
    # 能夠將文章id渲染出來 <div class="info" article_id="{{ article.pk }}"></div>  

</div>
<script>        // 點贊
    $('#div_digg .action').click(function () {
        var is_up = $(this).hasClass('diggit');
        var crticle_id = "{{ article.pk }}";
        # var article_id = $('.info').attr('article_id');當JS保存爲靜態文件時,獲取文章id
        $.ajax({
            url: '/blog/article/up_down/',
            type: 'post',
            data: {
                'article_id': crticle_id,
                'is_up': is_up,
                'csrfmiddlewaretoken': $('[name=csrfmiddlewaretoken]').val()
            },
            dataType: 'json',
            success: function (data) {
                if (data.status) {
                    if (data.is_up) {
                        var count = $('#digg_count').text();
                        count = parseInt(count) + 1;
                        $('#digg_count').text(count);
                    } else {
                        var count = $('#bury_count').text();
                        count = parseInt(count) + 1;
                        $('#digg_count').text(count);
                    }
                } else {
                    if (data.msg) {
                        $('#digg_tips').text(data.msg);
                    } else {
                        if (data.first_action) {
                            $('#digg_tips').text('您已經推薦過啦');
                        } else {
                            $('#digg_tips').text('您已經反對過啦');
                        }
                    }
                    setTimeout(function () {
                        $("#digg_tips").html("")
                    }, 1000)
                }
            }
        })

    })
</script>


# ========= 響應ajax,數據直接使用,不用寫dataType:'json' ========= 
from django.http import JsonResponse
return JsonResponse({'',''})
View Code

 

# +++++++++++++++++++使用JS動態綁定事件+++++++++++++++++++++++

    //後面添加的元素無法綁定事件,需預加載
$(document).on('click','#reply',function () {
    $("#comment_content").focus();
    var v = "@" + $(this).attr("username") + "\n";
    $("#comment_content").val(v);
    pid = $(this).attr("comment_id")
});
View Code

 

#_+__________++++++++評論樹例子+__________+++++++++

from django.http import JsonResponse
def comment_tree(request,article_id):
    comment_list = list(models.Comment.objects.filter(article_id=article_id).values("pk","content","parent_comment_id","create_time",'user__username'))
    print(comment_list)        # 將<QuerySet [{'pk': 6,}]> 轉爲列表。若直接json.dumps(comment_list)會報錯!
    return JsonResponse(comment_list,safe=False)

# 靜態文件中(外部js文件)須要使用的值,最好在渲染的時候將值做爲屬性存到標籤中。方便取值。
$(function () {
    // 獲取評論列表
    $.ajax({
        url: '/blog/comment/' + '{{ article.pk }}/',
        // dataType:'json',
        // return HttpResponse(json.dumps(dict(enumerate(comment_list))))    
        // enumerate(comment_list,start=1)指定起始值,那麼下面的.each index就不用加值了,不過這個麻煩
        // 瞎折騰得是,以上3行 等價 return JsonResponse(comment_list,safe=False)
        success: function (data) {
            $.each(data, function (index, comment_dict) {
                index = index + 1;
                var s = '<div class="comment_item well" comment_id="' + comment_dict.pk + '">\n' +
                    '        <div class="left">\n' +
                    '            <a href="">#' + index + '樓</a>\n' +
                    '            <span>' + comment_dict.create_time + '</span>\n' +
                    '            <a href="/blog/' + comment_dict.user__username + '/">' + comment_dict.user__username + '</a>\n' +
                    '        </div>\n' +
                    '        <div class="right">\n' +
                    '            <a id="reply" comment_pk="' + comment_dict.pk + '" username="' + comment_dict.user__username + '">回覆</a>\n' +
                    '        </div>\n' +
                    '        <div class="clear_float_before"><span>' + comment_dict.content + '</span></div>\n' +
                    '    </div>';

                if (comment_dict.parent_comment_id) {
                    // 子評論    追加到父評論下
                    var pid = comment_dict.parent_comment_id;
                    $('[comment_id="' + pid + '"]').append(s);
                } else {
                    // 根評論
                    $('.comment_tree').append(s);
                }
            })
        }
    });

    pid = "";    // 有值即回覆別人的評論內容,無值評論文章
    // 子評論設置pid
    $(document).on('click', '#reply', function () {
        var v = "@" + $(this).attr("username") + "\n";
        $("#comment_content").focus().val(v);
        pid = $(this).attr("comment_pk");
    });

    // 提交評論
    $('#comment_btn').click(function () {
        var content = $('#comment_content').val();
        var article_id = $('#info').attr('article_id');

        $.ajax({
            url: '/blog/comment/',
            type: 'post',
            data: {
                'content': content, 'article_id': article_id, 'pid': pid,
                csrfmiddlewaretoken: $("[name='csrfmiddlewaretoken']").val(),
            },
            success: function (data) {
                var s = '<div class="well"><span>' + content + '</span></div>';
                // 生成tag,添加到頁面暫不刷新,清除文本框,將pid清空,避免影響提交數據。
                $('.comment_tree').append(s);
                $('#comment_content').val('');
                pid = "";
            }
        })
    })
})
View Code

 

# ===========================富文本編輯器=kindeditor===============================

<textarea name="article_content" id="article_content" cols="60" rows="20"></textarea>
<script charset="utf-8" src="/static/kindeditor/kindeditor-all.js"></script>
<script src="/static/jquery-3.3.1.js"></script>
<script>
    KindEditor.ready(function (K) {
        window.editor = K.create('#article_content', {
            width: '800px',
            uploadJson: "/upload/",            //上傳圖片什麼的須要填參數
            extraFileUploadParams: {
                "csrfmiddlewaretoken": $("[name='csrfmiddlewaretoken']").val()
            },
            filePostName: "upload_file",
            //request.FILE.get('') 文件鍵名
        });
    });
</script>

上傳圖片
def upload(request):
    if request.method == 'POST':
        file_obj = request.FILES.get('upload_file')
        path = 'media/add_article/'+file_obj.name
        with open(path,'wb')as f:
            for i in file_obj.chunks():
                f.write(i)

        res = {
            'error':0,  # 沒有出錯
            'url':path,
        }
        return HttpResponse(json.dumps(res))
    return HttpResponse('')

提交文章        # 使用beautifulSoup過濾文章中的JS代碼,防止XSS攻擊
    
def add_article(request):
    if request.method=="POST":
        title=request.POST.get('title')
        article_content=request.POST.get('article_content')
        user=request.user

        from bs4 import BeautifulSoup
        bs = BeautifulSoup(article_content,'html.parser')
        # 過濾非法字符
        for tag in bs.find_all():
            # print(tag.name)
            if tag.name in ['script','link']:
                tag.decompose()

        desc = bs.text[0:150]+'...'
        article_obj = models.Article.objects.create(user=user,title=title,desc=desc)
        models.ArticleDetail.objects.create(content=str(bs),article=article_obj)

        return redirect('/blog/%s/'%request.user.username)
    return render(request,'add_article.html')


# orm查詢,基於對象查詢(子查詢),反向查詢按表名小寫_set.all()
# 基於queryset和__查詢(join查詢)正向查詢:按字段  反向查詢:表名小寫
# select publish.email from Book 
# left join Publish on book.publish_id=publish.nid 
# where book.title="python"
# 按邏輯來,對象查詢是基於單個對象!?,join只要連上表就能拿值!。
View Code

 

# ———————————————————————————————————簡單使用admin—————————————————————————————————————

from django.utils.safestring import mark_safe
from app01 import models

class UserInfoConfig(admin.ModelAdmin):

    def deletes(self):
        return mark_safe("<a href=''>刪除</a>")

    list_display = ["username","email","create_time",'blog',deletes]
    # 在admin管理頁面,顯示出用戶表的用戶信息字段,deletes是自定義的跳轉連接
    
    list_display_links = ["email"]
    # 設置哪一個字段能夠點擊跳轉到編輯當前頁信息的頁面
    
    list_filter=["username","email","create_time",'blog']
    # 篩選功能,按字段條件篩選,指定多個字段組合篩選。

    list_editable=["username",'blog']
    # 此配置須要有list_display_links = ["email"]配置才能生效,即在當前頁編輯其餘字段信息,效果和直接在被編輯字段的編輯頁面相同

    search_fields=["username","email"]
    # 添加搜索功能,以列表中的字段過濾出的信息後進行查找

    def patch_init(self,request,queryset):
        queryset.update(price=100)
    patch_init.short_description = "批量初始化"
    actions = [patch_init,]
    # 添加一個批量操做選項。傳入執行方法名

    change_list_template="login.html"
    # 本身的後臺管理頁面。
View Code

# -------------------Xadmin----------------------

流程
    1、啓動
        在settings文件中配置上    'Xadmin.apps.XadminConfig',
        將會自動執行ready方法,查找全部app中的Xadmin模塊
            autodiscover_modules('Xadmin')
            
    2、註冊
        單例模式
        from Xadmin.service.Xadmin import site
        from app01 import models
        site.registry(models.Test)
    
    3、設計url
        爲每一個app下的model設計增刪改查url
            127.0.0.1:8008/admin/app01/book/1/change/  :改id=1的數據

        # url的路由分發
            path('test/',([re_path('\d+',func),re_path('(\d+)',([],None,None)),],None,None))

            
# url    
path('xadmin/', Xadmin.site.urls),

# Xadmin組件 -> apps.py
from django.apps import AppConfig
from django.utils.module_loading import autodiscover_modules

class XadminConfig(AppConfig):
    name = 'Xadmin'
    def ready(self):
        autodiscover_modules('Xadmin')
            
# Xadmin -> service -> Xadmin.py
from django.urls import path,re_path
from django.shortcuts import render,HttpResponse,redirect

class ModelXadmin(object):
    def __init__(self,model,site):
        self.model=model
        self.site=site

    def list_view(self,request):
        return HttpResponse('list_view')
    def add_view(self,request):
        return HttpResponse('add_view')
    def change_view(self,request,id):
        return HttpResponse('change_view')
    def delete_view(self,request,id):
        return HttpResponse('delete_view')

    def get_urls2(self):
        temp=[]
        temp.append(re_path('^$',self.list_view))
        temp.append(re_path('^add/$',self.add_view))
        temp.append(re_path('^(\d+)/change/$',self.change_view))
        temp.append(re_path('^(\d+)/delete/$',self.delete_view))
        return temp

    @property
    def urls2(self):
        # 路由,某個表的增刪改查url
        return self.get_urls2(),None,None


class XadminSite(object):
    def __init__(self,name='admin'):
        self._registry = {}

    def get_urls(self):
        temp = []
        for model,xadmin_class_obj in self._registry.items():
            app_name = model._meta.app_label
            model_name = model._meta.model_name
            temp.append(re_path('^%s/%s/'%(app_name,model_name),xadmin_class_obj.urls2))
        return temp

    @property
    def urls(self):
        # 路由,app下的某個表url
        return self.get_urls(),None,None

    def registry(self,model,xadmin_class=None,**kwargs):
        if not xadmin_class:
            xadmin_class = ModelXadmin

        self._registry[model] = xadmin_class(model,self)
site = XadminSite()


# app01 -> Xadmin.py
from Xadmin.service.Xadmin import site
from app01 import models
site.registry(models.Test)

筆記暫斷
View Code

 

# =-=-=-=-=-=-=-=-=rbac基於角色的訪問權限控制,大體流程=--==-=-=-=-=-=-=-

# rbac -> views.py
from django.shortcuts import render,redirect
from rbac.models import *

def rbac_list(request):
    '''用戶權限信息'''
    role_list = Role.objects.all()
    user = Role.objects.values('o2o_user__user_id','o2o_user__user__username')
    user_list = []
    for item in user:
        if item['o2o_user__user_id']:
            user_list.append((item['o2o_user__user_id'],item['o2o_user__user__username']))

    obj = roleForm()
    return render(request,'rbac.html',{'role_list':role_list,'user_list':user_list,'obj':obj})


from django.forms import Form,fields,widgets
class roleForm(Form):
    users = fields.ChoiceField(
        choices=O2o_User.objects.values_list('user__nid','user__username')
    )
    roles = fields.MultipleChoiceField(
        choices=Role.objects.values_list('pk','title')
    )

def rbac_edit(request):
    '''修改權限'''
    id = request.POST.get('users')
    roles = request.POST.getlist('roles')
    obj = roleForm({'users':id,'roles':roles})
    res = obj.is_valid()
    if res:
        obj = O2o_User.objects.filter(user_id=id).first()
        obj.roles.set(roles)
    return redirect('/rbac/')
    
# 中間件過濾請求
import re
from django.utils.deprecation import MiddlewareMixin
from django.shortcuts import HttpResponse,redirect

class ValidPermission(MiddlewareMixin):
    def process_request(self,request):
        current_path = request.path_info

        pass_url = ["/index/",'/info/','/register/.*','/login/.*','/logout/','/admin/.*',]
        # 白名單直接放行
        for rule in pass_url:
            ret = re.match(rule, current_path)
            if ret:
                return None

        # 不在白名單內,判斷是否登陸用戶。
        if not request.user.username:
            return redirect('/login/')

        permission_dict = request.session.get('permission_dict')
        for item in permission_dict.values():
            urls = item['url']
            for rule in urls:
                rule = '^%s$'%rule
                ret = re.match(rule,current_path)
                if ret:
                    # 注入權限,用於控制template模板顯示增刪改
                    request.action = item['action']
                    return None
        print('沒有權限%s'%current_path)
        return HttpResponse('沒有權限%s'%current_path)

# rbac -> permission.py
from rbac import models

def valid_permission(request):
    '''提取用戶權限並存儲到session'''
    # print('ssssssssssssssss',request.path_info,user.email)
    res = models.O2o_User.objects.filter(user=request.user).values(
                                                           'roles__permissions__url',
                                                           # 'roles__permissions__title',
                                                           'roles__permissions__action',
                                                           'roles__permissions__group_id',)
    per = {}
    for item in res:
        if item['roles__permissions__group_id'] in per:
            per[item['roles__permissions__group_id']]['url'].append(item['roles__permissions__url'])
            # per[item['roles__permissions__group_id']]['title'].append(item['roles__permissions__title'])
            per[item['roles__permissions__group_id']]['action'].append(item['roles__permissions__action'])
        else:
            per[item['roles__permissions__group_id']] = {
                'url':[item['roles__permissions__url'],],
                # 'title':[item['roles__permissions__title'],],
                'action':[item['roles__permissions__action'],]
            }
        request.session['permission_dict'] = per
    print(per)
        
# 使用auth認證,登陸成功就將用戶權限保存到session中
auth.login(request,user)
valid_permission(request)

# 在rbac中建立一個模板用於rbac權限設置,用戶權限不知足就只渲染部分功能。
View Code

 

# -===-=-=-=-=-=-=-=-=-=-=-=-=-返回頂部=-=-=-=-=-=-=-=-

<span id="back_top" class="hidden">返回頂部</span>
<script>
    $(window).scroll(function () {
        var $height = $(window).scrollTop();
        if ($height > 200) {
            $('#back_top').removeClass('hidden');
        } else {
            $('#back_top').addClass('hidden');
        }
    })
    $('#back_top').click(function () {
        $('body,html').animate({
            scrollTop: 0
        }, 1000);
    })
</script>
View Code

 

# -=-=-=-=-=-=-=-ajax請求後端返回對象,前端直接使用

comment_list = list(models.Comment.objects.filter(article_id=article_id).values("pk","content"))
return JsonResponse(comment_list, safe=False) 傳送對象

success: function (data) {
$.each(data, function (index, comment_dict) {
    comment_dict.pk
}}
View Code

 

#-=-=-=-==========頁面跳轉=-=-=-=-=-=-=-=-=-

<script language="javascript" type="text/javascript"> 
// 如下方式直接跳轉
window.location.href='hello.html';
// 如下方式定時跳轉
setTimeout("javascript:location.href='hello.html'", 5000); 
</script>

<head>
<!-- 如下方式只是刷新不跳轉到其餘頁面 -->
<meta http-equiv="refresh" content="10">
<!-- 如下方式定時轉到其餘頁面 -->
<meta http-equiv="refresh" content="5;url=hello.html"> 
</head>

# 結合了倒數的javascript實現
<script language="javascript" type="text/javascript"> 
var second = document.getElementById('totalSecond').textContent; 
setInterval("redirect()", 1000); 
function redirect() 
{ 
document.getElementById('totalSecond').textContent = --second; 
if (second < 0) location.href = 'hello.html'; 
} 
</script>
View Code
相關文章
相關標籤/搜索