1. from django.core.urlresolvers import reverse 的reverse是为了解决url硬编码问题
示例:return HttpResponseRedirect(reverse('polls:results',args=(poll.id,)))
注意:args中的参数必须为元祖
感觉有点像模板中使用的 <a href="{% url 'polls:vote' poll.id %}">链接</a>
这里的'polls:vote'中:
polls是总项目urls.py中命名空间,如:url(r'^polls/', include('polls.urls',namespace='polls'));
vote是name参数指定的 如:url(r'(?P<poll_id>\d+)/vote/$', views.vote, name='vote');
2.通用视图使用 from django.views import generic
1.通用列表视图
class IndexView(generic.ListView):
template_name = 'polls/index.html'
context_object_name = 'lastest_polls_list'
def get_queryset(self):
return Poll.objects.order_by('-pub_date')[:5]
2.通用详情视图
class DetailsView(generic.DetailView):
template_name = 'polls/details.html'
model = Poll
PS:urls.py中的链接要改为相应的类如 url(r'^$', views.IndexView.as_view(), name='index'),
而参数一定要用pk表示,如:url(r'(?P<pk>\d+)/$', views.DetailsView.as_view(), name='details').
3.from django.utils import timezone
timezone.now()获得当前时间
timezone.now-datetime.timedelta(days=1) 可获取时间前一天的时间以此类推还可以有参数hours,minutes,seconds
4.在manage.py shell下模仿客户端测试:
from django.test.utils import setup_test_environment #导入安装测试环境
setup_test_environment()
from django.test.client import Client
from django.core.urlresolvers import reverse
client = Client()
response = client.get('/')
response.status_code
response = client.get(reverse('polls:index'))
response.content
p = Poll(question='who is your favorite Beatle?',pub_date=timezone.now())
p.save()
response.context['lastest_poll_list'] #视图里面的参数值 通用视图中的context_object_name的值
这样测试还是比较繁琐的,我们来看看自动测试app下的tests.py
一个较完整的测试案例:
from django.test import TestCase
from django.utils import timezone
from polls.models import Poll
import datetime
from django.core.urlresolvers import reverse
# Create your tests here.
class PollMethodTest(TestCase):
def test_was_published_recently_with_future_poll(self):
future_poll = Poll.objects.create(pub_date=timezone.now() + datetime.timedelta(days=30))
self.assertEqual(future_poll.was_published_recently(),False)
def test_was_published_recently_with_old_poll(self):
old_poll = Poll.objects.create(pub_date=timezone.now() - datetime.timedelta(days=2))
self.assertEqual(old_poll.was_published_recently(),False)
def test_was_published_recently_with_now_poll(self):
now_poll = Poll.objects.create(pub_date=timezone.now() - datetime.timedelta(hours=3))
self.assertEqual(now_poll.was_published_recently(),True)
def create_poll(question, days):
return Poll.objects.create(question=question, pub_date=timezone.now()+datetime.timedelta(days=days))
class PollViewTests(TestCase):
def test_index_view_with_no_polls(self):
response = self.client.get(reverse('polls:index'))
print 'response',response.context['lastest_polls_list']
self.assertEqual(response.status_code,200)
self.assertContains(response,'No polls are available.')
self.assertQuerysetEqual(response.context['lastest_polls_list'],[])
def test_index_view_with_a_past_poll(self):
create_poll('past poll.',days=-30)
response = self.client.get(reverse('polls:index'))
self.assertQuerysetEqual(response.context['lastest_polls_list'],['
'])
def test_index_view_with_a_future_poll(self):
create_poll('future poll.',days=30)
response = self.client.get(reverse('polls:index'))
#self.assertEqual(response.status_code,404)
self.assertContains(response,'No polls are available.')
self.assertQuerysetEqual(response.context['lastest_polls_list'],[])
def test_index_view_with_future_poll_and_past_poll(self):
create_poll('future poll.',days=30)
create_poll('past poll.',days=-5)
response = self.client.get(reverse('polls:index'))
self.assertQuerysetEqual(response.context['lastest_polls_list'],['
'])
class PollDetailsTest(TestCase):
def test_details_view_with_no_exist_id(self):
pid = 1
response = self.client.get(reverse('polls:details',args=(pid,)))
self.assertEqual(response.status_code,404)
def test_details_view_with_a_future_poll(self):
future_poll = create_poll(question='future poll.',days=5)
response = self.client.get(reverse('polls:details',args=(future_poll.id,)))
self.assertEqual(response.status_code,404)
def test_details_view_with_a_past_poll(self):
p = create_poll(question='past poll.',days=-30)
response = self.client.get(reverse('polls:details',args=(p.id,)))
self.assertContains(response,'past poll.')
5. 加载静态文件
{% load staticfiles %} #加载静态文件前输入,可找到对应的路径,当前在project/polls/static/polls/style.css
<link rel="stylesheet" type='text/css' href="{% static 'polls/style.css '%}"/>
如果把css文件直接放在project/static下的话,那么要在settings.py中指定
STATICFILES_DIRS = (
os.path.join(BASE_DIR,'static'),
)
然后再修改为<link rel="stylesheet" type='text/css' href="{% static 'style.css '%}"/>即可
6.用django提供的模板创建项目布局
django-admin.py startproject --template=https://github.com/twoscoops/django-twoscoops-project/archive/master.zip --extension=py,rst,html icecream_project
7.django的所有配置选项在pythonx.x/Lib/site-packages/django/conf/global_settings.py中.
8.一个app中不要超过5个model
9.定义模型字段常用的属性:注意:字段名不要用python保留字,也不能超过一个下划线_
maxlength = 100 #长度
primary_key = True #主键
db_column = 'xxxx' #设置真正的表字段名,不设置就用django默认设置
default = xxx #设置默认值
editable = True #在admin中是否能被编辑 默认为True
help_text = xxx #设置字段的帮助信息
radio_admin = Flase #默认为False,在admin界面中用下拉框形式选择,而不是单选钮
unique=False #默认为False,字段不唯一
unique_for_date='pub_date' #设置该属性字段和pub_date字段结合起来是唯一
相应的还有unique_for_month,unique_for_year
"description" #直接用字符串描述该字段
db_index=False #该字段是否加索引,默认为False.加索引的情况:字段作为查询条件频繁出现,10%-25%查询都需要它.
blank = False #默认为False 不允许为空白 是admin管理时指定是不是必填的默认为必填项 而NULL的设置主要是给数据库看的
NULL=False #默认为False 不为NULL.设置为True时,非字符串类型会以NULL储存,对于字符串型的字段不要设置NULL=True
auto_now_add=True #自动填写当前时间 用于models.DateTimeField(auto_now_add=True)
10.字段类型
AutoField #自增字段 整型必须指定maxlength
TextField #大文本字段 不限长
BooleanField #真假值
NullBooleanField #允许为空的bool型
IntegerField #整型
PositiveIntegerField #正整型
PositiveSmallIntegerField #小的正整型
SmallIntegerField #小整型
DateFiled #日期字段 年月日
DateTimeFiled #日期时间字段
TimeFiled #时间字段 时分秒
URLFiled #url字段 文本字段但加了验证
IPAddressField #ip字段 文本字段但加了验证 不建议使用
EmailField #不接受长度参数 文本字段但加了验证
CommasSeparatedIntegerField #逗号分隔的整数字段
PhoneNumberField #电话字段,很少用
SlugField
XMLField #xml
FloatField #max_digits=5,decimal_places=2 创建要设置的两个参数,长度为5,有效小数位为2位
FiledPathField #文件路径字段
ImageField #图片字段,要使用来上传的话要在settings.py中指定MODULE_ROOT,还要指定upload_to='/xxx/'参数 上传到哪里 module.objects.get(url=?)??
FileField #文件字段,要使用来上传的话要在settings.py中指定MODULE_ROOT,还要指定upload_to='/xxx/'参数 上传到哪里 module.objects.get(url=?)??
特殊的还有
1.models.ForeginKey(Model) #多对一 有很多属性可选
假如一个制造商可以造多辆车,一辆车只有一个制造商
class Zhizaoshang(models.Model):
...
class Car(models.Model):
zhizaoshang = models.ForeignKey( Zhizaoshang)
2.models.ManyToManyField(Model) #多对多
3.models.OnetoOneField #一对一 情况很少不常用
11.模型继承
抽象继承 写一个抽象模型.不会创建真正的表.然后被其他模型继承
class CommonInfo(models.Model):
name = models.CharField(max_length=100)
age = PositiveIntegerField()
class Meta:
abstract = True
class Student(CommonInfo):
...
多表继承 尽量不用.
代理模型 子类只能增加方法,不能增加属性,而且和父类公用一张表,不会自己创建表
class User(models.Model):
a =
b =
class MyUser(User):
obj = NewManager()
class Meta:
proxy = True
def myfun(self):
pass
每个真实的模型 有一个管理器Manager 自定义自己的管理器要继承models.Manager
class NewManager(models.Manager):
#定义一些过滤函数,一些方法
上面的模型就可以使用Myuser.obj.xxx()方法
12.South数据库迁移工具,第三方工具包,针对syncdb的缺陷
pip install South #安装
在settings.py中的INSTALLED_APPS中加入'south',然后syncdb同步south的表
迁移工作
manage.py schemamigration polls --initial #常见目录并初始化
manage.py migrate polls #迁移表
manage.py migrate polls 0001 --fake #跳过已迁移的表
manage.py migrate #对所有app迁移
貌似django1.7以后有直接的迁移文件生成了
创建数据库过程
1.验证有效性 python manage.py validate
2.python manage.py sqlall books 已经变成 python manage.py makemigrations books
3.python manage.py sqlmigrate books 0001(1.7以前没有这步骤)
4.python manage.py syncdb
13.
基于函数的视图FBVs
def myview(request):
return HttpRespose()
基于类的视图CBVs---就是基于类的通用视图,在第二点中有提到过.优先使用基于类的视图
django.views.generic.ListView
django.views.generic.DetailView
django.views.generic.FormViewdjango.views.generic.CreateView
django.views.generic.TemplateView
django.views.generic.UpdateView
django.views.generic.DeleteView
URLconfs的松耦合 urls.py中不要过分依赖其他的文件,也不要使用硬编码
14.自定义的模型注册到admin中
from django.contrib import admin
from polls.models import Poll,Choice
# Register your models here.
#admin.StackedInline层级样式关联模式
#class ChoiceInline(admin.StackedInline):
# model = Choice
# extra = 3
#admin.TabularInline表级样式关联模式
class ChoiceInline(admin.TabularInline):
model = Choice
extra = 3
class PollAdmin(admin.ModelAdmin):
#fields = ('question','pub_date') #规定只显示的供编辑的字段
fieldsets = [('Question',{'fields':['question']}),('Date information',{'fields':['pub_date'],'classes':['collapse']})] #以字段集形式显示,collapse表示可收缩的
list_display = ('question','pub_date','was_published_recently')#需要显示字段
inlines = [ChoiceInline]#和上面ChoiceInline关联
list_filter = ['pub_date']#为字段增加过滤
search_fields = ['question']#为字段增加搜索
date_hierarchy = 'pub_date'#层级日期,只限日期
#注册
admin.site.register(Poll,PollAdmin)
admin.site.register(Choice)
另外模型中的方法的显示样式可修改
def was_published_recently(self):
now = timezone.now()
return now >= self.pub_date >= now - datetime.timedelta(days=1)
was_published_recently.admin_order_field = 'pub_date' #可以按照日期排序
was_published_recently.boolean = True #以减号和勾表示false和true
was_published_recently.short_description = 'Published in one day?' #字段描述显示
15.django中的forms模块(from django import forms),注重介绍forms.ModelForm的用法
forms.py
from django import forms
from questionandanwser.models import Question
#不用forms.ModelForm的写法,要自己写每一个字段
#class QuestionForm(forms.Form):
# subject = forms.CharField(required=True,max_length=100)
# description = forms.CharField(widget=forms.Textarea,required=True)
#使用forms.ModelForm,可以针对模型中的所有字段,exclude排除不显示的字段
class QuestionForm(forms.ModelForm):
class Meta:
model = Question
exclude = ('pub_date',)
#相应的修改views.py,可以直接调用form.save,而且可以用form = QuestionForm(instance=question)的instance参数直接构建一张有数据的表,单纯的forms没有改参数,也不能直接调用form.save()
#q = Question(subject=subject,description=description,pub_date=timezone.now())
#q.save()
form.save()
备注:如果不用ModelForm建立的有数据的表格,是不能够调用form.as_p() as_label() as_table()这类函数的.
16.HttpRequest对象的几个属性
HttpRequest.method #返回大写的POST活GET
HttpRequest.GET #get表单传过来的name和value
HttpRequest.POST #post表单传过来的name和value
HttpRequest.COOKIES #cookie的键值对,也是python的字典对象
HttpRequest.FILES #接收上传的文件时用,键为input的name 值为文件对象
HttpRequest.META #获取http header的数据
HttpRequest.user #获取认证系统下的user对象
HttpRequest.session #获取session
17.登陆的表单和视图一般放在主项目的文件夹下(即setting.py和urls.py那个文件夹)
18.用户登录视图例子
views.py
from django.shortcuts import render_to_response,redirect
from django.template import RequestContext
from django.contrib.auth import authenticate,login,logout
from jumpingintodjango.forms import LoginForm
def login_page(request):
message = None
if request.method == 'POST':
form = LoginForm(request.POST)
if form.is_valid():
username = request.POST['username']
password = request.POST['password']
user = authenticate(username=username,password=password)
if user is not None:
if user.is_active:
login(request,user)
return redirect('index')
else:
message = "the user is not active"
else:
message = "invalid username/password."
else:
form = LoginForm()
return render_to_response('login.html',{"form":form,"message":message},context_instance=RequestContext(request))
def homepage(request):
return render_to_response('homepage.html',context_instance=RequestContext(request))
def logout_page(request):
logout(request)
return redirect('homepage')
相应的forms.py
from django import forms
class LoginForm(forms.Form):
username = forms.CharField(max_length=20)
password = forms.CharField(widget=forms.PasswordInput())
相应的login.html中可以这样验证
{% if user.is_authenticated %}
<p>Welcome,<b>{{user.username}}.</b><a href="{% url 'logout_page' %}">logout</a></p>
{% else %}
<p>Welcome,Please<a href="{% url 'login_page' %}">log in</a></p>
{% endif %}
<p><a href="{% url 'homepage' %}">Home</a> | <a href="{% url 'index' %}">Q&A</a></p>
如果某些视图需要登录才可以使用,则加上装饰器login_required
如:@login_required
def createForm(request):
#表示要登陆才能使用createForm视图
如果没登陆就操作的话会自动呢转向LOGIN_URL
默认为LOGIN_URL=/accounts/login/
在settings.py文件中配置
from django.core.urlresolvers import reverse_lazy #这里只能使用reverse_lazy,用reverse会报错
LOGIN_URL = reverse_lazy('login_page')
另外注意,写登录视图时,不要使用login为视图名字,因为会和django.contrib.auth.login冲突
会报错:Django “login() takes exactly 1 argument (2 given)” error
这里有篇文章列举了一些django开发中的常用错误:http://www.cnblogs.com/BeginMan/archive/2013/05/06/3062544.html