顯示具有 Python 標籤的文章。 顯示所有文章
顯示具有 Python 標籤的文章。 顯示所有文章

2017年11月25日 星期六

Django - Display Foreign Key object Fields at Admin Interface

# admin.py

class TaskDetailAdmin(admin.ModelAdmin):
    list_display = ['get_name']

    def get_name(self, obj):
        return obj.user.last_name

admin.site.register(models.Task, TaskAdmin)

2017年11月22日 星期三

Django - 分頁

from django.core.paginator import Paginator




reference:https://docs.djangoproject.com/en/1.11/topics/pagination/

Django - 設定User Model 顯示

#models.py

def get_name(self):
    return '{} {}'.format(self.last_name, self.first_name)

User.add_to_class("__str__", get_name)

2017年11月17日 星期五

Django - Message

此筆記將紀錄如何使用Django Message 功能
參考資料:https://docs.djangoproject.com/en/1.11/ref/contrib/messages/

設定預設Tag
# settigns.py

from django.contrib.messages import constants as messages
MESSAGE_TAGS = {
messages.INFO: '',
50: 'critical',
}


# views.py

from django.contrib import messages
messages.add_message(request, messages.INFO, 'Hello world.')


# template

            {% if messages %}
                {% for message in messages %}
                <p {% if message.tags %} class="bg-{{ message.tags }}"{% endif %}>{{ message }}</p>
                {% endfor %}
            {% endif %}



各種TAG

messages.debug(request, '%s SQL statements were executed.' % count)
messages.info(request, 'Three credits remain in your account.')
messages.success(request, 'Profile details updated.')
messages.warning(request, 'Your account expires in three days.')
messages.error(request, 'Document deleted.')


客制level
剛剛設定預設Tag的 50 = critical

def my_view(request):
    messages.add_message(request, 50, 'A serious error occurred.')

2017年11月13日 星期一

Python - DataTime筆記

from datetime import date

取得日期
t = date.today()

轉換字串
t.strftime('%Y%m%d') # 20171114

轉成TUPLE
tt = t.timetuple()


使用localtime()取得時間跟日期
import time

time.strftime('%Y-%m-%d %H:%M:%S', time.localtime()) 

Python - CSV筆記

參考:https://docs.python.org/3.6/library/csv.html


mode二碼
第一碼:
r -讀取
w - 檔案存在與否,均可寫入
x - 檔案不存在時,寫入
a - 檔案存在時,寫入結尾

第二碼:
t - 文字
b - 二進位



讀取

 import csv
 with open('eggs.csv', newline='') as csvfile:
     spamreader = csv.reader(csvfile, delimiter=',', quotechar=',')
     for row in spamreader:
         print(', '.join(row))


csvinstance轉換成串列

lists = []
for row in csv_instance:
    lists.append(row)


寫入

import csv
with open('eggs.csv', 'w', newline='') as csvfile:
    spamwriter = csv.writer(csvfile, delimiter=',', quotechar=',', quoting=csv.QUOTE_MINIMAL)
    spamwriter.writerow(['001','002','003'])

如果要使用絕對路徑backslash 改成 common slash
c:\123\  to c:/123/



2017年11月11日 星期六

Django - 語系更改

以輸入中文為例:

# settings.py

import sys  
reload(sys)  
sys.setdefaultencoding('utf-8')

LANGUAGE_CODE = 'zh-hant' # Django 1.9之前zh-TW

TIME_ZONE = 'Asia/Taipei'

2017年11月10日 星期五

Django - 客製Admin



1. 修改Admin Title



新增admin資料夾至templates資料夾並新增base_site.html
取得admin templates,參考以下連結,複製內容貼在剛剛新增的base_site.html
https://github.com/django/django

django/contrib/admin/templates/admin/base_site.html

{% extends "admin/base.html" %}

{% block title %}{{ title }} | {{ site_title|default:_('Django site admin') }}{% endblock %}

{% block branding %}
<h1 id="site-name"><a href="{% url 'admin:index' %}">{{ site_header|default:_('派工系統後台') }}</a></h1> 
{% endblock %}

{% block nav-global %}{% endblock %}


2.客制Admin ListView
首先新增一個class名字為model+admin

# admin.py

from django.contrib import admin
from . import models

class SchoolAdmin(admin.ModelAdmin):
   

記得將新增的class註冊到admin
admin.site.register(models.School, SchoolAdmin)


如要設定只需要override以下ModelAdmin變數

設定ListView欄位名稱排序
 fields = ['field1','field2','field3'] # 左至右

設定ListView搜尋功能
search_fields = ['field1','field2'] # 如此field1, field2都可以搜尋到

設定ListView Filter
list_filter = ['field1','field2']

設定ListView顯示欄位
list_display = ['field1','field2']

設定ListView欄位編輯
list_editable = ['field1','field2']






Django - Dynamic URL

# views.py

from django.shortcuts import render
from .models import Post


def post_detail(request, pk):
    post = Post.objects.get(pk=pk)
    return render(request, 'post.html', {'post': post})


# urls.py

url(r'^post/(?P<pk>\d+)/$', post_detail, name='post_detail'),
url(r'^send_message/(?P<user_id>[\w]+)/(?P<text>\w+)/$', views.send_message, name="send_message"),


2017年11月9日 星期四

Django - Line Message API 筆記

from django.conf import settings
from django.http import HttpResponse, HttpResponseBadRequest, HttpResponseForbidden
from django.views.decorators.csrf import csrf_exempt

from linebot import LineBotApi, WebhookHandler
from linebot.exceptions import InvalidSignatureError, LineBotApiError
from linebot.models import MessageEvent, TextSendMessage, TextMessage, FollowEvent

line_bot_api = LineBotApi('Channel access token')
handler = WebhookHandler('Channel secret')

# member_ids_res = line_bot_api.get_group_member_ids(group_id)

@handler.add(MessageEvent, message=TextMessage)
def handle_text_message(event):
    # print('room_id: {}'.format(event.room_id))
    print('text: {}'.format(event.message.text))
    text =event.message.text.lower()
    user = event.source.user_id
    print('user_id: {}'.format(user))
    line_bot_api.reply_message(
        event.reply_token,
        TextSendMessage(text=user)
    )

@handler.add(FollowEvent)
def handle_follow(event):
    line_bot_api.reply_message(
        event.reply_token,
        TextSendMessage(text='感謝這位兄長加我')
    )


@handler.default()
def default(event):
    print(event)
    line_bot_api.reply_message(
        event.reply_token,
        TextSendMessage(text='Currently Not Support None Text Message')
    )


@csrf_exempt
def callback(request):
    if request.method == 'POST':
        signature = request.META['HTTP_X_LINE_SIGNATURE']
        body = request.body.decode('utf-8')

        try:
            handler.handle(body, signature)
        except InvalidSignatureError:
            return HttpResponseForbidden()
        except LineBotApiError:
            return HttpResponseBadRequest()
        return HttpResponse()
    else:
        return HttpResponseBadRequest()

def send_message(request):
    line_bot_api.multicast(['to1', 'to2','to3'], TextSendMessage(text='各位都是帥哥!'))
    # line_bot_api.push_message('to1', TextSendMessage(text='Hello World!'))
    return HttpResponse()

Django - CBV筆記

之前這筆記都是使用FBV(Function Based Views),以下與CBV(Class Based Views)做對照:

#FBC
def index(request):
    return render(request, 'index.html')

#CBV
class IndexView(TemplateView):
    template_name = 'index.html'


快速體驗CBV

# views.py
from django.views.generic import View

class CBView(View):
def get(self, request):
return HttpResponse('Class Based View are Cool!')

# urls.py
from basic_app import views

url(r'^$', views.CBView.as_view()),



TemplateView應用

from django.views.generic import TemplateView

# views.py
class IndexView(TemplateView):
    template_name = 'index.html'

    # for injection
    def get_context_data(self,**kwargs): # 雙*代表字典,單*代表Tuple
     context = super(IndexView, self).get_context_data(**kwargs)
     context['injectme'] = 'Basic Injection!'
     return context
    
#urls.py
url(r'^$', views.IndexView.as_view()),





ListView應用

from django.views.generic import ListView

class SchoolListView(ListView):
context_object_name = 'schools' # 沒有使用context_object_name django將預設成 school_list
model = models.School



DetailView應用



from django.views.generic import DetailView

class SchoolDetailView(DetailView):
context_object_name = 'school_detail' # 未設定
model = models.School
template_name = 'basic_app/school_detail.html'


url(r'^(?P<pk>\d+)/$', views.SchoolDetailView.as_view(),name='detail'),



CreateView應用

class SchoolCreateView(CreateView):
fields = ('name', 'principal', 'location')
model = models.School
之後要記得去School Model 加上get_absolute_url設定轉換的頁面
url(r'^create/$', views.SchoolCreateView.as_view(), name='create'),



UpdateView應用

class SchoolUpdateView(UpdateView):
fields = ('name','principal')
model = models.School

url(r'^update/(?P<pk>\d+)/$', views.SchoolUpdateView.as_view(),name='update'),


DeleteView應用









2017年11月7日 星期二

Django - Login筆記

新增 LOGIN_URL變數 於 settings.py
新增login template
設定login views
使用decorator
設定urls.py


1. 設定settings LOGIN_URL變數
LOGIN_URL = '/basicapp/user_login'


2. 新增login template
<h1>Login</h1>

<form method="post" action="{% url 'basicapp:user_login' %}" >
{% csrf_token %}
<label for="username">Username:</label>
<input type="text" name="username" placeholder="Enter username...">
<label for="password">Password:</label>
<input type="password" name="password" placeholder="Enter password...">
<input type="submit" name="" value="Login">
</form>


3. 設定views.py

from django.http import HttpResponseRedirect, HttpResponse
from django.core.urlresolvers import reverse
from django.contrib.auth import authenticate, login, logout
from django.contrib.auth.decorators import login_required

def user_login(request):

if request.method == 'POST':
username = request.POST.get('username')
password = request.POST.get('password')

user = authenticate(username=username, password=password)

if user:
if user.is_active :
login(request, user)
return HttpResponseRedirect(reverse('index'))
else:
return HttpResponse('Account not active')
else:
print('Someone tried to login and failed')
print('Username: {} and password {}'.format(username,password))
return HttpResponse('invalid login details supply')

return render(request, 'basicapp/login.html')



@login_required
def user_logout(request):
logout(request)
return HttpResponseRedirect(reverse('index'))

@login_required
def special(request):
return HttpResponse('You are logged in!')

4. 設定urls.py

完成

判斷登入使用者

不可等入admin mode
is_authenticated

可登入admin mode
is_staff
is_superuser

2017年11月5日 星期日

Django - User Model & Form

新增與django內建User model關聯的UserProfileInfo model

from __future__ import unicode_literals
from django.db import models
from django.contrib.auth.models import User
# Create your models here.

class UserProfileInfo(models.Model):

user = models.OneToOneField(User)

# additional
portfolio_site = models.URLField(blank=True)

profile_pic = models.ImageField(upload_to='profile_pics', blank=True)

def __str__(self):
return self.user.username
使用image前先安裝pillow Image Library

pip install pillow


設定form.py

設定views.py

設定urls.py

makemigrations


2017年11月4日 星期六

Django - Password筆記

此筆記將紀錄使用者認證以及密碼

settting.py

我們將使用以下兩個app才能實作
TEMPLATE_APPS = [
    'django.contrib.auth',
    'django.contrib.contenttypes',
]

我將使用bcrypt,使用bcrypt加密密碼是較安全的做法

pip install bcrypt
pip install [argon2] # 如果是1.10以上不需要裝argon2,已經內建於django中


於settings新增

PASSWORD_HASHERS = [
    'django.contrib.auth.hashers.PBKDF2PasswordHasher',
    'django.contrib.auth.hashers.PBKDF2SHA1PasswordHasher',
    'django.contrib.auth.hashers.Argon2PasswordHasher',
    'django.contrib.auth.hashers.BCryptSHA256PasswordHasher',
    'django.contrib.auth.hashers.BCryptPasswordHasher',
]


設定AUTH_PASSWORD_VALIDATORS(可略過)

AUTH_PASSWORD_VALIDATORS = [
    {
        'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator',
    },
    {
        'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator',
        'min_length' : 9, #設定密碼至少9碼
    },
    {
        'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator',
    },
    {
        'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator',
    },
]



Django - Filter & 自製Tag 筆記

此筆記將紀錄如何使用Filter

{{ value | filter : "params" }}
並非全部的filter都用參數

每個單字以大寫開頭
{{ text | title }}

日期格式
{{ mydate | data : "Y-m-d"  }}

大寫text
{{ text | upper }}

小寫
{{ text | lower }}

數字加法,number變數必須要是數字型別
{{ number | add:"2" }}

顯示前n個字元
{{ text | truncatewords:80 }} # 前80


自製Filter


新增templatetags資料夾於app底下,注意不是project而是app


接著於templatetags新增__init__.py 和 tags.py,內容如下:

from django import template

register = template.Library()

def cut(value, arg):
return value.replace(arg,'')

register.filter('cut', cut) # 註冊cut function 成 'cut'

自製Filter,使用decorator

tags.py改成

from django import template

register = template.Library()

@register.filter(name='cut')
def cut(value, arg):
return value.replace(arg,'')


上述設定完就可以使用自製的Filter

{{ text | cut:'cool' }}



自製Tag

import datetime
from django import template

register = template.Library()

@register.simple_tag
def current_time(format_string):
    return datetime.datetime.now().strftime(format_string)

參考:https://docs.djangoproject.com/en/1.11/topics/templates/





2017年11月1日 星期三

Django - Template Inheritance筆記

此筆記將紀錄以DRY為原則的Template Inheritance
{% extends "basic_app/base.html" %}
{% block body_block %}
{% include "includes/_messages.html" %}

# base.html

{% extends "basic_app/base.html" %}

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <title>Base</title>
  </head>
  <body>
    <nav class="navbar navbar-default navbar-static-top">
    </nav>
    <div class="container">
        {% block body_block %}
        {# Anything outside of this will be inherited if you use extend.#}
        {% endblock %}
    </div>
  </body>
</html>

index.html繼承base.html的navbar

{% extends "basic_app/base.html" %}
    {% block body_block%}
        <h1>This is the index.html page</h1>
    {% endblock %}

2017年10月30日 星期一

Django - Relative URLs筆記

此筆記將紀錄進階Template技巧

1. Relative URLs


<a href="basicapp/index"> Index </a>
簡化成
<a href="{% url 'basicapp:index' %}">  Index </a>

上例我們設定路由urls.py

# urls.py

from django.conf.urls import url
from basicapp import views

app_name = 'basicapp' # 新增app_name變數
urlpatterns = [
    url(r'^$', views.index, name='index'), # 設定屬性name為index
]

由此可得 {% url 'basicapp:index' %}是如何生成


如果要產生admin頁面相對URLs
{% url 'admin:index' %}


注意:'basicapp:index' 請確認有無空白,不然會噴錯

P.S:此方法為Python2.0之後方法

Django - Model Form筆記

使筆記將紀錄使用Model Form,Model Form直接的與Form做連接,來達成驗證。

操作前務必import以下:
form django import forms
form mapp.models import MyModel

P.S:我們將使用Meta class,實作ModelForm


ModelForm操作案例:

1. show model中全部的欄位,使用__all__

class MyForm(models.ModelForm):
class Meta:
model = MyForm()
fields = "__all__"


2. 排除特定欄位,使用exclude

class MyForm(models.ModelForm):
class Meta:
model = MyForm()
exclude = ["field1", "field2", "field3"]


3. 指定特定欄位
class MyForm(models.ModelForm):
class Meta:
model = MyForm()
fields = ("field1", "field2", "field3")


如想要客制驗證,可以直接寫在Form class裡

class MyForm(models.ModelForm):
        # 加在這 name = froms.CharField(...)
class Meta:
model = MyForm()
fields = ("field1", "field2", "field3")
# 更改Modelform field 屬性
        widgets = {
            'field1': forms.TextInput(attrs={'class': 'textinputclass'}),
            'field2': forms.Textarea(attrs={'class': 'editable medium-editor-textarea postcontent'}),
        }


現在我們將進行ModelForm實作,假設我們已經有一個User Model,現在要製作一個輸入User Model頁面

1. 設定form.py

class MyModelForm(forms.ModelForm):
class Meta():
model = User
fields = '__all__'

2. 設定templates

<form method="POST">
{{ form.as_p }}
{% csrf_token %}
<input type="submit" value="Submit">
</form>

3. 設定views.py

from form import MyModelForm

def model_form_name_view(request):
form = forms.MyModelForm()
if request.method == 'POST':
form = MyModelForm(request.POST)
if form.is_valid():
form.save(commit=True) # exection, same as form.save()
return index(request)
else:
print('ERROR FORM INVALID')

return render(request, 'myapp/model_form_page.html', {'form' : form})

4. 設定urls.py

完成



隱藏內建User model  help_text 訊息

# form.py

from django.contrib.auth.models import User

class UserForm(forms.ModelForm):

password = forms.CharField(widget=forms.PasswordInput())

class Meta():
model = User
help_texts = {
'username': None, # 取消掉
                }
fields = ('username', 'email', 'password')

完成

2017年10月29日 星期日

Django - Form資料驗證筆記

此筆記將紀錄詳細的資料驗證。

以驗證機器人為例:
新增一個隱藏的欄位來檢驗機器人,如屬性value有值代表是機器人,即發出資料驗證訊息。
使用clean_XXX()來驗證單一欄位
from django import forms

class FormName(forms.Form):
name = forms.CharField()
email = forms.EmailField()
text = forms.CharField(widget=forms.Textarea)
botcatcher = forms.CharField(required=False,
widget=forms.HiddenInput)

def clean_botcatcher(self):
botcatcher = self.cleaned_data['botcatcher']
if len(botcatcher) > 0:
raise forms.ValidationError("Gotcha bot!!!")

return botcatcher



另一種方法是使用validators,可以讓程式更簡短

from django import forms
from django.core import validators

class FormName(forms.Form):
name = forms.CharField()
email = forms.EmailField()
text = forms.CharField(widget=forms.Textarea)
botcatcher = forms.CharField(required=False,
widget=forms.HiddenInput,
validators = [validators.MaxLengthValidator(0)])

客製驗證,以檢驗開頭必要為z為例:
利用validators客制自己的資料驗證,新增一個method 來寫入檢驗邏輯,成立即發出error訊息。

from django import forms
from django.core import validators

def check_for_z(value):
if value[0].lower() != 'z':
raise forms.ValidationError('Name needs to start with z')


class FormName(forms.Form):
name = forms.CharField(validators=[check_for_z],)
email = forms.EmailField()
text = forms.CharField(widget=forms.Textarea)



驗證再次輸入的email與email欄位是否相符,使用clean()
使用clean()讀取多個欄位

from django import forms
from django.core import validators

class FormName(forms.Form):
name = forms.CharField(validators=[check_for_z],)
email = forms.EmailField()
verify_email = forms.EmailField(label='Enter your email again')
text = forms.CharField(widget=forms.Textarea)

def clean(self):
email = self.cleaned_data.get('email')
vmail = self.cleaned_data.get('verify_email')
if email != vmail:
raise forms.ValidationError("make sure emails match")


Django - Basic Form筆記

此筆記將實作Basic Form


1.
新增form.py並設定欄位,如下:
from django import forms

class FormName(forms.Form):
name = forms.CharField()
email = forms.EmailField()
text = forms.CharField(widget=forms.Textarea)

2.
新增view
from django.shortcuts import render
from . import form as forms

def for_name_view(request):
form = forms.FormName()
if request.method == 'POST':
form = forms.FormName(request.POST)

if form.is_valid():
print('Validation success!!!')
print("Name: "+form.cleaned_data['name'])
print("Email: "+form.cleaned_data['email'])
print("Text: "+form.cleaned_data['text'])
                        # 此處之後進行query或是一些邏輯

return render(request, 'basicapp/form_page.html',{'form' : form})


3.
新增template
<form method="POST"> # 大小寫沒差
{{ form.as_p }}
{% csrf_token %}
<input type="submit" value="Submit">
</form>

4.
設定路由

完成