扫二维码与项目经理沟通
我们在微信上24小时期待你的声音
解答本文疑问/技术咨询/运营咨询/技术建议/互联网交流
濮阳ssl适用于网站、小程序/APP、API接口等需要进行数据传输应用场景,ssl证书未来市场广阔!成为创新互联的ssl证书销售渠道,可以享受市场价格4-6折优惠!如果有意向欢迎电话联系或者加微信:028-86922220(备注:SSL证书合作)期待与您的合作!
目录
django.1
django-admin startproject.3
django-admin startapp.5
model:...7
view中使用model:...10
template.11
view中使用template:...13
去掉url和static硬编码:...15
url反解析:...15
url命名空间:...15
form处理:...16
是py下一款著名的web框架;
框架,是整个或部分系统的可重用设计,表现为一组抽象构件及构件实例间交互的方法;
是可被应用开发者定制的应用骨架;
其它web框架:flask、tornado;
django优:
自带轮子众多,方便快速开发,如ORM、Auth、Cache、Template、From核心组件;
天生的MVC设计模式;
实用且强大的管理后台;
简洁的url设计;
周边插件丰富;
django缺:
重;
同步阻塞;
django设计哲学:
大而全;
快速开发;
django历史:
最初开发者,Adrian和Simon;
开发背景,World Online维护几个新闻站点,要求快速发布新闻,快速建立其它新闻站点(快速开发、数据驱动);
World Online于05年夏天开源;
https://www.djangoproject.com/
(django) C:\django>pip install django==1.11
(django) C:\django>ipython
In [1]: import django
In [2]: django.get_version()
Out[2]: '1.11'
django version | python versions |
1.8 | 2.7,3.2,3.3,3.4,3.5 |
1.9,1.10 | 2.7,3.4,3.5 |
1.11 | 2.7,3.4,3.5,3.6 |
2.0 | 3.4,3.5,3.6 |
2.1 | 3.5,3.6,3.7 |
响应流程:
pycharm,New Project-->webproject,C:\webproject
(webproject) C:\webproject>django-admin startproject mysite #或用python manage.py startproject mysite;此命令脚本在虚拟环境的C:\Users\Administrator\py_env\webproject\Scriptsdjango-admin.exe
mysite/mysite/sessings.py #项目配置
mysite/mysite/urls.py #入口url
def url(regex, view, kwargs=None, name=None): #view是function object,不是函数调用;view函数的第一参数永远是request,不探讨CBV,view函数的返回值永远是HttpResponse对象,显式或隐式;
url(r'^hello/$', hello), #django默认会给url后加/,此处定义,hello前不带/,hello后一定要有/,这样即使用户访问http://127.0.0.1:8000/hello也会自动跳到http://127.0.0.1:8000/hello/上;若此处配置为r'^hello$',用户访问http://127.0.0.1:8000/hello/,访问的地址无论是否带/都会报404;所以记住,此处定义的url,hello前没有/,hello后要有/;
url(r'^$', views.index, name='index') #app中的urls.py,可通过name反解出url;
url(r'^polls/', include('polls.urls')), #项目中的urls.py,include里是str,在用到时才动态导入;
mysite/mysite/wsgi.py #生产部署时调用
注:
include源码,from django.conf.urls import url, include:
def include(arg, namespace=None, app_name=None):
例:
urls.py
from django.conf.urls import url
from django.contrib import admin
from django.http import HttpResponse
def index(request):
return HttpResponse('this is index')
def hello(request): #view函数的第一个参数永远是request,不探讨CBV
return HttpResponse('Hello world')
urlpatterns = [ #urlpatterns约定俗成的名字
url(r'^$', index),
url(r'^hello/$', hello), #django默认会给url后加/,此处定义,hello前不带/,hello后一定要有/,这样即使用户访问http://127.0.0.1:8000/hello也会自动跳到http://127.0.0.1:8000/hello/上;若此处配置为r'^hello$',用户访问http://127.0.0.1:8000/hello/,访问的地址无论是否带/都会报404;所以记住,此处定义的url,hello前没有/,hello后要有/
url(r'^admin/', admin.site.urls),
]
(webproject) C:\webproject\mysite>python manage.py runserver #可自定义ip:port,python manage.py runserver 0.0.0.0:8080,启动的是django内置webserver,用于测试
django app与django project区别:
app中才能用model;
app设计是可插拔的,app不一定在project中;
settings.py中有内置的app,可根据项目情况禁用;
(webproject) C:\webproject\mysite>django-admin startapp polls #或用python manage.py startapp polls,新建投票app,在项目根下操作
admin.py #后台管理
apps.py #1.8ver后加的,app的独立配置
tests.py #测试用例
views.py #业务逻辑
migrations/ #与model的版本控制有关
例:
mysite/mysite/settings.py #在项目settings.py中导入app
INSTALLED_APPS = [
'polls.apps.PollsConfig',
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
]
mysite/polls/views.py
from django.shortcuts import render
from django.http import HttpResponse
def index(request):
return HttpResponse('this is index at polls')
mysite/polls/urls.py #app中的urls.py默认不存在,新建
urlpatterns = [
url(r'^$', views.index, name='index')
]
mysite/mysite/urls.py
urlpatterns = [
url(r'^polls/', include('polls.urls')), #include中是str,在用到时才动态导入
url(r'^admin/', admin.site.urls),
]
支持sqlite、MySQL、postgresql、oracle;
py3.5以上版本,不支持MySQLdb驱动;
可用pymysql,py写的;
可用mysqlclient,c写的,速度快,fork的MySQLdb,官方推荐;
ORM,用py的方法、数据结构,来访问db,可兼容不同的DB;
一个class代表一张表,多对多会产生额外一张关系表;
默认pk为id,也可自定义pk;
表名默认为$APP_NAME$CLASS_NAME.lower(),表名小写(跨平台支持),可重写;
models migrations:
定义好models.py需应用到db,django为了能跟踪表结构的变化,增加了migration版本控制功能,如果没有该功能,需手动编写表结构变化的语句,重新导入数据;
models CRUD:
增:
q = Question(**kwargs) #方式1
q.save()
q = Question.objects.create(**kwargs) #方式2
删:
q = Question.objects.get(id=1)
q.delete()
Question.objects.filter(id=1).delete()
Question.objects.all().delete()
改:
q = Question.objects.get(id=1)
q.question_text = 'some text'
q.save()
Question.objects.filter(id=1).update(question_text='why ?')
查:
Question.objects.all()
Question.objects.filter(question_text="what's up?") #objects,model默认的manager管理器
Question.objects.get(id=1)
latest_question_list = Question.objects.order_by('-pub_date')[:3] #默认升序,加上-倒序
注:
>>> from django.utils import timezone
>>> import datetime
>>> timezone.now() #比datetime.datetime.now()多了时区,在页面展示时,django内部会转为适合用户所在的时区
datetime.datetime(2019, 1, 2, 7, 2, 18, 244920, tzinfo=
>>> datetime.datetime.now()
datetime.datetime(2019, 1, 2, 15, 2, 32, 837755)
models中方法:
def __str__(self):
return self.question_text
def was_published_recently(self):
return self.pub_date >= timezone.now() - datetime.timedelta(days=1)
mysite/mysite/settings.py
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.sqlite3',
'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
}
}
mysite/polls/models.py
from django.db import models
class Question(models.Model): #一个class代表一张表,多对多会产生额外一张关系表;默认pk为id,也可自定义pk;表名默认为$APP_NAME$CLASS_NAME.lower(),可重写
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)
(webproject) C:\webproject\mysite>python manage.py makemigrations #生成迁移记录
(webproject) C:\webproject\mysite>python manage.py migrate #应用到db
(webproject) C:\webproject\mysite>sqlite3 db.sqlite3
sqlite> .tables
auth_group django_admin_log
auth_group_permissions django_content_type
auth_permission django_migrations
auth_user django_session
auth_user_groups polls_choice
auth_user_user_permissions polls_question
sqlite> .quit
(webproject) C:\webproject\mysite>dir polls\migrations\
驱动器 C 中的卷是 OS
卷的序列号是 000B-5D26
C:\webproject\mysite\polls\migrations 的目录
2019/01/02 14:24
2019/01/02 14:24
2019/01/02 14:24 1,266 0001_initial.py
2019/01/02 11:29 0 __init__.py
2019/01/02 14:25
2 个文件 1,266 字节
3 个目录 77,168,365,568 可用字节
(webproject) C:\webproject\mysite>python manage.py sqlmigrate polls 0001_initial #查看sql语句是否是指定要求的
(webproject) C:\webproject\mysite>python manage.py shell #进入交互式命令行
>>> from django.utils import timezone
>>> from polls.models import Question,Choice
>>> q = Question(question_text="what's new", pub_date=timezone.now())
>>> q.save()
>>> q.id
1
>>> q.pk
1
>>> q.question_text
"what's new"
>>> q.pub_date
datetime.datetime(2019, 1, 2, 6, 49, 16, 612213, tzinfo=
>>> from polls.models import Question,Choice
>>> from django.utils import timezone
>>> q = Question.objects.create(question_text="how are you?", pub_date=timezone.now())
>>> q = Question.objects.create(question_text="what's the weather?", pub_date=timezone.now())
>>> q = Question.objects.create(question_text="fuck you!", pub_date=timezone.now())
>>> q
>>> q.was_published_recently()
True
>>> d = timezone.now() - timezone.timedelta(days=2)
>>> q.pub_date = d
>>> q.save()
>>> q.was_published_recently()
False
from django.http import HttpResponse
from .models import Question
def index(request):
latest_question_list = Question.objects.order_by('-pub_date')[:3] #默认升序,加上-倒序
output = ', '.join([q.question_text for q in latest_question_list])
return HttpResponse(output)
def detail(request, question_id):
return HttpResponse('Your are looking at question {}'.format(question_id))
def results(request, question_id):
response = 'Your are looking at results of question {}'.format(question_id)
return HttpResponse(response)
def vote(request, question_id):
return HttpResponse('Your are voting on question {}'.format(question_id))
django内置了自己的模板引擎,和jinja很像,使用简单;
django默认会在app_name/templates/下寻找模板,在app_name/templates/下再建立app_name,这样app_name/templates/app_name/下存放与该app相关的模板,因为默认django会去所有的app下找模板,可能会优先找到其它app下的模板;
默认会到app_name/static/下寻找静态文件;
设置公用templates和公用static:
mysite/mysite/settings.py
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [os.path.join(BASE_DIR, 'templates')],
'APP_DIRS': True,
……
STATIC_URL = '/static/'
STATICFILES_DIRS = [
os.path.join(BASE_DIR, 'static'),
]
>>> from django.template import Template,Context
>>> t = Template('My name is {{ name }}')
>>> c = Context({'name':'jowin'}) #context可以是 dict、属性、方法、tuple|list
>>> t.render(c)
'My name is jowin'
>>> t = Template('my name is {{ name }}')
>>> d = {'name':'jowin'}
>>> c = Context(d)
>>> t.render(c)
'my name is jowin'
>>> t = Template('my name is {{ user.name }}') #变量查找,dict、attr、method、list、tuple
>>> class Person:
... def __init__(self,name):
... self.name = name
...
>>> user = Person('jowin')
>>> user.name
'jowin'
>>> c = Context({'user':user})
>>> t.render(c)
'my name is jowin'
>>> t = Template('my name is {{ user.name }}')
>>> class Person:
... def name(self):
... return 'jowin'
...
>>> user = Person()
>>> user.name()
'jowin'
>>> c = Context({'user':user})
>>> t.render(c)
'my name is jowin'
模板引擎支持循环、判断、过滤器:
for:
{% for person in person_list %}
{% endfor %}
if:
{% if max > 10 %}
{% else %}
{% endif %}
过滤器:
{{ now | date:"F j,Y" }}
{{ name | length }}
render源码,from django.shortcuts import render:
def render(request, template_name, context=None, content_type=None, status=None, using=None):
"""
Returns a HttpResponse whose content is filled with the result of calling
django.template.loader.render_to_string() with the passed arguments.
"""
content = loader.render_to_string(template_name, context, request, using=using)
return HttpResponse(content, content_type, status)
另,render_to_response(),老版本1.6用;
mysite/polls/views.py
from django.http import HttpResponse
from .models import Question
from django.template import loader
# def index(request):
# latest_question_list = Question.objects.order_by('-pub_date')[:4]
# template = loader.get_template('polls/index.html')
# context = {'latest_question_list': latest_question_list}
# # output = ', '.join([q.question_text for q in latest_question_list])
# return HttpResponse(template.render(context)) #方1
def index(request):
latest_question_list = Question.objects.order_by('-pub_date')[:4]
context = {'latest_question_list': latest_question_list}
return render(request, 'polls/index.html', context) #方2
mysite/polls/templates/polls/index.html
#mysite/polls/static/django.png
{% if latest_question_list %}
{% for question in latest_question_list %}
{% endfor %}
{% endif %}
(webproject) C:\webproject\mysite>python manage.py runserver
mysite/polls/templates/polls/index.html
{% load static %}
{% if latest_question_list %}
{% for question in latest_question_list %}
{% endfor %}
{% endif %}
注:
{% url 'detail' question.id %} #app的urls.py中定义的name有关;app namespace改后,'detail'改为'polls:detail';
正解析,url-->view;
反解析,view-->url;
>>> from django.shortcuts import reverse
>>> reverse('detail',kwargs={'question_id':1})
'/polls/1/'
另,reverse_lazy(),为解决循环依赖;
app namespace和instance namespace:
通常使用app namespace;
若app有多个include,使用instance namespace;
app namespace:
mysite/polls/urls.py #方1,建议使用,在app_name/urls.py中定义
app_name = 'polls'
mysite/mysite/urls.py
url(r'^polls/', include('polls.urls', app_name='polls')), #方2,在项目下定义mysite/mysite/urls.py
instance namespace:
instance级别,名称不可以重复;
mysite/mysite/urls.py
url(r'^polls/', include('polls.urls', namespace='polls')),
mysite/polls/templates/polls/detail.html
{% if error_message %}
{{ error_message }}
{% endif %}
mysite/polls/views.py
from django.shortcuts import render, get_object_or_404, reverse
from django.http import HttpResponse, HttpResponseRedirect
from .models import Question, Choice
from django.template import loader
# from django.core.urlresolvers import reverse
# def index(request):
# latest_question_list = Question.objects.order_by('-pub_date')[:4]
# template = loader.get_template('polls/index.html')
# context = {'latest_question_list': latest_question_list}
# # output = ', '.join([q.question_text for q in latest_question_list])
# return HttpResponse(template.render(context))
def index(request):
latest_question_list = Question.objects.order_by('-pub_date')[:4]
context = {'latest_question_list': latest_question_list}
return render(request, 'polls/index.html', context)
def detail(request, question_id):
# try:
# question = Question.objects.get(id=question_id)
# except Question.DoesNotExist:
# return HttpResponse('Not Found', status=404)
question = get_object_or_404(Question, pk=question_id)
return render(request, 'polls/detail.html', {'question': question})
def results(request, question_id):
question = get_object_or_404(Question, pk=question_id)
return render(request, 'polls/results.html', {'question': question})
def vote(request, question_id):
question = get_object_or_404(Question, pk=question_id)
print(request)
if request.method == 'POST':
choice_id = request.POST.get('choice', 0)
try:
selected_choice = question.choice_set.get(pk=choice_id)
except Choice.DoesNotExist:
return render(request, 'polls/detail.html', {
'question': question, 'error_message': 'You did not select a choice',
})
else:
selected_choice.votes += 1
selected_choice.save()
return HttpResponseRedirect(reverse('polls:results', args=(question.id,)))
mysite/polls/templates/polls/results.html
{% for choice in question.choice_set.all %}
{% endfor %}
项目中使用:
pip install pymysql
pip install pillow #ImageField依赖
1、 数据库使用mysql:
项目目录的__init__.py中
import pymysql
pymysql.install_as_MySQLdb()
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.mysql',
'NAME': 'mxonline',
'USER': 'mxonline',
'PASSWORD': '123456',
'HOST': '192.168.88.222',
'PORT': 3306
}
2、apps目录下统一放app:
右键apps-->Mark directory as-->Source Root #解决编辑器查找,import时可在apps中找
import sys
sys.path.insert(0, os.path.join(BASE_DIR, 'apps')) #解决命令行环境查找
我们在微信上24小时期待你的声音
解答本文疑问/技术咨询/运营咨询/技术建议/互联网交流