学习django的心得与记录

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.FormView

django.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

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值