0%

Mac Docker 创建第一个Django 应用,Part 4

参考原文:Writing your first Django app, part 4
本文Python搭建在 Django Compose + Djang 执行Python需进入web server容器中,请参看[第一步:在Mac构建Django 容器]
翻译整理:CK

简单的表单处理以及精简代码

1. 简单表单

polls/templates/polls/detail.html

1
2
3
4
5
6
7
8
9
10
11
12
<h1>{{ question.question_text }}</h1>

{% if error_message %}<p><strong>{{ error_message }}</strong></p>{% endif %}

<form action="{% url 'polls:vote' question.id %}" method="post">
{% csrf_token %}
{% for choice in question.choice_set.all %}
<input type="radio" name="choice" id="choice{{ forloop.counter }}" value="{{ choice.id }}" />
<label for="choice{{ forloop.counter }}">{{ choice.choice_text }}</label><br />
{% endfor %}
<input type="submit" value="Vote" />
</form>

Mac Docker 创建第一个Django 应用,Part 3

参考原文:Writing your first Django app, part 3
本文Python搭建在 Django Compose + Djang 执行Python需进入web server容器中,请参看[第一步:在Mac构建Django 容器]
翻译整理:CK

Part3:开发前端

1. 概述

一个View是一个为特定功能服务的一种网页,例如在本例中有4个View:

  • Question “index” page – 展示最新的问题.
  • Question “detail” page – 展示一个问题,提供答题表,无答案.
  • Question “results” page – 展示一个特定问题的答案.
  • Vote action – 处理针对一个特定问题的投票.

在Djanog中网页和其他内容通过View来展示,每个View相当于一个简单的Python函数(或方法,在基于类的View中),在URLconfs中做了URL到View的映射。

2. 编写更多的View

添加到polls/views.py

1
2
3
4
5
6
7
8
9
def detail(request, question_id):
return HttpResponse("You're looking at question %s." % question_id)

def results(request, question_id):
response = "You're looking at the results of question %s."
return HttpResponse(response % question_id)

def vote(request, question_id):
return HttpResponse("You're voting on question %s." % question_id)

添加到polls.urls

1
2
3
4
5
6
7
8
9
10
11
12
13
14
from django.conf.urls import url

from . import views

urlpatterns = [
# ex: /polls/
url(r'^$', views.index, name='index'),
# ex: /polls/5/
url(r'^(?P<question_id>[0-9]+)/$', views.detail, name='detail'),
# ex: /polls/5/results/
url(r'^(?P<question_id>[0-9]+)/results/$', views.results, name='results'),
# ex: /polls/5/vote/
url(r'^(?P<question_id>[0-9]+)/vote/$', views.vote, name='vote'),
]

http://127.0.0.1:8000/polls/34/ 为例, URL之匹配除域名以外的部分,ROOT_URLCONF里的URL url(r'^polls/', include('polls.urls')), 匹配了 “polls/“ 再将剩余部分 “34/“ 发送到‘polls.urls’ URLconf 进一步处理,(?P<question_id>[0-9]+)圆括号用来捕获值,”?P“ 用来定义将要匹配到的模式的名字。[0-9]+ 匹配1到多个数字。最后将匹配到的34作为参数传给detail方法。

3. 写几个有用的View

每个View负责返回一个HttpResponse 对象,或者返回异常如Http404
列出最后5个问题:

1
2
3
4
5
6
7
8
9
10
11
from django.http import HttpResponse

from .models import Question


def index(request):
latest_question_list = Question.objects.order_by('-pub_date')[:5]
output = ', '.join([q.question_text for q in latest_question_list])
return HttpResponse(output)

# Leave the rest of the views (detail, results, vote) unchanged

这样做的缺点时,页面内容写在View的代码里,如果要改变页面的样子,就得修改Python代码。可以用模版系统来把Python跟页面设计区分开来。在setting.py的TEMPLATES设置里描述了Django如何加载和渲染模版。习惯上Django会在每个安装的APP的目录下查找templates 文件夹。

创建polls/templates/polls/index.html 写入:

1
2
3
4
5
6
7
8
9
{% if latest_question_list %}
<ul>
{% for question in latest_question_list %}
<li><a href="/polls/{{ question.id }}/">{{ question.question_text }}</a></li>
{% endfor %}
</ul>
{% else %}
<p>No polls are available.</p>
{% endif %}

修改polls/views.py

1
2
3
4
5
6
7
8
9
10
11
12
13
from django.http import HttpResponse
from django.template import loader

from .models import Question


def index(request):
latest_question_list = Question.objects.order_by('-pub_date')[:5]
template = loader.get_template('polls/index.html')
context = {
'latest_question_list': latest_question_list,
}
return HttpResponse(template.render(context, request))

这段代码加载polls/templates/polls/index.html 并传入一个context。这个context是一个字典,将模版的变量名映射为Pyhon对象。

一个快捷的render() 方法,常见的做法是载入模版,填入上下文,返回一个包含了渲染后之模版的HttpResponse对象。Django提供一个捷径如下:

重写polls/views.py

1
2
3
4
5
6
7
8
9
from django.shortcuts import render

from .models import Question


def index(request):
latest_question_list = Question.objects.order_by('-pub_date')[:5]
context = {'latest_question_list': latest_question_list}
return render(request, 'polls/index.html', context)

4. 报一个404错误

修改polls/views.py

1
2
3
4
5
6
7
8
9
10
11
from django.http import Http404
from django.shortcuts import render

from .models import Question
# ...
def detail(request, question_id):
try:
question = Question.objects.get(pk=question_id)
except Question.DoesNotExist:
raise Http404("Question does not exist")
return render(request, 'polls/detail.html', {'question': question})

创建polls/templates/polls/detail.html

1
{{ question }}

5. 捷径:A shortcut: get_object_or_404()

重写detail方法:

1
2
3
def detail(request, question_id):
question = get_object_or_404(Question, pk=question_id)
return render(request, 'polls/detail.html', {'question': question})

之所以让model API 报Http404错误而不是ObjectDoesNotExist异常,是因为如果不这样会造成模型层跟视图层的耦合。或者说views.py不应该关心模型层面的事情,而应该只专注于如何展示,取到什么内容就展示什么。去到的内容是正确的值还是错误信息,应该是model或者controller的事

同样的get_list_or_404()函数像之前的一样,除了使用filter()而不是get()。当取回的列表为空的时候返回404错误

6. 使用模版系统

polls/templates/polls/detail.html

1
2
3
4
5
6
<h1>{{ question.question_text }}</h1>
<ul>
{% for choice in question.choice_set.all %}
<li>{{ choice.choice_text }}</li>
{% endfor %}
</ul>

7. 去掉模版中的URL固定代码

修改polls/index.html

1
<li><a href="/polls/{{ question.id }}/">{{ question.question_text }}</a></li>

因为这是紧耦合的做法(当你修改项目的URL的时候,还需要去改动模版),可以使用模版标记来去掉模版对特定URL路径的依赖,改为:

1
<li><a href="{% url 'detail' question.id %}">{{ question.question_text }}</a></li>

这样的好处是polls.urls模块中,名为’detail’的url已经定义好了,根据这个跳转就了,以后如果要修改指向,只要修改polls.urls就好,例如:

1
url(r'^specifics/(?P<question_id>[0-9]+)/$', views.detail, name='detail'),

8. 使用带命名空间的URL名

如果项目中有多个app 不只一个app有detail View,如何使用模版标记

1
{% url %}

template tag?

polls/urls.py中加入 app_name = 'polls' 变成

1
2
3
4
5
6
7
8
9
10
11
from django.conf.urls import url

from . import views

app_name = 'polls'
urlpatterns = [
url(r'^$', views.index, name='index'),
url(r'^(?P<question_id>[0-9]+)/$', views.detail, name='detail'),
url(r'^(?P<question_id>[0-9]+)/results/$', views.results, name='results'),
url(r'^(?P<question_id>[0-9]+)/vote/$', views.vote, name='vote'),
]

修改polls/templates/polls/index.html

1
<li><a href="{% url 'polls:detail' question.id %}">{{ question.question_text }}</a></li>

这样Django就知道如何生成动态的超链接指向了,而去要修改app的URL也只需要修改对应app/urls.py ,无需修改模版。由于模版中往往包含超链接,这样的好处还是很大的。

Mac Docker 创建第一个Django 应用,Part 2

原文:Writing your first Django app, part 2
本文Python搭建在 Django Compose + Djang 执行Python需进入web server容器中,请参看[第一步:在Mac构建Django 容器]
翻译整理:CK

Part 2:配置后端

1. 配置数据库

已有建有的项目为mysite,Docker Django 的教程里建立了一个composeexample,这里不适用它。假设我们的真实项目为mysite,打开myiste/settings.py,默认配置的数据库是SQLite,SQLite包含在Python里,无需安装任何其他东西。如果第一次创建真实的项目,仍然希望用可伸缩性更强的数据库像PostgreSQL,免得将来又要切换数据库则:

1
2
3
4
5
6
7
8
9
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.postgresql',
'NAME': 'postgres',
'USER': 'postgres',
'HOST': 'db',
'PORT': 5432,
}
}

其他数据库绑定参考:Database Bindings

由于使用了Docker容器来运行python,数据迁移$ python manage.py migrate也需要在容器里做,所以先查看容器

1
2
3
4
$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
bf1ef3b74f1b mysite_web "python3 manage.py..." About an hour ago Up 13 minutes 0.0.0.0:8000->8000/tcp mysite_web_1
09f6cebc8741 postgres "docker-entrypoint..." 2 hours ago Up 13 minutes 5432/tcp mysite_db_1

进入容器并执行migrate:

1
2
docker exec -it mysite_db_1 bash
$ python manage.py migrate

这条命令根据myiste/settings.py里的 INSTALLED_APPS 的需要安装必要数据库表格,安装完成后再连接PostgreSQL psql DBNAME USERNAME

1
root@09f6cebc8741:/# psql postgres postgres

输入\dt 应该能看到类似Tables

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
postgres=# \dt
List of relations
Schema | Name | Type | Owner
--------+----------------------------+-------+----------
public | auth_group | table | postgres
public | auth_group_permissions | table | postgres
public | auth_permission | table | postgres
public | auth_user | table | postgres
public | auth_user_groups | table | postgres
public | auth_user_user_permissions | table | postgres
public | django_admin_log | table | postgres
public | django_content_type | table | postgres
public | django_migrations | table | postgres
public | django_session | table | postgres
(10 rows)

退出Postgres

1
postgres-# \q

2. 创建数据模型

编辑polls/models.py

1
2
3
4
5
6
7
8
9
10
11
12
from django.db import models


class Question(models.Model):
question_text = models.CharField(max_length=200)
pub_date = models.DateTimeField('date published')


class Choice(models.Model):
question = models.ForeignKey(Question, on_delete=models.CASCADE)
choice_text = models.CharField(max_length=200)
votes = models.IntegerField(default=0)

3. 启动数据模型

  1. 通知Prject,polls app 应用已安装

    编辑mysite/settings.py,添加一行'polls.apps.PollsConfig',

1
2
3
4
5
6
7
8
9
INSTALLED_APPS = [
'polls.apps.PollsConfig',
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
]
  1. 到web容器中执行命令:
1
$ python manage.py makemigrations polls

makemigrations 告诉Django你对模型做了些修改,并并希望保存下来。Django会创建修改脚本polls/migrations/0001_initial.py,
应该会看到类似:

1
2
3
4
5
Migrations for 'polls':
polls/migrations/0001_initial.py:
- Create model Choice
- Create model Question
- Add field question to choice

到此数据库并未改变,真正执行变更并且帮助你管理数据库模式是migration命令,可以用如下命令查看将要执行的SQL命令

1
$ python manage.py sqlmigrate polls 0001

应该会看到类似(不同数据库会有所不同):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
BEGIN;
--
-- Create model Choice
--
CREATE TABLE "polls_choice" ("id" serial NOT NULL PRIMARY KEY, "choice_text" varchar(200) NOT NULL, "votes" integer NOT NULL);
--
-- Create model Question
--
CREATE TABLE "polls_question" ("id" serial NOT NULL PRIMARY KEY, "question_text" varchar(200) NOT NULL, "pub_date" timestamp with time zone NOT NULL);
--
-- Add field question to choice
--
ALTER TABLE "polls_choice" ADD COLUMN "question_id" integer NOT NULL;
CREATE INDEX "polls_choice_question_id_c5b4b260" ON "polls_choice" ("question_id");
ALTER TABLE "polls_choice" ADD CONSTRAINT "polls_choice_question_id_c5b4b260_fk_polls_question_id" FOREIGN KEY ("question_id") REFERENCES "polls_question" ("id") DEFERRABLE INITIALLY DEFERRED;
COMMIT;

保存数据库修改:

1
2
3
4
5
6
$ python manage.py migrate
Operations to perform:
Apply all migrations: admin, auth, contenttypes, polls, sessions
Running migrations:
Rendering model states... DONE
Applying polls.0001_initial... OK

小结:
修改数据库分三步:

  1. 修改模型 (in models.py).
  2. 执行: python manage.py makemigrations 创建一个迁移
  3. 执行:python manage.py migrate 保存变更

4. API

下面进入交互式的Python Shell跟API一起玩耍吧,别忘了先进入容器。

1
$ python manage.py shell

如需了解database API的相关内容:database API

可进行一下尝试了解API:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
>>> from polls.models import Question, Choice   # Import the model classes we just wrote.

# No questions are in the system yet.
>>> Question.objects.all()
<QuerySet []>

# Create a new Question.
# Support for time zones is enabled in the default settings file, so
# Django expects a datetime with tzinfo for pub_date. Use timezone.now()
# instead of datetime.datetime.now() and it will do the right thing.
>>> from django.utils import timezone
>>> q = Question(question_text="What's new?", pub_date=timezone.now())

# Save the object into the database. You have to call save() explicitly.
>>> q.save()

# Now it has an ID. Note that this might say "1L" instead of "1", depending
# on which database you're using. That's no biggie; it just means your
# database backend prefers to return integers as Python long integer
# objects.
>>> q.id
1

# Access model field values via Python attributes.
>>> q.question_text
"What's new?"
>>> q.pub_date
datetime.datetime(2012, 2, 26, 13, 0, 0, 775217, tzinfo=<UTC>)

# Change values by changing the attributes, then calling save().
>>> q.question_text = "What's up?"
>>> q.save()

# objects.all() displays all the questions in the database.
>>> Question.objects.all()
<QuerySet [<Question: Question object>]>

为了让<Question: Question object>输出更可读
给模块Question and Choice (in the polls/models.py file) 添加 __str__() 方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
from django.db import models
from django.utils.encoding import python_2_unicode_compatible

@python_2_unicode_compatible # only if you need to support Python 2
class Question(models.Model):
# ...
def __str__(self):
return self.question_text

@python_2_unicode_compatible # only if you need to support Python 2
class Choice(models.Model):
# ...
def __str__(self):
return self.choice_text

除了那些常见的Python方法,可以添加一个自定义的

1
2
3
4
5
6
7
8
9
10
import datetime

from django.db import models
from django.utils import timezone


class Question(models.Model):
# ...
def was_published_recently(self):
return self.pub_date >= timezone.now() - datetime.timedelta(days=1)

在次进入shell看看有哪些变化:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
>>> from polls.models import Question, Choice

# Make sure our __str__() addition worked.
>>> Question.objects.all()
<QuerySet [<Question: What's up?>]>

# Django provides a rich database lookup API that's entirely driven by
# keyword arguments.
>>> Question.objects.filter(id=1)
<QuerySet [<Question: What's up?>]>
>>> Question.objects.filter(question_text__startswith='What')
<QuerySet [<Question: What's up?>]>

# Get the question that was published this year.
>>> from django.utils import timezone
>>> current_year = timezone.now().year
>>> Question.objects.get(pub_date__year=current_year)
<Question: What's up?>

# Request an ID that doesn't exist, this will raise an exception.
>>> Question.objects.get(id=2)
Traceback (most recent call last):
...
DoesNotExist: Question matching query does not exist.

# Lookup by a primary key is the most common case, so Django provides a
# shortcut for primary-key exact lookups.
# The following is identical to Question.objects.get(id=1).
>>> Question.objects.get(pk=1)
<Question: What's up?>

# Make sure our custom method worked.
>>> q = Question.objects.get(pk=1)
>>> q.was_published_recently()
True

# Give the Question a couple of Choices. The create call constructs a new
# Choice object, does the INSERT statement, adds the choice to the set
# of available choices and returns the new Choice object. Django creates
# a set to hold the "other side" of a ForeignKey relation
# (e.g. a question's choice) which can be accessed via the API.
>>> q = Question.objects.get(pk=1)

# Display any choices from the related object set -- none so far.
>>> q.choice_set.all()
<QuerySet []>

# Create three choices.
>>> q.choice_set.create(choice_text='Not much', votes=0)
<Choice: Not much>
>>> q.choice_set.create(choice_text='The sky', votes=0)
<Choice: The sky>
>>> c = q.choice_set.create(choice_text='Just hacking again', votes=0)

# Choice objects have API access to their related Question objects.
>>> c.question
<Question: What's up?>

# And vice versa: Question objects get access to Choice objects.
>>> q.choice_set.all()
<QuerySet [<Choice: Not much>, <Choice: The sky>, <Choice: Just hacking again>]>
>>> q.choice_set.count()
3

# The API automatically follows relationships as far as you need.
# Use double underscores to separate relationships.
# This works as many levels deep as you want; there's no limit.
# Find all Choices for any question whose pub_date is in this year
# (reusing the 'current_year' variable we created above).
>>> Choice.objects.filter(question__pub_date__year=current_year)
<QuerySet [<Choice: Not much>, <Choice: The sky>, <Choice: Just hacking again>]>

# Let's delete one of the choices. Use delete() for that.
>>> c = q.choice_set.filter(choice_text__startswith='Just hacking')
>>> c.delete()

5. 介绍Django Admin

1. 创建Admin用户

1
$ python manage.py createsuperuser
1
Username: admin
1
Email address: admin@example.com

验证两次密码:

1
2
3
Password: **********
Password (again): *********
Superuser created successfully.

注册成功

2. 开始服务器开发

Django的Admin是默认激活的

启动服务器 docker-compose up

打开: http://127.0.0.1:8000/admin/

image

输入账号密码

image

3. 通过admin来管理poll应用

修改polls/admin.py 注册Question到admin site 来告诉admin Question 已经提供了admin的接口

1
2
3
4
5
from django.contrib import admin

from .models import Question

admin.site.register(Question)

image

可以看到之前创建的question

image

可以修改

image

如果选择时间Now的时候发现时间不对,那可能就是时区问题。
检查之前的设置mysite/setting.py 例如:

1
2
#TIME_ZONE = 'UTC'
TIME_ZONE = 'Pacific/Auckland'

好了,完成第二步了

Mac Docker 创建第一个Django 应用,Part 1

第一步:在Mac构建Django 容器

原文:Quickstart: Compose and Django
翻译整理:CK

这篇文章将指导你如何用Docker Compose 配置和启动一个简单的 Django + PostgreSQL 应用。请先确保您已安装Compose:
Install Docker Compose

定义您的项目组件

您需要创建一个Dockerfile 和一个Python 依赖文件,以及一个docker-compose.yml文件

  1. 创建一个项目目录

  2. 创建一个新的Dockerfile在当前项目目录下

  3. 添加内容到Dockerfile

    1
    2
    3
    4
    5
    6
    7
    FROM python:3
    ENV PYTHONUNBUFFERED 1
    RUN mkdir /code
    WORKDIR /code
    ADD requirements.txt /code/
    RUN pip install -r requirements.txt
    ADD . /code/
  4. 保存Dockerfile

  5. 创建一个 requirements.txt
    Dockerfile 中的 RUN pip install -r requirements.txt 将会用到它

  6. 添加所需的软件到requirements.txt

    1
    2
    Django>=1.8,<2.0
    psycopg2
  7. 保存requirements.txt

  8. 创建一个docker-compose.yml
    docker-compose.yml文件里描述了您的app所需要的服务。compose一词我认为翻译为编制更恰当。在这里我们需要一个web服务器,一个数据服务器。编制文件指明了我们这些服务所用的镜像,他们如何连接,哪些卷要挂载到容器。最后定义服务端口。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    version: '3'

    services:
    db:
    image: postgres
    web:
    build: .
    command: python3 manage.py runserver 0.0.0.0:8000
    volumes:
    - .:/code
    ports:
    - "8000:8000"
    depends_on:
    - db
  9. 保存 docker-compose.yml

创建一个Django项目

  1. 转到项目根目录

  2. 用docker-compose 创建项目

    1
    docker-compose run web django-admin.py startproject composeexample .

    docker将启动web容器,并在里面执行 django-admin.py startproject composeexample,因为web镜像不存在所以compose先从当前目录建立它,见 build: 因为挂在了当前目录,所以新创建的项目文件在docker-compose run执行完推出后可以看到

  3. ls 项目目录

    1
    2
    3
    4
    5
    6
    $ ls -l
    drwxr-xr-x 2 root root composeexample
    -rw-rw-r-- 1 user user docker-compose.yml
    -rw-rw-r-- 1 user user Dockerfile
    -rwxr-xr-x 1 root root manage.py
    -rw-rw-r-- 1 user user requirements.txt

    连接数据库

  4. 打开composeexample/settings.py

  5. 替换DATABASE = …项

    1
    2
    3
    4
    5
    6
    7
    8
    9
    DATABASES = {
    'default': {
    'ENGINE': 'django.db.backends.postgresql',
    'NAME': 'postgres',
    'USER': 'postgres',
    'HOST': 'db',
    'PORT': 5432,
    }
    }

    这些参数是根据docker-compose.yml所指定的postgres Docker 镜像决定的。

  6. 保存

  7. 执行docker-compose up

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    $ docker-compose up
    djangosample_db_1 is up-to-date
    Creating djangosample_web_1 ...
    Creating djangosample_web_1 ... done
    Attaching to djangosample_db_1, djangosample_web_1
    db_1 | The files belonging to this database system will be owned by user "postgres".
    db_1 | This user must also own the server process.
    db_1 |
    db_1 | The database cluster will be initialized with locale "en_US.utf8".
    db_1 | The default database encoding has accordingly been set to "UTF8".
    db_1 | The default text search configuration will be set to "english".

    . . .

    web_1 | May 30, 2017 - 21:44:49
    web_1 | Django version 1.11.1, using settings 'composeexample.settings'
    web_1 | Starting development server at http://0.0.0.0:8000/
    web_1 | Quit the server with CONTROL-C.

    此时,你的Django app应该运行在8000端口上了。浏览器打开http://localhost:8000应该能看到
    image

  8. 列出所有容器:

    1
    2
    3
    4
    $ docker ps
    CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
    def85eff5f51 django_web "python3 manage.py..." 10 minutes ago Up 9 minutes 0.0.0.0:8000->8000/tcp django_web_1
    678ce61c79cc postgres "docker-entrypoint..." 20 minutes ago Up 9 minutes 5432/tcp django_db_1
  9. 关闭容器
    Ctrl-C
    或者新开一个terminal执行: docker-compose down

部署已有的项目到容器

  1. 将docker-compose.yml requirements.txt Dockerfile 拷贝到Django项目的根目录,应与manage.py同目录
  2. 运行docker-compose up

Python Notes

Development Specification

This is a Real Project running on AWS.
Technique used: Meteor platform + MongoDB + JavaScript
Last update at: 9/08/2017

Web Application Introduction

Client Use Interface

Most of the pages share the same template. This templete can show information in the manner of “Card”. A card can have Title, Image and Description. A Web page adopt the templete can have one card or mulitple cards.
So, it can provide a consistent style across all your Web pages, not only easy to read but also easy to maintain.

image

Admin Interface

what you see is what you get
After login the Admin accout, it’s very easy to edit the exist “Card” info or add a new “Card”.
Admin can adopt two type of “Card”, one is a Comparison Card with two images, another one have only one image.
image
image

Doing Data Science

Status: Unfinished

Statical inference
This overall process of going from the world to the data, and then from the data back to the world, is the field of statistical inference.

Observation
The characteristics of object is Observation

Modeling

  • A model is our attempt to understand and represent the nature of reality through a particular lens, be it architectural, biological, or mathematical.
  • How do you have any clue whatsoever what functional form the data should take? Truth is, it’s part art and part science.

Probability Distribution

So what is the process of doing data science?

The population is the total objects we interested in which can be represented as N.
The sample is the subset of population.
A observation can be think as the quantized or classified characteristics we capture or extract from an object.
The observe data of sample object are usually the so call data (as far as I know).
But the data themselves do not say any thing, we need some a new idea, to simplify the data, make them more comprehensible and easy to use to explain the rules of our real world. So we need the estimator or statistical estimator.

Statistical estimator is a function or rule for calculating an estimate of given quantity based on observed data. Firstly, it’s a function comes from observed data, the discovering of this function is modeling.
Secondly, it is used to calculating the estimate of given quantity.
The activities above form the process of statistical inference, start from the real world to data and then from the data back to the real world.

Modeling

Modeling is man made, aimed at eliminating the unimportant detail of the objects and abstracting information from data.
Can I say that the modeling is choosing estimator, combining and optimizing the estimators?
Before coding, we need to take a look at our data or draw a map of our data, try to understand which one is the cause, which one is affected.
In Statical Modeling people use a function to represent the relationship between data.
Greek letters represent the parameters latin letters represent data.
Modeling is part of art and port of science.
So there is no such a model that is the best.
We can just start from the simple one, take a look at the hist scatter plot, find out a simple model. Sometimes, for example, a simple model can explain 90% of data relationship while a complex one only make it 2% better to 92%.

1
2


This is a cheat sheet I reorganized, it’s aim all the Symbols or Greek letters could be appear in the R markdown, some of them can also be use in reglar markdown files. [Click]

部分内容整理自Oil Tang
参考MathJax 快速参考
希腊字母表来自维基百科
Maintainer: Chunkai

如何插入公式

LaTeX的数学公式有两种:行中公式和独立公式。行中公式放在文中与其它文字混编,独立公式单独成行。

行中公式可以用如下两种方法表示:

\(数学公式\) 或 $数学公式$(要把人民币符号换成美元符号)

独立公式可以用如下两种方法表示:

\[数学公式\] 或 $ $数学公式$ $(要把人民币符号换成美元符号)

例子:
J\alpha(x) = \sum{m=0}^\infty \frac{(-1)^m}{m! \Gamma (m + \alpha + 1)} {\left({ \frac{x}{2} }\right)}^{2m + \alpha}

显示:
$$
J\alpha(x) = \sum{m=0}^\infty \frac{(-1)^m}
{m! \Gamma (m + \alpha + 1)} {\left({ \frac{x}{2} }\right)}^{2m + \alpha}
$$

如何输入上下标

^表示上标, _表示下标。如果上下标的内容多于一个字符,要用{}把这些内容括起来当成一个整体。上下标是可以嵌套的,也可以同时使用。

例子:x^{y^z}=(1+{\rm e}^x)^{-2xy^w}

显示: $$x^{y^z}=(1+\rm {e}^x)^{-2xy^w}$$

另外,如果要在左右两边都有上下标,可以用\sideset命令。

例子:\sideset{^12}{^34}\bigotimes

显示: $$\sideset{^12}{^34}\bigotimes$$

如何输入括号和分隔符

()、[]和|表示自己,{}表示{}。当要显示大号的括号或分隔符时,要用\left和\right命令。

例子:f(x,y,z) = 3y^2z \left( 3+\frac{7x+5}{1+y^2} \right)

显示: $$f(x,y,z) = 3y^2z \left( 3+\frac{7x+5}{1+y^2} \right)$$

有时候要用 \left. 或 \right. 进行匹配而不显示本身。

例子:\left. \frac {\rm du} {\rm dx} \right| _{x=0}
\rm 空格 可以改变其后的text格式为正常格式(默认公式中的字母为斜体),其他格式可以参照#13
显示: $$\left. \frac{ {\rm d}u}{ {\rm d}x} \right| _{x=0}$$

如何输入分数

例子:\frac{1}{3} 或 1 \over 3

显示: $\frac{1}{3}$  或 $1 \over 3$

如何输入开方

例子:\sqrt{2} 和 \sqrt[n]{3}

显示: $\sqrt{2}$  和  $\sqrt[n]{3}$

如何输入省略号

数学公式中常见的省略号有4种,
\ldots 表示与文本底线对齐的省略号,
\cdots 表示与文本中线对齐的省略号,
\vdots 表示纵向排列的省略号,
\ddots 表示西方向排列的省略号。

例子:f(x1,x2,\ldots,xn) = x1^2 + x2^2 + \cdots + xn^2

显示: $$f(x1,x2,\ldots,xn) = x1^2 + x2^2 + \cdots + xn^2$$

如何输入矢量

例子:\vec{a} \cdot \vec{b}=0

显示: $$\vec{a} \cdot \vec{b}=0$$

如何输入积分

例子:\int_0^1 x^2 {\rm d}x

显示: $$\int_0^1 x^2 {\rm d}x$$

如何输入极限运算

例子:\lim_{n \rightarrow +\infty} \frac{1}{n(n+1)}

显示: $$\lim_{n \rightarrow +\infty} \frac{1}{n(n+1)}$$

如何输入累加、累乘运算

例子:\sum _{i=0}^n \frac{1}{i^2 } 和 \prod _{i=0}^n \frac{1}{i^2}

显示:
$$
\prod_{i=0}^n \frac{1}{i^2}
$$


$$\sum_{i=0}^n \frac{1}{i^2}$$

如何进行公式应用

例子:\begin{equation}\label{equation1}r = rF+ \beta(rM – r_F) + \epsilon\end{equation}

显示:$$\begin{equation}\label{equation1}r = rF+ \beta(rM – r_F) + \epsilon\end{equation}$$

引用:请见公式( \ref{equation1} )

12.希腊字母:

字母 表示 大写 表示 发音(英/美)
$\alpha$ \alpha $A$ A /ˈælfə/
$\beta$ \beta $B$ B /ˈbiːtə/ /ˈbeɪtə/
$\gamma$ \gamma $\Gamma$ \Gamma /ˈɡæmə/
$\delta$ \delta $\Delta$ \Delta /ˈdɛltə/
$\epsilon$ \epsilon $E$ E /ɛpˈsaɪlən/ /ˈɛpsɨlɒn/
$\varepsilon$ \varepsilon
$\zeta$ \zeta $Z$ Z /ˈziːtə/ /ˈzeɪtə/
$\eta$ \eta $E$ E /ˈiːtə/ /ˈeɪtə/
$\quad$
$\theta$ \theta $\Theta$ \Theta /ˈθiːtə/ /ˈθeɪtə/
$\vartheta$ \vartheta
$\iota$ \iota $I$ I /aɪˈoʊtə/
$\kappa$ \kappa $K$ K /ˈkæpə/
$\lambda$ \lambda $\Lambda$ \Lambda /ˈlæmdə/
$\mu$ \mu $M$ M /ˈmjuː/ /ˈmuː/
$\nu$ \nu $N$ N /ˈnjuː/ /ˈnuː/
$\xi$ \xi $\Xi$ \Xi /ˈzaɪ/, /ˈksaɪ/
$\quad$
$o$ \o $O$ O /oʊˈmaɪkrɒn/
$\pi$ \pi $\Pi$ \Pi /ˈpaɪ/
$\varpi$ \varpi
$\rho$ \rho $P$ P /ˈroʊ/
$\varrho$ \varrho
$\sigma$ \sigma $\Sigma$ \Sigma /ˈsɪɡmə/
$\varsigma$ \varsigma
$\tau$ \tau $T$ T /ˈtaʊ/,/ˈtɔː/
$\quad$
$\upsilon$ \upsilon $\Upsilon$ \Upsilon /juːpˈsaɪlən/ /ʌpˈsaɪlən/
$\phi$ \phi $\Phi$ \Phi /ˈfaɪ/
$\varphi$ \varphi
$\chi$ \chi $A$ A /ˈkaɪ/
$\psi$ \psi $\Psi$ \Psi /ˈsaɪ/,/ˈpsaɪ/
$\omega$ \omega $\Omega$ \Omega /ˈoʊmɨɡə/ /oʊˈmeɪɡə/

常用符号

关系运算符:

$\pm$ :\pm

$\times$ :\times

$\div$ :\div

$\mid$ :\mid

$\nmid$ :\nmid

$\cdot$ :\cdot

$\circ$ :\circ

$\ast$ :\ast

$\bigodot$ :\bigodot

$\bigotimes$ :\bigotimes

$\bigoplus$ :\bigoplus

$\leq$ :\leq

$\geq$ :\geq

$\neq$ :\neq

$\approx$ :\approx

$\sim$ : \sim

$\cong$ : \cong

$\equiv$ :\equiv

$\sum$ :\sum

$\prod$ :\prod

$\coprod$ :\coprod

##集合运算符:
$\emptyset$ :\emptyset

$\in$ :\in

$\notin$ :\notin

$\subset$ :\subset

$\supset$ :\supset

$\subseteq$ :\subseteq

$\supseteq$ :\supseteq

$\bigcap$ :\bigcap

$\bigcup$ :\bigcup

$\bigvee$ :\bigvee

$\bigwedge$ :\bigwedge

$\biguplus$ :\biguplus

$\bigsqcup$ :\bigsqcup

##对数运算符:
$\log$ :\log

$\lg$ :\lg

$\ln$ :\ln

##三角运算符:
$\bot$ :\bot

$\angle$ :\angle

$30^\circ$ :30^\circ

$\sin$ :\sin

$\cos$ :\cos

$\tan$ :\tan

$\cot$ :\cot

$\sec$ :\sec

$\csc$ :\csc

##微积分运算符:
$\prime$ :\prime

$\int$ :\int

$\iint$ :\iint

$\iiint$ :\iiint

$\iiiint$ :\iiiint

$\oint$ :\oint

$\lim$ :\lim

$\infty$ :\infty

$\nabla$ :\nabla

$\bigtriangleup$ : \bigtriangleup

$\bigtriangledown$ : \bigtriangledown

$\S$ : \S

##逻辑运算符:
$\because$ :\because

$\therefore$ :\therefore

$\forall$ :\forall

$\exists$ :\exists

$\not=$ :\not=

$\not>$ :\not>

$\not\subset$ :\not\subset

##戴帽符号:
$\hat{y}$ :\hat{y}

$\check{y}$ :\check{y}

$\breve{y}$ :\breve{y}

##连线符号:
$\overline{a+b+c+d}$ :\overline{a+b+c+d}

$\underline{a+b+c+d}$ :\underline{a+b+c+d}

$\overbrace{a+\underbrace{b+c}{1.0}+d}^{2.0}$ :\overbrace{a+\underbrace{b+c}{1.0}+d}^{2.0}

##箭头符号:
$\uparrow$ :\uparrow

$\downarrow$ :\downarrow

$\Uparrow$ :\Uparrow

$\Downarrow$ :\Downarrow

$\rightarrow$ :\rightarrow

$\leftarrow$ :\leftarrow

$\Rightarrow$ :\Rightarrow

$\Leftarrow$ :\Leftarrow

$\longrightarrow$ :\longrightarrow

$\longleftarrow$ :\longleftarrow

$\Longrightarrow$ :\Longrightarrow

$\Longleftarrow$ :\Longleftarrow

函数名

latex公式中字母默认为变量,用斜体排版,但是函数名通常用罗马字体正体排版,因此,可以用一下函数名符号书写
\sin + \cos + \tan + \max + \min + \lim + \log \ln + \deg + \exp
$$\sin + \cos + \tan + \max + \min + \lim + \log \ln + \deg + \exp$$

要输出字符

$$\# \quad $ % & \_ \{ \}$$

公式编排

列表

用- 作为无序列表的标记,不要用*

空格

\quad 生成一个空格(相当于大写’M’的宽度)
\qquad 生成一个大空格
\, 相当于3/18个\quad
相当于4/18个\quad
\; 相当于5/18个\quad
! 生成一个负空格-3/18个\quad

分隔符(括号)

(), [], {}, <>等均可以作为分隔符(分隔符主要指括号)
但是{}要用{,}表示

分割符大小调整

  • 将\left放在分隔符前,tex会自动调整分隔符的大小
  • 但是每个\left必须要用一个\right关闭
  • 如果分隔符仅有左括号则用\right关闭
    如:\left(\frac{\sqrt x}{y^3}\right)
    显示效果为:
    $$\left(\frac{\sqrt x}{y^3}\right)$$

对齐数组/矩阵

使用\begin{array}{}和\begin{matrix}都可以整齐排列公式等,个人喜欢用array,如下:

$$ \left[
\begin{array}{cc|c}
1 & 2 & 3 \\
4 & 5 & 6
\end{array}
\right] $$

$$
\begin{matrix}
1 & x & x^2 \\
1 & y & y^2 \\
1 & z & z^2 \\
\end{matrix}
$$
多级列表的缩进要连续两个tab再加标记-/*

  • 列由&分隔
  • 行由\分隔
  • 列样式有n(列数)个表示列对齐方式的字母组成,字母意义如下:
    • l 该列左对齐排列
    • c 该列居中排列
    • r 该列右对齐排列

$$
X=
\left( \begin{array}{ccc}
x_1 & x_2 & \cdots \\
x_3 & x_4 & \cdots \\
\vdots & \vdots & \ddots
\end{array}\right)
$$

如何进行字体转换

\mathrm{$\mathrm{正常字体}$}
\mathit{$\mathit{斜体}$}
\mathbf{$\mathbf{粗体符号boldfont}$}
\mathbb{$\mathbb{空心粗体blackboard}$}
\mathcal{$\mathcal{花体 flower}$}
\mathsf{$\mathsf{等线体}$}
\mathtt{$\mathtt{打字机体}$}

Java-ChatSystem

IDE Eclipse Version: Oxygen.1a Release (4.7.1a)
java version “1.8.0_144”
Java(TM) SE Runtime Environment (build 1.8.0_144-b01)
Developer: Chunkai
Repositorie
Completed at Oct 2017

USAGE

  • Clone the repository to you local disk
  • Run “ChatServer.java” to start Server, please make sure that the 5000 port is not being used.
  • Run some copy of “ChatGui.java” so you can send message to each other.
  • Input the correct Server IP into Client, by default the server and client running on the same machine, the IP address already set up for you.
  • Test Account(Usename/Password):
    A/A
    B/B
    C/C
    Bajie/B1234

Functions

Client:

image

  • Send a basic text message to the server
  • Receive text from the server
  • Username/Password login
    When account successfully login the login area Test Field will be set to disable, at the same time, the Connect Button text is set to be “Disconnect” waiting for user to disconnect.
  • Display IP address/nickname of other chat clients
  • Private messaging between users
    • Design
      By select a contact from the User List, the message will only be delivered to that person.
    • Implementation:
      When sending a private message, the first msg being sent to server is of type: CHAT_MESSAGE. The second msg is the receiver name, the third msg is message itself.
      The corresponding ClientHandler Thread maintain a total Client List will forward it to the right person.
  • Block/ignore user
    image
    • Design:
      When chose a user and click “Block/Unblock” button, this user will be block in this client.Right after the click, the background color of Blocked-User cell is set to Color Gray.If user A is block by user B, A will not received any notice about this blocking, this is for protecting B’s privacy.
    • Implementation:
      Each Client maintain two BlockUser ArrayList variables, one is the index of block-user in JList which is used to highlight cell, another ArrayList restore the block-user name for checking the incoming msg.
  • Enhanced GUI JList
    • Design:
      A checkbox is added to JList Cell to help distinguish select user and blocked user. The Checkbox always represent the current chatting friend. One Client can block as many users as it want.
    • Implementation:
      A CheckboxListCellRenderer class is use to render JList cells, this object is help render different cell background for the blocked users.

Server:

  • Listen to the default 5000 port and create a new thread for each new connection.
  • Receive text from a client
  • Broadcast a text message received from a client to all the other clients connected to the server.
  • Send the message to the specific person if Messge type is “CHAT_MESSAGE” and receiver is provided.
  • When a new user is connected or an online user logout, broadcast the new online user list to all online accounts.

Documents Description

  • ChatServer.java: The entry of the Server Application, run this app to start server
  • ChatGui.java: The entry point of Chat Client, run some of these app to start chatting.
  • ClientHandler.java: One ClientHandler thread serve one client.
  • readByLine.java: Read registered user data from UserModel.txt (Restore Username and password)
  • ServerConstants.java: Restore the constant variables which are used to defined the message type.
  • run.sh is a bash script to recompile and run the server app.

Repository

Development Specification

  • Xcode v9.1
  • Swift 3
  • Support: iphone 8/7/6/SE or plus, iPad and iPad Pro
  • Latest commit on Oct 19

Screenshot

image
image
image

1 List of technologies

1.1 Property Observers

1
2
3
4
5
6
7
8
9
10
var selectedShapeTag: Int = 0 {
willSet(newTag) {
shapeButtonArray[newTag].isSelected = true
}
didSet(oldTag) {
if selectedShapeTag != oldTag {
shapeButtonArray[oldTag].isSelected = false
}
}
}
  • Property observers observe and respond to changes in a property’s value.
    Here the variable “selectdShapeTag” is the property being observed.

  • The observer’s body is call every time a property’s value is set, it doesn’t matter if its value changed or not.
    There are two kinds of observers willSet and didSet. each property can have either one or both of these observers.

  • Here when you change the selectedShapeTag vale, for example into #3, before the new value is stored into selectedShapeTag, the shapeButtone which has a tag number 3 in an array, is set to Selected.

  • Then the variable selectedShapedTag become 3.

  • Immediately after this, the didSet snippet is called, so if the new tase is equal to the old tag, we change the old button’s state into unselected.

1.2 Delegation

Delegation is a pattern that enables one class to hand off its task to another class.

  1. Defining a protocol that encapsulate the responsibilities.

    Below is my Setting View controller.

    The Delegation is used to respond to a particular action, here it is dissmissView

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
import UIKit

protocol SettingsViewControllerDelegate: class {
func settingsViewControllerFinished(_ settingsViewController: SettingsViewController)
}

class SettingsViewController: UIViewController {

var delegate: SettingsViewControllerDelegate?
....
....
@IBAction func dismissView(_ sender: Any) {
self.dismiss(animated: true, completion: nil)
self.delegate?.settingsViewControllerFinished(self)
}
}

image

Then the CanvasViewController will adopt and confirm the protocol, and he got the object sent by the settingViewController as self, so he got the setting values of every thing: the brush size, color, transparency etc. then all the current setting can be updated.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
extension CanvasViewController: SettingsViewControllerDelegate {

func settingsViewControllerFinished(_ settingsViewController: SettingsViewController) {

if self.currentBrush.red == settingsViewController.redColorValue &&
self.currentBrush.green == settingsViewController.greenColorValue &&
self.currentBrush.blue == settingsViewController.blueColorValue {

// Get new opacty & size
self.currentBrush.opacty = settingsViewController.opacity
self.currentBrush.size = settingsViewController.lineWidth

} else {
// Get the new color from Setting View
self.currentBrush.red = settingsViewController.redColorValue
self.currentBrush.green = settingsViewController.greenColorValue
self.currentBrush.blue = settingsViewController.blueColorValue

// remove highlight from color button
colorButtonArray[selectedColorTag].backgroundColor = UIColor.white
}
}
}

image

2 Parts could be improved

2.1 Method Size

  • The codes are too big sometimes, it’s not easy to read and maintain.

  • Also my code is not neat enough, I think it is because I’m not able to get the most from various beautiful features of Swift language. So just learn more and do more.

2.2 comment

  • Another thing is annotation or comment. I don’t have much sense of when and how to make a useful comment.
    This need to do more pratices and I wish somene can shore something about that.

3 Apple Human Interface Guideline

  • User Standard gestures
  • Avoid using standard gestures to perform nonstandard actions.
  • Don’t block systemwide screen-edge gestures.
  • Offer shortcut gestures to supplement, not replace, interface-based navigation and actions.
  • Use multi-finger gestures to enhance the experience of some apps.

4 iOS Life Cycle

  • Five different Execution states of an App:
    Not running / Inactive / Active / Background / Suspended
  • Something about the App Termination
    • Misbehaving or not responding
    • Suspended
    • user can terminate
  • Apps must be prepared for termination to happen at any time and should not wait to save user data.

5 Comparison between Swift and C#

BASICS

Const is let and var is still var

1
2
3
4
# Swift
var myVariable = 42
myVariable = 50
let myConstant = 42
1
2
3
4
# C#
var myVariable = 42;
myVariable = 50;
const int myConstant = 42;

COLLECTIONS

1
2
3
4
# Swift
var shoppingList = ["catfish", "water",
"tulips", "blue paint"]
shoppingList[1] = "bottle of water"
1
2
3
# C#
var shoppingList = new[]{"catfish", "water", "tulips", "blue paint"};
shoppingList[1] = "bottle of water";

Protocol

1
2
3
4
5
6
7
protocol Nameable {
func name() -> String
}

func f<T: Nameable>(x: T) {
println("Name is " + x.name())
}
1
2
3
4
5
6
7
8
# C#
interface Nameable {
string name();
}

public void f<T>(T x) where T : Nameable {
Console.WriteLine("Name is " + x.name());
}

Lambdas and Closures

1
2
3
4
5
6
7
8
9
10
# Closure Expression Syntax
{ (parameters) -> return type in
statements
}


# Example
reversedNames = names.sorted(by: { (s1: String, s2: String) -> Bool in
return s1 > s2
})
1
2
3
4
5
6
7
8
9
10
# C#
# Expression Lambdas
(input-parameters) => expression
(x, y) => x == y

# Statement Lambdas
(input-parameters) => { statement; }
delegate void TestDelegate(string s);
TestDelegate del = n => { string s = n + " World";
Console.WriteLine(s); };

What I learned

  • How to use SQLiteBrowser to view your CoreData
  1. Download and install from http://sqlitebrowser.org

  2. Insert follow code to show db file e.g. “AppName”.sqlite

1
2
let storeUrl = appDelegate.persistentContainer.persistentStoreCoordinator.persistentStores.first?.url
print(storeUrl!)

file:///Users/xxx/Library/Developer/CoreSimulator/Devices/95E79F65-8DC5-4200-83C7-CE443685D25E/data/Containers/Data/Application/35C1939D-DD2F-4B4E-AF70-6489047977A2/Library/Application%20Support/SmartPen.sqlite

  1. Open Termial and locate to that file
    cd /Users/xxx/Library/Developer/CoreSimulator/Devices/95E79F65-8DC5-4200-83C7-CE443685D25E/data/Containers/Data/Application/35C1939D-DD2F-4B4E-AF70-6489047977A2/Library/Application%20Support

  2. run open . open that folder

  3. copy that three data file to Desktop then in sqlite brower click open DataBase.