文章目录
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报错 '''