dirtree

mysite               :pycharm默认的项目根目录,import会正常导入下面的各个目录.
  - db.sqlite3       :对应了models.py.数据库中的表名如:app1_usertype..
  - manage.py        :python manage.py startapp app1

  - mysite
    - __init__.py    :python3可以不需要.
    - settings.py    :数据库,指定html路径,指定添加的app..
    - urls.py        :route(rul->method)
    - wsgi.py        :一般会替换为uWSGI+NGINX,性能更好一些.

  - templetes        :html
    - master.html    :属于公共的html模板,实现了大部分公共界面,里面预留了一些block,等待他业务html继承.

  - static           :js,images,video..  

  - app1
    - templetestags

      - func.py      :里面定义一些函数共html中使用
    - migrations     :记录数据库的每次修改

    - admin.py       :后台管理
    - apps.py        :对当前app1的配置
    - models.py      :每个类都对应了数据中的一张表!
    - views.py       :业务处理,回调函数对应于urls.py.
    - tests.py       :单元测试

  - middle
    m1.py            :中间件,对应于settings.py-MIDDLEWARE.
python manage.py createsuperuser  # 建立超级管理员,对应admin.py!
python manage.py makemigrations  # 修改model后同步到数据库
python manage.py migrate  # 应用上面的更改

settings.py

INSTALLED_APPS = (
  ....
  'app1',  # 不然models的类不能配合makemigrations同步到数据库!

)

DATABASES = (
  'default': {
     # django默认使用mysqldb连接,故需要在mysite/__init__.py中需要'import pymysql && pymysql.install_as_MySQLdb()'
     'ENGINE': 'django.db.backends.mysql',
     'NAME': 'dbname',  # 必须是已经创建好的数据库
     'USER': 'root',
     'PASSWORD': 'pwd',
     'HOST': '',
     'PORT': '',
  }
)
STATICFILES_DIR = (
  os.path.join(BASE_DIR, 'static'),  # 配置静态文件目录

)
SESSION_ENGINE='django.contrib.sesssions.backends.cache'  # session默认放在数据库中
MIDDLEWARE = [
  ....
  'middle.m1.CMiddleWare1',
]

models.py

from django.db import models

class UserType(models.Model):
    # 会隐含的创建id自增主键列.
    name = models.CharField(max_length=32)  # 表UserType的第一列.

class UserInfo:
    '''  其他参数
    blank    :admin中是否可以为空
    help_text:admin中的提示信息
    db_index :是否对该列建立索引,经常做查询key的列需要建立.
    unique   :唯一索引
    auto_now :在更新记录的时候,该列会自动更新时间,精确到微妙!
    auto_now_add :在创建新记录的时候,该列会自动插入当前时间!
    '''
    uid = models.AutoFiedl(primary_key=True)  # 自指定自增列
    username = models.CharField(verbose_name='用户名',max_length=16)  # 用户名可以在views中使用ModeForm使自动取值
    pwd = models.CharField(max_length=16,null=True)  # 注意:若之前其他列都有好多数据了,则新添加的列必须指定值,不然会有提示!
    email = models.EmailField(max_length=16)  # 实际上仅能够对admin的表单数据做验证!

    user_type_id = models.IntegerField(choices=((0,'超级用户'),(1,'普通用户')), default=1)  # admin中会显示下拉框
    # 可直接访问关联的表: row.user_type.name
    # 类型是UserType.uid(默认就是主键关联),列明会被自动修改为user_type_id.
    user_type = models.ForeignKey('UserType', to_field='uid')
# 通常在Views.py导入,然后取得数据库的数据后传递给render参数!
# filter()+values()过滤中使用双下划线用于跨表取数据,相当于对象的点语法!
models.UserInfo.objects.create(username='root',pwd='123')  # 或-->
models.UserInfo.objects.filter(username='root').delete()  # 也可以all().delete()
models.UserInfo.objects.filter(username='root').update(pwd=1)  # 改密码
models.UserInfo.objects.filter(username='root').first()  # 找到第1个匹配,不存在==None!
.all().values('col1','user_type__name') # [{'col1':v, 'col2':v}...],限定仅取指定的列
for r in models.UserInfo.objects.all(): # [userinfo_obj, ...]
    r.id, r.username, r.pwd

admin.py

后台管理用的,必须把^admin映射添加到urls.py中!

from django.contrib import admin
from app1 import models
admin.site.register(models.UserInfo)
admin.site.register(models.UserType)

urls.py

相当于一个桥梁,很多动作都需要借助此处搭建!

from django.conf.urls import url,include
from django.contrib import admin
from app1 import views
urlpatterns = [ # $防止子页面匹配
  url(r'^app2', include('app2.url')),  # 分发出去,分解到每个app中.更合理!
  url(r'^admin/', admin.site.urls),
  url(r'^index/$', views.index, {name='urlname'}), # 默认值,函数必须要有参数name
  url(r'^login/', views.Login.as_view()),  # 使用类对应route!
  url(r'^detail-(\d+)-(?P<pname>\d+).html', views.detail),  # 第二个正则指定了名称
]

views.py

request.environ 里面放了很多请求头的信息!

from django import render,redirect,forms
from django.views import View
from django.core.validators import RegexValidator
from app1 import models

# 简化表单的验证操作,对应了html中的表单,数据成员与表单的name一一对应!
# html模板里面{{ obj.username }} == <input type='text' name=username>
def MyForm(forms.Form):
    # 其他类型的field:
    # IntegerField(max_value=) FloatField DecimalField DateField(2017-10-10) TimeField(11:12) DateTimeField ChoiceField...
    # -------    # field的其他参数:
    # strip=True  :移除用户输入的空白,CharField才有,另外还有max_length+min_length.
    # lable       :控件(输入框)前面对应的说明label
    # initial     :initValue
    # help        :控件后面显示的帮助信息
    # widgets     :HTML插件
    # validators  :额外的正则表达式验证:RegexValidator(r'^\d+$')
    # -------
    # widgets.PasswordInput, 对应ChoiceField: RadioSelect/Select/SelectMultiple CheckBox .....
    username = forms.fields.CharField(error_message={'required':'用户名不能为空'}, widget=forms.widgets.Textarea(attrs={'class':'c1'}))
    usertype = forms.fields.ChoiceField(choice=models.UserType.objects.values_list('id','caption'))
    email = forms.fields.EmailField()
    def __init__(self, *args, **kvargs):
        super(MyForm, self).__init__(*args, **kvargs)
        self.fields['usertype'].choices = models.UserType.objects.values_list('id','caption')
		
# 这种方式定制程度小一些
def MyForm1(forms.ModelForm):
    ''' 可以定义一些额外的组件,如操作的checkbox,统计等 '''
    class Meta:
        model = models.UserInfo
        fields = ['username']  # 或 __all__
        exclude=....
        labels = {'username':'用户名'}  # model里面就不用指定verbose_name了
        help_texts = {'username':'控件后面的提示信息'}
        widgets = ...
    def clean_username(self):  # 定义一个username的钩子,可以对其做最后的修饰
        old = self.cleaned_data['username']
        return old

# ----- 对应每个url
def detail(request, *args, **kwargs):
    if request.method == 'POST':
        obj = MyForm(request.POST)
        obj1= MyForm1(request.POST,instance=models.UserInfo.objects.filter(id=nid).first()) # instance:用于指定对哪个数据进行更新
        if obj.is_valid():
            models.UseInfo.objects.create(**obj.cleaned_data)  # 使用表单数据来创建数据库条目
            obj1.save()
        else:
            obj.errors['username']  # 获取其中的一个错误信息
            obj1.errors.as_json()
    elif request.method == 'GET':
        obj = MyForm()  # get中使用是为了兼容诸如{{obj.username}},并让错误提示后不清空原有输入
        obj1= MyForm1(instance=models.UserInfo.objects.filter(id=nid).first())
        di = f(p)
    return render(request, 'detail.html', {'key':di, 'obj':obj})

def index(request, p):
    if request.method == 'GET':
        v = request.session.get('username',None)  # 对session可使用所有字典方法
        v = request.session.session_key  # 服务器产生的双方的key.一个随机字符串
        v = request.COOKIES.get('username')  # 取用户以前填过的值,也可使用[]或.语法!
        v = request.get_signed_cookie('pwd',salt='123')
    elif request.method == 'POST':
        request.POST.get('user', None)

        request.POST.getlist('user', None)  # checkbox,select等多选内容

        # ------
        o = request.FILES.get('filename')  # 获得可迭代的文件对象
        o.name;
        for i in o.chunks(): f.write(i)
        # 这种方式比下面的安全点!依赖于cookie!
        request.session['username']=...
        # ------
        r = redirect('/home')
        # 填入v(用户输入的值),8秒后失效.expires=datetime();path:生效的路径;
        # r.set_signed_cookie(..., salt='123')
        r.set_cookie('username',v,max_age=8)

        return r
    # 会自动进入templetes找!打开+读取+render,然后交给django+cgi转发给浏览器!
    # html文件中tag标签内容可以使用{{key}}.render后会被参数中的value替换!直接传递request也行!
    return render(request, 'login.html', {'key':g_dict})

class Login(View):
    # dispath类似于PreTranslateMessage,最终的父类负责调用GET+POST..此处是在响应之前/后加装修饰!
    def dispatch(self, request, *args, **kwargs):
        ...
        r = super(Login, self).dispath(request, *args, **kwargs)
        ...
        return r
    def get(self, request):  pass
    def post(self, request): pass

home.html

要想样一个连接关联一个动作,则需要借助与一个唯一的url,故总是需要借助与urls中url<–>method函数映射!

{% url 'urlname' 2 %}. :urlname/2/; django.urls.reverse('urlname', args=(2,))可以翻转.

func.py

from django import template

from django.utils.safestring import mark_safe
register = template.Library()
# simple_tag定义的函数只能用{%..%}调用,但是不能用在{%if%}这种语句.

@register.simple_tag
def func(p1, p2):
  str = mark_safe(str)  # 默认str中内容(用户的评论)服务器都认为是不安全,此处屏蔽.
# 可以在{{}}中调用,p1参数自动取|前面的值!可以用在{%if%}这种语句.

@register.filter
def func1(p1, p2, p3):
  ...

yewu.html

{% extents 'master.html' %}

{% load 'func.py' %}
{% block title %}业务1{% block content %}

{% block content %}
  <!-- 这里面的内容可以替换模板master.html中的content块! -->
  <!-- 通常还会有css与js的block块等待实现.顺序无所谓 -->
  {% include add.html %}  :引入某些小的重复的html模块,可以引入多次.

  {% func param1 par2 %}  :调用自定义函数
  {% csrf_token %}        :表单提交安全性要求.服务器的随机字符串.
  <table>
    {% for k,v in g_dict.items %}
      <tr>
        <td>{{ row.atrr1 | lower | func1:'p2,p3' }}</td>
        {{ request.path_info }} :当前页面的url
        {{ forloop.counter }}.  :当前第几次循环!counter0:从0开始.revcount:倒序
      </tr>
    {% endfor %}

    {% if age > 2 %}

    {% else %}
    {% endif %}
  </table>

{% endblock %}

m1.py

每个中间件就相当于一个把门的,里面有好几个人,职责各异.

|m1| |m2| |m3| ...
request... == m1:request1 --> m2:request2 --> m3:request3 --> ...
request... --> view... --> exception... --> response...
class CMiddleWare1(MiddlewareMixin):
    def process_request(self, request):
        ''' 不返回则不过滤 '''
    def process_response(self, request, response):
        ''' 一般用来过滤 '''
    def process_view(self, request, callback, args, kvargs):
        ''' 一般用来过滤 '''
    def process_exception(self, request, exception):
        ''' view中的回调函数出现异常时进来;一般用来处理views报错 '''