django 菜鸟篇+进阶篇

django自带web server, 故django开发的项目可以独立的运行,也可以安置在apache(+mod_python)下运行

django wiki

django主页

django源码和api

hello,word demo

django官方文档


django的官网手册 http://www.djangobook.com/en/2.0/; 对应的中文翻译版本 http://download.csdn.net/detail/xiarendeniao/4232144 http://djangobook.py3k.cn/


下面是菜鸟篇:

django处理请求的过程:
    1. 进来的请求转入/hello/.
    2. Django 通过在ROOT_URLCONF 配置来决定根URLconf.
    3. Django 在 URLconf 中的所有 URL 模式中,查找第一个匹配/hello/的条目。
    4. 如果找到匹配,将调用相应的视图函数
    5. 视图函数返回一个HttpResponse
    6. Django 转换HttpResponse 为一个适合的HTTP response, 以 Web page 显示出来
    
M ,数据存取部分,由django 数据库层处理,本章要讲述的内容。
V ,选择显示哪些数据要及怎样显示的部分,由视图和模板处理。
C ,根据用户输入委派视图的部分,由Django 框架通过按照URLconf 设置,对给定URL 调用合适的python 函数来自行处理。


一、视图函数(views.py中的函数):第一个参数类型是HttpRequest对象,返回值是HttpResponse对象
二、URLconf(urls.py):绑定视图函数和URL (urlpatterns只有一个空串时django显示欢迎页面)
    (r'^time/plus/(\d{1,2})/$', hours_ahead),urls.py用圆括号从正则中提取数据;
    def hours_ahead(request, offset):...,views.py视图函数的第二个参数是从url中提取的字符串
三、调试,在视图的任何位置插入一个assert False来触发django的出错页
四、模板引擎
    1.模板是一个文本,用于分离文档的表现形式和内容。模板定义了占位符以及各种用于规范文档该如何显示的各部分基本逻辑(模板标签)。模板通常用于产生HTML,但是 Django 的模板也能产生任何基于文本格式的文档。
    2.用两个大括号括起来的文字(例如{{ person_name }} )称为变量(variable) 。这意味着将按照给定的名字插入变量的值。
    3.被大括号和百分号包围的文本(例如 {% if ordered_warranty %} )是 模板标签(template tag) 。标签(tag)定义比较明确,即:仅通知模板系统完成某些工作的标签。
    4.filter 过滤器,它是一种最便捷的转换变量输出格式的方式。如这个例子中的{{ship_date|date:”F j, Y” }},我们将变量ship_date 传递给date 过滤器,同时指定参数”F j,Y”。date过滤器根据参数进行格式输出。
    5.模板使用
        1>可以用原始的模板代码字符串创建一个Template 对象,Django 同样支持用指定模板文件路径的方式来创建Template 对象;
        2>调用模板对象的render 方法,并且传入一套变量context。它将返回一个基于模板的展现字符串,模板中的变量和标签会被context 值替换。
        python manage.py shell 进入交互模式

                >>> from django import template
		>>> t = template.Template('My name is {{ name }}.')
		>>> c = template.Context({'name': 'Adrian'})
		>>> print t.render(c)
		My name is Adrian.
		>>> c = template.Context({'name': 'Fred'})
		>>> print t.render(c)
		My name is Fred.


    6.template.Context跟字典的结构类似;t.render(c)返回的是一个unicode对象,not 普通python字符串
    7.在 Django 模板中遍历复杂数据结构的关键是句点字符(.);假设你要向模板传递一个Python 字典。 要通过字典键访问该字典的值,可使用一个句点;同样,也可以通过句点来访问对象的属性;点语法也可以用来引用对象的"方法",调用方法时并没有使用圆括号而且也无法给该方法传递参数,你只能调用不需参数的方法;不允许使用负数列表索引,像 {{ items.-1 }} 这样的模板变量将会引发`` TemplateSyntaxError``
    8.get_template() 函数以模板名称为参数,在文件系统中找出模块的位置,打开文件并返回一个编译好的Template对象.要定位某个模板文件在你的系统里的位置, get_template()方法会自动为你连接已经设置的TEMPLATE_DIRS 目录和你传入该法的模板名称参数
    9.比get_template()+Context+HttpResponse更方便的方式:render_to_response() 的第一个参数必须是要使用的模板名称。如果要给定第二个参数,那么该参数必须是为该模板创建Context 时所使用的字典。如果不提供第二个参数,render_to_response() 使用一个空字典
    10.{% include "xx.html" %} 把一个网页嵌入到另一个中,适用于头部和底部的共有部分,对网页中间部分使用不方便
    11.{% extents "xx.html" %} {% block yy %} {% endblock %} 模板继承就是先构造一个基础框架模板,而后在其子模板中对它所包含站点公用部分和定义块进行重载
    12.如果你需要访问父模板中的块的内容,使用{{ block.super }}这个标签吧,这一个魔法变量将会表现出父模板中的内容。如果只想在上级代码块基础上添加内容,而不是全部重载,该变量就显得非常有用了


补充:

1.setting.py中INSTALLED_APPS 告诉 Django 项目哪些 app 处于激活状态,可以激活对应app下面的模型

2.在app的目录下添加management/commands目录,django就会自动的为commands目录下的每个模块自动注册manage.py命令,可以用python manage.py command_name来调用,具体命令的文件编写格式如下:

#polls/management/commands/closepoll.py 
from django.core.management.base import BaseCommand, CommandError
from example.polls.models import Poll

class Command(BaseCommand):
    args = '<poll_id poll_id ...>'
    help = 'Closes the specified poll for voting'

    def handle(self, *args, **options):
        for poll_id in args:
            try:
                poll = Poll.objects.get(pk=int(poll_id))
            except Poll.DoesNotExist:
                raise CommandError('Poll "%s" does not exist' % poll_id)

            poll.opened = False
            poll.save()

            self.stdout.write('Successfully closed poll "%s"\n' % poll_id)
3.对session的使用:request.session['test'] = 'test',设置;request.session[‘test’]或request.session.get('test',None),获取;session是一个类似于字典的结构;HttpRequest对象中除session以外,其他属性都应该当做只读属性用


这个项目做完以后推出进阶篇.....


1.django模板的html自动转义

在django里默认情况下,每一个模板自动转意每一个变量标签的输出。 尤其是这五个字符。

< 被转意为 &lt; 

> 被转意为 &gt;

 ' (single quote) 被转意为 &#39;

 " (double quote) 被转意为 &quot; 

& 被转意为 &amp;

另外,我强调一下这个行为默认是开启的。 如果你正在使用django的模板系统,那么你是被保护的。

关闭自动转义

对于单独变量:

This will not be escaped: {{ data|safe }}

对于模板, autoescape 标签有两个参数on和off 有时,你可能想阻止一部分自动转意,对另一部分自动转意
Auto-escaping is on by default. Hello {{ name }}

{% autoescape off %}   #默认转义
    This will not be auto-escaped: {{ data }}.

    Nor this: {{ other_data }}
    {% autoescape on %}  #关闭默认转义
        Auto-escaping applies again: {{ name }}
    {% endautoescape %}
{% endautoescape %}



2.配置多个数据库 https://docs.djangoproject.com/en/1.4/topics/db/multi-db/

DATABASES = {
    'default': {
        'NAME': 'app_data',
        'ENGINE': 'django.db.backends.postgresql_psycopg2',
        'USER': 'postgres_user',
        'PASSWORD': 's3krit'
    },
    'users': {
        'NAME': 'user_data',
        'ENGINE': 'django.db.backends.mysql',
        'USER': 'mysql_user',
        'PASSWORD': 'priv4te'
    }
}

$ ./manage.py syncdb --database=users

syncdb会把所有的model都同步到users数据库,所以不一定是我们想要的(可以用router控制入库到user数据库的app)

syncdb也会检索对应app的<appname>/sql/<modelname>.sql(modelname小写),并会在正常syncdb后执行这些sql语句


[dongsong@bogon boosencms]$ vpython manage.py sqlall app_user | vpython manage.py dbshell --database=users
这个会把名为app_user的app下面的model都同步到数据库users(这个是setting.py的DATABASES中定义的数据库key,不是实际数据库的名字)中去

sqlall会把models.py中定义的model都转换成sql语句、同时会把<appname>/sql/<modelname>.sql中的sql语句也打印出来

sqlcustom只打印<appname>/sql/<modelname>.sql中的sql语句

<appname>/sql/<modelname>.sql中的sql语句主要用来对models.py不能做到的东西做补充,比如在models中定义的数据表无法对column设置数据库层面的default value,models.py中定义的default只是django层面的default value,如果不用django程序写库就无法用到默认值;再比如v1.5之前的组合索引(1.5开始可以在meta calss中这是组合索引index_together)

sqlcustom的使用参考https://docs.djangoproject.com/en/dev/ref/django-admin/#sqlcustom-appname-appname(sql文件的名称必须lowercase)


WARNING:在models.py中设置column属性时max_length,null,db_index,premary_key,unique,unique_together这些都是可以通过syncdb等命令作用到数据库层面的,defalt则不行


操作数据表的时候在正常语法中间加上using(dbname)

Author.objects.using('default').all()

3.数据库路由 database router

     1>setting.py的DATABASES加入数据库配置就不说了

      2>创建myapp/myrouter.py文件,并写入如下代码(每个函数的具体含义可看官网说明)

class MyAppRouter(object):
    """A router to control all database operations on models in
    the myapp application"""

    def db_for_read(self, model, **hints):
        "Point all operations on myapp models to 'other'"
        if model._meta.app_label == 'myapp':
            return 'other'
        return None

    def db_for_write(self, model, **hints):
        "Point all operations on myapp models to 'other'"
        if model._meta.app_label == 'myapp':
            return 'other'
        return None

    def allow_relation(self, obj1, obj2, **hints):
        "Allow any relation if a model in myapp is involved"
        if obj1._meta.app_label == 'myapp' or obj2._meta.app_label == 'myapp':
            return True
        return None

    def allow_syncdb(self, db, model):
        "Make sure the myapp app only appears on the 'other' db"
        if db == 'other':
            return model._meta.app_label == 'myapp'
        elif model._meta.app_label == 'myapp':
            return False
        return None
      3>修改setting.py,加入下面这行
DATABASE_ROUTERS = ['myapp.myrouter.MyAppRouter']
      4>为每个model的类添加app标签app_label
class Info(models.Model):
    id = models.IntegerField(primary_key = True)
    name = models.CharField("站", max_length = 100, db_index = True)
    info = models.CharField("板", max_length = 100)
    
    class Meta:
        db_table = 't_info'
        app_label = 'content'
     5>同步数据库,不制定database的时候用的默认default数据库,由路由控制需要在其他数据库创建的数据表会被忽略
vpython manage.py syncdb --database=default
vpython manage.py syncdb --database=content
....
     6>数据表创建完成就可以正式工作了,具体哪些model跟哪些数据库对应,由router决定


     附加:讨论一个问题,如果model的app_label不存在会怎样?

                  a.要想通过syncdb创建数据表就必须保证app_label跟实际存在及setting.py中注册的app名称(INSTALLED_APPS)相对应,可以不等于当前所在app的名字,但必须是存在和注册的app名,否则syncdb的时候会把该model忽略掉(syncdb --database=dbName,django会根据router找跟dbName对应的app,并安装,但是app如果没有注册则失败),结果所有数据库中都找不到该model对应的数据表结构

                 b.而如果所有model的app_label都对应着实际存在的app名,加上数据库路由是由app_label和database_name(setting.py中DATABASES的key)来作控制的,那么就出现了一个问题:每个app_label必须跟同一个数据库对应

                 c.这个也不是什么大问题,一般都满足需求!万一有变态需求呢?好吧,事实上我们可以定义不存在和没注册的app名作为app_label,然后在路由器上根据该app_label来控制其访问哪个数据库,这样我们付出的代价就是a的问题不得不手动创建数据表了....还有一种处理办法是在router根据表名制定更细的规则,只是这样不便于修改(一个installed_app对应一个app_label,一个app_label对应一个database最好控制了)


4.关于自增和联合索引

class SiteBbsInfo(models.Model):
    id = models.AutoField(primary_key=True)
    v1 = models.CharField("v1", max_length = 100, db_index = True)
    v2 = models.CharField("v2", max_length = 100)
    
    class Meta:
        unique_together = ("v1", "v2")
        db_table = 't_v1_v2'
        app_label = 'content'

5.django的DateTimeField列类型指定了auto_now=True结果生成的数据表还是没有默认当前更新时间的性质,google结果只说到如何在django的模型层实现这个功能(下面是两个方案),但是这样在数据库层面还是没有默认当前更新时间的性质,如果用其他程序往该数据表写数据或者更新数据就会出现问题!!!这个问题如何从数据库层面解决呢???!!!(见2标红<---2012.7.17 12:23)

http://stackoverflow.com/questions/1737017/django-auto-now-and-auto-now-add

import datetime

class User(models.Model):
    created     = models.DateTimeField(editable=False)
    modified    = models.DateTimeField()

    def save(self, *args, **kwargs):
        ''' On save, update timestamps '''
        if not self.id:
            self.created = datetime.datetime.today()
        self.modified = datetime.datetime.today()
        super(User, self).save(*args, **kwargs)


http://stackoverflow.com/questions/5899868/django-datetimefield-auto-now-add-not-working

created_datetime = models.DateTimeField(default=datetime.datetime.now)

6.model一些语法

Entry.objects.exclude(pub_date__gt=datetime.date(2005, 1, 3), headline='Hello')
等价于
SELECT ...
WHERE NOT (pub_date > '2005-1-3' AND headline = 'Hello')

Entry.objects.exclude(pub_date__gt=datetime.date(2005, 1, 3)).exclude(headline='Hello')

等价于
SELECT ...
WHERE NOT pub_date > '2005-1-3'
AND NOT headline = 'Hello'

filter的上述用法就不赘述了

对于__get还有其他类似的东东

__gt 大于
__gte 大于等于
__lt 小于
__lte 小于等于

__contains 包含

__startswith 以XX开头


distinct的用法:

Entry.objects.order_by('pub_date').distinct('pub_date')
Entry.objects.order_by('author', 'pub_date').distinct('author', 'pub_date')

values()的用法:

>>> Blog.objects.values()
[{'id': 1, 'name': 'Beatles Blog', 'tagline': 'All the latest Beatles news.'}],
>>> Blog.objects.values('id', 'name')
[{'id': 1, 'name': 'Beatles Blog'}]

count()的用法:

Entry.objects.count()
Entry.objects.filter(headline__contains='Lennon').count()

Avg的用法:无记录时34.35这个值是None

>>> from django.db.models import Avg
>>> Book.objects.all().aggregate(Avg('price'))
{'price__avg': 34.35}


sum()的用法:

from django.db.models import Sum
ModelName.objects.aggregate(Sum('field_name'))

更多类似的用法https://docs.djangoproject.com/en/1.4/ref/models/querysets/


7.django的QuerySet支持以数字索引取值,以及[num1:num2],但是不支持负数索引(不同于list)

>>> snapshots = WomFollowerSnapshot.objects.filter(uid = 2124561663, time__lte = datetime.now()).order_by("time")[0:2]
>>> type(snapshots)
<class 'django.db.models.query.QuerySet'>
>>> snapshots[0]
<WomFollowerSnapshot: WomFollowerSnapshot object>
>>> snapshots[1]
Traceback (most recent call last):
  File "<console>", line 1, in <module>
  File "/home/dongsong/venv/lib/python2.6/site-packages/Django-1.4-py2.6.egg/django/db/models/query.py", line 207, in __getitem__
    return list(qs)[0]
IndexError: list index out of range
>>> snapshots[-1]
Traceback (most recent call last):
  File "<console>", line 1, in <module>
  File "/home/dongsong/venv/lib/python2.6/site-packages/Django-1.4-py2.6.egg/django/db/models/query.py", line 174, in __getitem__
    "Negative indexing is not supported."
AssertionError: Negative indexing is not supported.
>>> snapshots[0:2]
[<WomFollowerSnapshot: WomFollowerSnapshot object>]
>>> len(snapshots)
1
>>> len(snapshots[0:2])
1

8.select xxx from xxx where x in (y,yy,yyy);

result = Test.objects.filter(test_id__in=test_ids)

9.获取表名
XX._meta.db_table

10.如何指定查询某些列?如果全部列都构造出来可能会太占内存、网络,也可能有延时的问题

# This will defer all fields except the headline.
Entry.objects.only("body", "rating").only("headline")

参考: http://stackoverflow.com/questions/7071352/django-objects-values-select-only-some-fields

            https://docs.djangoproject.com/en/dev/ref/models/querysets/#only

   用only返回的对象modelObj,django只从数据查询和构造用only指定的列;如果你用该modelObj取其他列,则django会立即去数据库获取(warning:此时获取的可能是已经被其他进程或者线程修改过的数据哦,要小心)

   用only指定某些列获取值并修改了这些列,save()的时候会把相应的列更新到数据库,其他列不变(不修改、不覆盖);如果修改了only指定以外的列,save()的时候会把only制定的和这些被修改的列都更新到数据库

   更新还可以用这种方式实现:

>>> WomKeyWord.objects.filter(wordId=1).update(wordStr=u"中国人")
1L

11.reverse()方法 参考http://hi.baidu.com/youngvleo/blog/item/755ecf3f177128c07c1e71da.html

views.py

    from django.core.urlresolvers import reverse

    def redirect(request):
    return HttpResponseRedirect(reverse('mysite.polls.views.detail',args=(1,)))
很容易明白,第一个参数就直接添入要使用的view方法,第二个args里边顺序填入方法的参数,(extra_context也从这里传入)然后剩下的就全部交给django去完成拉。于是我们就可以放心的修改url.py里的url配置,不
必再担心有什么地方没修改网站出错啦

说白了,reverse()就是屌丝views的逆袭,从views里面的方法反解url,该函数返回的字符串就是一个url串。用它的好处是修改urls.py里面的url可以不用修改views文件中的HttpResponseRedirect()参数。


12.djang多进程和多线程的问题

     django单进程多线程:每个线程的数据库操作会用不同的连接,如果某进程有60个线程,每个线程都有对同一个数据库的操作,那么该进程会有60个对该数据库的连接(小心mysql最大连接数达到上限)。就测试结果来看,数据库操作结束后(线程还没退出)几分钟,连接会自动断开(说个跟本话题无关的,tmpThread.setDaemon(True)考虑清楚再用,今天线程抛异常就跟这个有关Exception in thread Thread-6 (most likely raised during interpreter shutdown))

    django多进程:如果在某个django的进程里面用multiprocessing创建新的进程,则子进程会继承父进程的数据库连接socket,那么父子进程同时做数据库操作时会出错(数据库socket连接会抛出异常“数据库已不在”/"查询过程中出错")

                                如果在某个django的进程里面用os.popen()或者subprocess.Popen()创建新的django进程(比如启动一个django的command),则,子进程虽然会继承父进程的数据库连接socket,但也会自己构建属于自己的数据库连接(跟从bash下启动进程一样嘛,可以预料到的),不会有上述问题(顺便说一句,subprocess才是正道,什么os.popen()、popen2.*已不是官方倡导的多进程用法;multiprocessing倒不至于被人遗弃,因为它是类似于多线程threading模块的多进程模块,和前面的那些多进程模块适用性不一样)


13.日志

#settings.py
LOGGING = {
    'version': 1,
    'disable_existing_loggers': False,
    'formatters':{
        'simple':{
            'format':'%(threadName)s %(asctime)s %(levelname)s [%(filename)s:%(lineno)d]%(message)s'
        },
    },
    'handlers': {
        'log_to_stdout':{
            'level':'INFO',
            'class':'logging.StreamHandler',
            'formatter':'simple',
        },
    },
    'loggers': {
        'main':{
            'handlers':['log_to_stdout'],
            'level':'INFO',
            'propagate':True,
        }
    }
}

#.../commands/mycommand.py
logger = logging.getLogger('main')
logger.debug("entered %s" % __name__)

14.关于django自动添加的primary key(id, AutoField),如果指定了其他列primary_key = True则不会自动添加这个id列;每个model必须有一个primary_key(这个真是别扭啊)

Each model requires exactly one field to haveprimary_key=True.

15.关于django事务操作

     官方文档https://docs.djangoproject.com/en/1.4/topics/db/transactions/

     两种官方支持的方式:

     1>在MIDDLEWARE_CLASSES中配置中间件TransactionMiddleware,这种基于http服务的request和response决定何时提交(具体见文档,我没细看),对于deamon process不靠谱儿

     2>用装饰器@transaction.commit_on_success、@transaction.commit_manually

    还用一种方式大家应该想到了,直接编写事务的sql语句,通过执行raw sql来实现事务,我要这个!

    sql = '''
    BEGIN;
    INSERT INTO wom_repost_path (retweetedId,uid,provider,parentStatusId,parentUid,childStatusId,childUid) values (1,1,1,1,1,3,1);
    UPDATE wom_repost_report set repostCount = repostCount + 1 where weiboId = 1 and provider = 1 and repostUid = 1; 
    COMMIT;
    '''
    print sql
    from django.db import connections, transaction
    cursor = connections['wom'].cursor()
    cursor.execute(sql)
    #transaction.commit_manually(using = 'wom')


16.或者,OR语法

select * from xx where a = 1 or a = 2;

在django中的实现:

     rts = XX.objects.filter(a = 1) | XX.objects.filter(a = 2)

或者

    from django.db.models import Q

    rts = XX.objects.filter(Q(a = 1) | Q(a = 2))

    或者| 并且& 都可以用


17.QuerySet分析(2013.3.6 14:56)

>>> rts = WomAccount.objects.only('id').filter(provider = 1) #no db operate
>>> type(rts) #no db operate
<class 'django.db.models.query.QuerySet'>
>>> fRts = rts.exclude(id__lt=1000) #no db operate
>>> len(fRts)
#execute SQL:SELECT `wom_account`.`id` FROM `wom_account` WHERE (`wom_account`.`provider` = 1  AND NOT (`wom_account`.`id` < 1000 ))
24176
>>> 
>>> 
>>> rts = WomAccount.objects.only('id').filter(provider = 1) #no db operate
>>> len(rts)
#execute SQL: SELECT `wom_account`.`id` FROM `wom_account` WHERE `wom_account`.`provider` = 1
25175
>>> type(rts) #no db operate
<class 'django.db.models.query.QuerySet'>
>>> fRts = rts.exclude(id__lt=1000) #no db operate
>>> len(fRts)
#execute SQL: SELECT `wom_account`.`id` FROM `wom_account` WHERE (`wom_account`.`provider` = 1  AND NOT (`wom_account`.`id` < 1000 ))
24176
>>> 
>>> rts = WomAccount.objects.only('id').filter(provider = 1)[0:10000] #no db operate
>>> type(rts) #no db operate
<class 'django.db.models.query.QuerySet'>
>>> fRts = rts.exclude(id__lt=1000) #先有了limit语法,再做过滤是不可行的!
Traceback (most recent call last):
  File "<console>", line 1, in <module>
  File "/home/dongsong/venv/lib/python2.6/site-packages/Django-1.4-py2.6.egg/django/db/models/query.py", line 628, in exclude
    return self._filter_or_exclude(True, *args, **kwargs)
  File "/home/dongsong/venv/lib/python2.6/site-packages/Django-1.4-py2.6.egg/django/db/models/query.py", line 633, in _filter_or_exclude
    "Cannot filter a query once a slice has been taken."
AssertionError: Cannot filter a query once a slice has been taken.

18.django记录HTTP响应时间的方法 http://www.morethanseven.net/2011/06/30/Django-performance-1-measuring-performance/

我在项目中选用的是timelog模块,veasy_install django-timelog


19.为apache安装mod_python模块:

鸟人用的第一种方法,这样mod_python貌似(反正我没找到方法)只能使用系统默认路径下的python,真是很不爽呀...第二种方式编译mod_python时可指定使用我自己的python,可惜失败了

sudo yum install mod_python -y
--------------------------------------------------------------------------------------------------
wget http://archive.apache.org/dist/httpd/modpython/mod_python-2.7.10.tgz
tar zvxf mod_python-2.7.10.tgz
sudo yum install httpd-devel -y #安装apxs(apache编译和安装扩展模块的工具,http://httpd.apache.org/docs/2.2/programs/apxs.html)
cd mod_python-2.7.10
./configure --with-apxs=/usr/sbin/apxs --with-python=/home/dongsong/venv/bin/
make #报错!!还是yum install mod_python比较方便!
make install


20.部署Django程序到运行mod_python的apache环境:

参考:https://docs.djangoproject.com/en/1.4/howto/deployment/modpython/

    1>告诉apache要加载mod_python模块(mod_python 是一个 Apache 模块,它将对 Python 编程语言的支持集成到 Web 服务器中。与用传统的 CGI 方法执行 Python 脚本相比,这种方法要快得多),在httpd.conf或/var/etc/httpd/conf.d/python.conf中添加:

LoadModule python_module modules/mod_python.so
    2>告诉apache讲我们的Django程序关联到那个URL,在httpd.conf或者python.conf中添加:(如需要使用virtualenv下的python环境,可参考 http://blog.csdn.net/xiarendeniao/article/details/6774520item47)
<Location "/apps/">
    SetHandler python-program
    PythonHandler django.core.handlers.modpython
    SetEnv DJANGO_SETTINGS_MODULE boosencms.settings
    PythonPath "['/var/www/html/apps/','/var/www/html/apps/boosencms/'] + sys.path"
    PythonDebug On
</Location>

<LocationMatch "\.(png|gif|jpg|mov|mp3|avi|wav)$">
    SetHandler None
</LocationMatch>

Location是url匹配,<Location "/apps/">表示只要url请求符合/apps/就用mod_python来处理,同一台机器上的不同virtualhost只要url符合这个规则其url请求都会交由mod_python来处理,就算某个virtualhost的root目录下没有apps目录也是这样

那么就会有个问题:如果我们在同一台机器上起了多个virtual host,一个指定8088端口、root路径是/var/www/html/,另一个指定9000端口、root路径是/var/www/app/,那么"http://localhost:8088/apps/"和"http://localhost:9000/apps/"请求是等效的,都交由mod_python处理去了。如果我们实际要做的是只对9000端口来的请求交由/var/www/app/apps下面的django程序处理呢?答案是Direcctor!

Directory是本地目录匹配,上述配置改成<Directory "/var/www/app/apps/">就可以把针对”/var/www/app/apps“的访问交给mod_python来处理!这时候请求"http://localhost:8088/apps/"则要看对应root目录/var/www/html/下面是否有apps了,没有就是非法访问!

所以在

    3>告诉apache不对媒体文件使用mod_python,在httpd.conf或python.conf中添加:

<LocationMatch "\.(png|gif|jpg|mov|mp3|avi|wav)$">
    SetHandler None
</LocationMatch>
    4>重启httpd


21.部署Django程序到共享Web宿主环境(httpd.conf不可修改;使用执行FastCGI程序的Web服务器衍生进程):

参考:http://www.ibm.com/developerworks/cn/opensource/os-django/index.html

    1>创建.htaccess文件,并放到Django程序所在目录
cat .htaccess
AddHandler fastcgi-script .fcgi
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^(.*)$ testproject.fcgi/$1 [QSA,L]
    2>创建Python脚本(与前述RewriteRule配置的文件名相同)告诉Apache我们Django项目的不同设置并执行FastCGI程序。
cat testproject.fcgi
#!/usr/bin/python
import sys, os
sys.path.insert(0, "/home/joelennon/python")
os.environ['DJANGO_SETTINGS_MODULE'] = "testproject.settings"
from django.core.servers.fastcgi import runfastcgi
runfastcgi(method="threaded", daemonize="false")

    3>chmod 755 testproject.fcgi 或者 用FTP客户端修改文件属性(如不能通过shell访问服务器)

    4>每次更改程序代码之后都需要更改该fcgi文件的时间戳,告诉apache应用程序已经更新,然后它会重启Django程序。


22.部署Django程序到运行mod_wsgi的apache环境:

参考:http://www.51know.info/system_base/django_wsgi.htmlhttps://docs.djangoproject.com/en/1.4/howto/deployment/wsgi/modwsgi/

 

[root@localhost conf.d]# cat wsgi.conf 
LoadModule wsgi_module modules/mod_wsgi.so

WSGIScriptAlias / "/var/www/html/apps/wsgi.py"

<Directory "/var/www/html/apps">
        Order Deny,Allow
        Allow from all
</Directory>

[dongsong@localhost boosencms]$ cat wsgi.py 
# -*- coding: utf-8 -*-
import os
import sys
os.environ['DJANGO_SETTINGS_MODULE'] = 'settings'
os.environ['PYTHON_EGG_CACHE'] = '/tmp/.python-eggs'
current_dir = os.path.dirname(__file__)
if current_dir not in sys.path: sys.path.append(current_dir)
parent_dir = '/home/dongsong/boosencms/src/'
if parent_dir not in sys.path: sys.path.append(parent_dir)
activate_this = '/home/dongsong/venv/bin/activate_this.py'
execfile(activate_this, dict(__file__=activate_this))  
import django.core.handlers.wsgi
application = django.core.handlers.wsgi.WSGIHandler()


23. model.save()貌似会触发两次sql操作,一个SELECT (1) AS `a` FROM a_table where provimaryId  = xx; 一个update a_table set ...; 这个如何规避?

如果model的实例设置了有效的主键值,save会先查数据库该主键对应记录是否存在,是就update,否就insert

如果model的实例没有设置有效的主键值,save会直接insert

save的参数force_insert就是直接insert;save的参数force_update是直接根据主键update

record.save(force_update=True)的前提是record的primary_key列有值

>>> rt.save(force_update=True)
Traceback (most recent call last):
  File "<console>", line 1, in <module>
  File "/home/dongsong/venv/lib/python2.6/site-packages/Django-1.4-py2.6.egg/django/db/models/base.py", line 463, in save
    self.save_base(using=using, force_insert=force_insert, force_update=force_update)
  File "/home/dongsong/venv/lib/python2.6/site-packages/Django-1.4-py2.6.egg/django/db/models/base.py", line 545, in save_base
    raise ValueError("Cannot force an update in save() with no primary key.")
ValueError: Cannot force an update in save() with no primary key.

24.settings.py中设置DEBUG = True,同时logging的级别设置为logging.DEBUG则每次数据库操作都会打印到日志里面(sql+args+time)

25.用django给其他应用提供http数据接口,当收到post请求的时候会返回403错误,原因为请求方没有提供csrf_token,解决办法是对views.py中对应的方法添加@csrf_exempt装饰(记得要 from django.views.decorators.csrf import csrf_exempt)

参考:http://stackoverflow.com/questions/6800894/django-returns-403-error-when-sending-a-post-request

你可能感兴趣的:(数据库,Date,django,python,database)