django學習總結

tips:django官方中文文檔(http://python.usyiyi.cn/django/index.html),django基礎教程(http://www.ziqiangxuetang.com/django/django-tutorial.html)html

1、關於django

  django是一個python中的web框架,若是想更好的使用它,最好還能有HTML, CSS, JavaScript等方面的知識。它的特色主要體如今幾個方面:強大的數據庫(具備許多api同時支持執行sql語句)、自帶強大的後臺功能、利用正則表達式匹配網址(簡化網頁管理)、模板與視圖一一對應、緩存機制、國際化支持等等。前端

  django適合於敏捷開發,只須要少許代碼便可創建高性能web應用。因其已經完成了開發網站的許多常見代碼,因此減小了代碼的重複度。Ok,讓咱們首先看下django的主要文件組成。主要文件包括以下幾個py文件:node

django工程主要py文件
文件 功能
urls.py 網址入口,關聯到views中對於的函數
models.py 與數據庫操做相關,創建應用數據模型
views.py 處理用戶發出請求,從urls中對應過來,經過渲染templates中網頁顯示內容
settings.py 相關設置,包括數據庫設置,郵件設置,靜態文件配置等
forms.py 表單,用戶在瀏覽器端提交的表單數據類
admin.py 後臺代碼,大部分已完成

2、經常使用命令

  環境搭建這一部分就不做敘述,網上教程不少。經常使用命令以下:python

 1 #新建django project
 2 django-admin.py startproject project-name
 3 #新建django app命令
 4 django-admin.py startapp app-name (or) python manage.py startapp app-name
 5 #同步數據庫
 6 python manage.py syncdb
 7 #(django1.7.1及以上版本須要使用如下命令)
 8 python manage.py makemigrations
 9 python manage.py migrate
10 #運行django項目,不加port默認爲8000
11 python manage.py runserver port
12 #ex: python manage.py runserver 8080
13 #清空數據庫
14 python manage.py flush
15 #建立超級管理員
16 python manage.py createsuperuser
17 #修改管理員密碼
18 python manage.py changepassword username
19 #導出數據
20 python manage.py dumpdata appname > appname.json
21 #導入數據
22 python manage.py loaddata appname.json
23 #進入django項目命令終端
24 python manage.py shell
25 #進入數據庫命令行
26 python manage.py dbshell

3、視圖

  咱們已經知道views中的函數是與urls中的網址對應的,接下來咱們作一個簡單的實例演示。mysql

1. 首先將應用名稱添加到settings.py中git

INSTALLED_APPS = (
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'newReverse',
    'reverse',
)

2. 在views中定義視圖函數github

def test(request):
    return render(request, 'test.html')

這裏返回的結果有多種,其本質返回的結果是HttpResponse。其餘返回狀況如web

return HttpResponse("hello world")
return render_to_response('test.html', '')
return HttpResponseRedirect('/index/')

其中render與render_to_respose是同樣的,只是render不須要說明ResponseContext而render_to_respose則須要coding出來。render,最後會返回一個字典,以向模板中傳遞數據。ajax

return render_to_response('checkmt.html', {'info': info})
return render(request, 'day2.html', {'info': info})

3. 設置在urls.py中的地址正則表達式

urlpatterns = patterns('',
    url(r'^admin/', include(admin.site.urls)),
    url(r'^login/$', login),
    url(r'^index/$', views.index, name="index"),   
)

這裏urls設置有多種方式,具體能夠查看官方文檔,其主要包括兩部分,正則表達式格式的網址+views函數。同時網址中還能夠傳遞參數。

4、模板

  模板是經過views函數渲染的,其實質是一個html網頁。通常放在app下的templates中,加載模板時django會自動尋找。那麼假如一個工程中有多個應用,每一個應用的templates中都有一個index.html,而後直接調用render(request, 'index.html')能不能找到呢?答案是可能會出錯。讓咱們來探究下django模板查找機制。django模板查找過程是在每一個app的templates文件夾中查找(而不是當前app中的templates),當在這些應用的templates文件夾列表中查找到index.html模板時中止,因此說可能出現錯誤;若是最終沒有找到則返回一個templates not found錯誤。

  接下來咱們來介紹一下關於模板代碼的應用。通常地,網站中都會有一些模板設計,即不少網頁都有不少相同的部分(如導航、底部、時間等),這時就能夠用使用模板來減小代碼重複度了。如假設有一個base.html

 1 <!DOCTYPE html>
 2 <html>
 3 <head>
 4     <title>{% block title %}默認標題{% endblock %} - 自強學堂</title>
 5 </head>
 6 <body>
 7  
 8 {% include 'nav.html' %}
 9  
10 {% block content %}
11 <div>這裏是默認內容,全部繼承自這個模板的,若是不覆蓋就顯示這裏的默認內容。</div>
12 {% endblock %}
13  
14 {% include 'bottom.html' %}
15  
16 {% include 'tongji.html' %}
17  
18 </body>
19 </html>

block就是模板能夠重寫的部分,include即包含其餘文件內容,因此咱們就能夠設計以下index.html

1 {% extends 'base.html' %}
2  
3 {% block title %}歡迎光臨首頁{% endblock %}
4  
5 {% block content %}
6 {% include 'ad.html' %}
7 歡迎光臨
8 {% endblock %}

django模板還提供了用於處理傳遞過來的字典數據的技術,如循環、條件判斷、過濾器、經常使用標籤等。以下就是這些技術的一些相關應用。

<!-- 雙重循環加載表格數據, if判斷輸出什麼數據-->
        <table border="1">
            <tr>
                <td>會議室\時間</td>
                {%for each in info.time%}
                <td>{{each}}</td>
                {%endfor%}
            </tr>
            {% for each in info.rvsdest %}
            <tr>
                <td>{{each.mtrname}}</td>
                {% for ev in each.time%}
                {% if ev == 1%} <td>NO</td> {%else%} <td></td> {%endif%}
                {% endfor%}
            </tr>
            {% endfor%}
        </table>

其餘的諸如(==, !=, >=, <=, >, <, and, or, not, in, not in)等也能夠在模板中使用。

5、數據模型

  Django模型與數據庫相關,其相關代碼通常寫在models.py中。django支持的數據庫包括sqlite3,mysql,PostgreSQL等,只需在settings.py中配置便可,同時數據模型提供了豐富的api。以下便可settings.py的配置樣例。

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.mysql',
        'NAME': 'reverse',
        'USER': 'root',
        'PASSWORD': '******',
        'HOST': '127.0.0.1',
        'PORT': '3306',
    }
}

1. 關於數據模型,首先咱們來介紹下field,以下爲一個model實例

 1 class RoomReverse(models.Model):
 2     mtno = models.IntegerField(default=0)
 3     STATE_CHOICES = (('st', 'stale'), ('ing', 'underway'), ('ns', 'notstart'), )
 4     state = models.CharField(max_length=20, choices=STATE_CHOICES, default='ns')
 5     rvstime = models.DateTimeField(auto_now_add=True)
 6     mtdate = models.CharField(max_length=100, default=None)
 7     mtrno = models.ForeignKey(Meetingroom)
 8     emails = models.TextField(default=None)
 9     rpemail = models.EmailField(default=None)
10     class Meta:
11         table_name = 'RoomReverse'
12     def __getstr__():
13         return str(mtno)

其中包括的field有CharField、DateTimeField、IntegerField、TextField、ForeignKey、EmailField等等,其能夠實現數據庫的主鍵設置、外鍵設置,還能實現一對多、多對1、多對多設置等。另外一方面,若是以爲django自帶的field不夠用,還可使用本身定義的field。

2. 接下來咱們來介紹下關於數據庫的一些操做。首先是將數據模型同步到數據庫操做,命令以下:

1 python manage.py syncdb
2 #(django1.7.1及以上版本須要使用如下命令)
3 python manage.py makemigrations
4 python manage.py migrate

3. 對數據進行增刪改查操做,通常的方法有:

#新建對象
User.objects.create(name=name,pwd=pwd) #1
#處理重複,是否建立
User.objects.get_or_create(name=name,pwd=pwd)
#用save建立
us = User(name=name,pwd=pwd)
us.save()
#批量建立
User.objects.bulk_create(user_object_list)
User.objects.all()#獲取所有對象
User.objects.all()[:10]#切片操做
User.objects.get(name=name1)#獲取單個數據,第一個查找到的數據
User.objects.filter(name=name1)#=User.objects.filter(name_exact=name1)#獲取多個數據
User.objects.filter(name__iexact="abc")#不區分大小寫
User.objects.filter(name__contains="abc")#name包含abc
User.objects.filter(name__icontains="abc")#name不包含abc,且不區分大小寫
User.objects.filter(name__regex="^abc")#正則表達式查詢
User.objects.filter(name__iregex="^abc")#正則表達式不區分大小寫
User.objects.exclude(name__contains="abc")#排除包含abc的對象
User.objects.filter(name__contains="abc").exclude(pwd=111)#name等於abc但pwd不等於111的對象
User.objects.filter(name__in=[])#至關於將全部name在列表中的對象提取出來

 4. 對django中的數據模型,存在一些內部方法來設置或修改模型屬性值

model._meta.get_fields()    #獲取全部屬性
model._meta.get_field_by_name('id')    #按屬性名獲取屬性
model._meta.get_all_field_names()    #獲取模型全部屬性名稱
object.__setattr__(attr, data)    #按屬性名設置模型對象對應的屬性值
getattr(model, attr)    #獲取模型某一列屬性

5. 在模型對象中還能夠設置虛類來實現繼承方法

 1 class BaseInfo(models.Model):
 2     '''
 3     模板基本信息,包括建立時間、更新時間、更新人、操做人,爲虛類
 4     '''
 5     create_time = models.DateTimeField(auto_now_add=True)
 6     update_time = models.DateTimeField(auto_now=True)
 7     ISVALID = ((CHECKING, 0), (VALID, 1), (INVALID, 2))
 8     valid = models.IntegerField(choices=ISVALID, default=CHECKING)
 9     creator = models.CharField(max_length=30, default=None)
10     operator = models.CharField(max_length=30, default=None)
11     class Meta:
12         abstract = True
13 
14 
15 # 單個節點
16 class NodeData(BaseInfo):
17     id = models.AutoField(verbose_name='配置id', primary_key=True, auto_created=True)
18     script = models.CharField(verbose_name='中文簡述', max_length=50, default=None)
19     category = models.CharField(verbose_name='類別', max_length=30, default=None)
20     ensuper_class = models.CharField(verbose_name='實體父類', max_length=30, default=None)
21     evsuper_class = models.CharField(verbose_name='事件父類', max_length=30, default=None)
22     prsuper_class = models.CharField(verbose_name='屬性父類', max_length=30, default=None)
23     roleid = models.CharField(verbose_name='角色宿主', max_length=30, default=None)
24     define_area = models.CharField(verbose_name='定義域', max_length=50, default=None)
25     value_area = models.CharField(verbose_name='值域', max_length=50, default=None)
26     location_area = models.CharField(verbose_name='位置域', max_length=50, default=None)
27     statement = models.CharField(verbose_name='聲明', max_length=50, default=None)
28     illustrate = models.CharField(verbose_name='舉例', max_length=50, default=None)
29     combination = models.CharField(verbose_name='中文簡述 + 類別', max_length=80, default=None, unique=True)
30 
31     class Meta(BaseInfo.Meta):
32         # managed = True
33         db_table = 'node_data'
34 
35     def toJSON(self):
36         fields = []
37         for field in self._meta.fields:
38             fields.append(field.name)
39         d = {}
40         for attr in fields:
41             if isinstance(getattr(self, attr), datetime.datetime):
42                 d[attr] = getattr(self, attr).strftime('%Y-%m-%d %H:%M:%S')
43             elif isinstance(getattr(self, attr), datetime.date):
44                 d[attr] = getattr(self, attr).strftime('%Y-%m-%d')
45             else:
46                 d[attr] = getattr(self, attr)
47         return json.dumps(d)
View Code

6、基於CBS編程

Class-based views是Django爲解決建站過程當中的常見的呈現模式而創建的。具備以下幾個原則:

  • 代碼越少越好
  • 永遠不要重複代碼
  • View應當只包含呈現邏輯, 不該包括業務邏輯
  • 保持view邏輯清晰簡單
  • 不要將CBVs用做403, 404, 500的錯誤處理程序
  • 保持mixin簡單明瞭

1. 使用django自身的cbvs

    cbvs是可擴展的,但在也增長了複雜度,有時甚至出現8個import引入關係。django自帶的view以下表所示:

 

類名 功能 例子
View 基本View, 能夠在任什麼時候候使用 見後面詳細介紹
RedirectView 從新定向到其餘URL 將訪問"/log-in/"的用戶從新定向到"/login/"
TemplateView 顯示Django HTML template 通常網站中使用模板顯示的頁
ListView 顯示對象列表 文章列表頁
DetailView 顯示對象詳情 文章詳細頁
FormView 提交From 網站聯繫咱們或emai訂閱form
CreateView 建立對象 建立新文章頁
UpdateView 更新對象 修改文章頁
DeleteView 刪除對象 刪除文章頁
Generic date views 顯示一段時間內的對象 按時間歸類的博客

2. View中基本元素

 1 class ModelCreatView(CreateView):
 2     def __init__(self, model, template_name, context_object_name, success_url, success_msg, fields):
 3         """
 4         初始化函數,這裏以creatview爲例,其餘view大同小異
 5         :param model:  對應要操做的模型
 6         :param template_name: 對應的模板名稱,通常爲html頁面
 7         :param context_object_name: 返回給前臺的對象
 8         :param success_url: 操做成功定向地址
 9         :param success_msg: 返回的成功信息
10         :param fields: 須要操做的對應的模型中的屬性
11         """
12         self.model = model 
13         self.template_name = template_name
14         self.context_object_name = context_object_name
15         self.success_url = success_url
16         self.success_msg = success_msg
17         self.fields = fields
18     # 
19     # self.model = MODEL
20     # self.fields = ['event_attribute', 'role_attribute', 'entiry_value', 'event_type', 'direction_flag', 'unique_flag',
21     #                'appear_flag']
22     # self.context_object_name = 'knowledgeGraph'
23     # self.success_url = '/knowledgeGraph/'
24     # self.template_name = 'knowledge_graph/add.html'
View Code

3. ListView簡介

      listview是一個展現列表的view,返回的是一個template,包含兩個關鍵方法:

def get_context_data(self, **kwargs):
def get_queryset(self):

      第一個方法返回一個字典給前端,包括分頁信息,列表信息,已經其餘自定義的信息;第二個方法返回數據庫中獲取到的數據(可能通過條件迭代),具體實現的實例代碼以下:

 1     def get_context_data(self, **kwargs):
 2         """
 3         用來獲取返回給前端頁面的dict數據,前端頁面可直接經過應用dict中的key來獲取value
 4         :param kwargs:
 5         :return: context,一個字典類型的數據
 6         """
 7         try:
 8             context = super(ModelListView, self).get_context_data(**kwargs)
 9             log.debug("get_context_data")
10             page_obj = context['page_obj']
11             pages = []
12             for i in range(1, page_obj.paginator.num_pages + 1):
13                 if i == 1 or i == page_obj.paginator.num_pages:
14                     pages.append(i)
15                 elif i >= page_obj.number - 2 and i <= page_obj.number + 2:
16                     pages.append(i)
17                 elif pages[-1] != None:
18                     pages.append(None)
19                 else:
20                     pass
21             context['pages'] = pages
22             context['order_type'] = self.order_type
23             context['length'] = len(self.object_list)
24             if 'pagination_num' not in context:
25                 context['pagination_num'] = self.paginate_by
26             self.echo_search(context)
27             if self.model == NodeData:
28                 context['tree'] = self.get_tree()
29             return context
View Code

4. Mixin實現

     view中若是以爲自帶的post、get方法不夠好,也能夠重寫post、get方法,這樣就與函數式編程沒有什麼區別。有時須要先後端異步方式加載數據,就須要使用ajax來完成,這時就可使用mixin來解決。

     使用mixin能夠爲class提供額外的功能,但它自身卻不能單獨使用的類. 在具備多繼承能力的編程語言中, mixin能夠爲類增長額外功能或方法. 在Django中, 咱們可使用mixin爲CBVs提供更多的擴展性, 固然在類繼承過程當中, 咱們推薦如下原則:

  • Django自身提供的View永遠在最右邊
  • mixin依次在以上view的左邊
  • mixin永遠繼承自Python的object類型
  • 推薦mixin庫django-braces
class ModelValidView(LoginRequiredMixin, AjaxResponseMixin, View):
    def __init__(self, model):
        self.model = model
    def post_ajax(self, request, *args, **kwargs):
        pass

7、文件上傳下載

django中文件上傳通常是將文件拷本到服務器上,而後訪問服務器上數據;下載文件則能夠直接經過訪問url完成。

1. 文件上傳:

前端:

 1 {% include "./_meta.html" %}
 2 {% load staticfiles %}
 3 
 4 
 5 </head>
 6 <body>
 7 <article class="page-container">
 8         <form action="{% url 'freedomSegger_fileupload' %}" method="post" class="form form-horizontal" id="form-admin-role-add" enctype="multipart/form-data">{% csrf_token %}
 9                 <div class="row cl">
10                         <label class="form-label col-xs-4 col-sm-3">模板下載:</label>
11                         <div class="formControls col-xs-8 col-sm-9">
12                                 <a href="TODO">點我下載</a>
13                         </div>
14                 </div>
15                 <div class="row cl">
16                         <label class="form-label col-xs-4 col-sm-3"><span class="c-red">*</span>上傳文件:</label>
17                         <div class="formControls col-xs-8 col-sm-9">
18                                 <input type="file" class="input-text"  name="file">
19                         </div>
20                 </div>
21                 <div class="row cl">
22                         <div class="col-xs-8 col-sm-9 col-xs-offset-4 col-sm-offset-3">
23                                 <button  type="submit" class="btn btn-success radius" id="admin-role-save" name="admin-role-save"><i class="icon-ok"></i> 肯定</button>
24                         </div>
25                 </div>
26         </form>
27 </article>
28 
29 {% include "./_footer.html" %}
30 
31 </body>
32 </html>
View Code

後臺:

1)工具方法:

 1 def handle_uploaded_file(f):
 2     """
 3     將上傳的文件寫入服務器對應目錄下
 4     :param f: 上傳文件
 5     :return: 
 6     """
 7     file_name = ""
 8     try:
 9         path = "uplodfile" + time.strftime('/%Y/%m/%d/%H/%M/%S/')
10         if not os.path.exists(path):
11             os.makedirs(path)
12             file_name = path + f.name
13             destination = open(file_name, 'wb+')
14             for chunk in f.chunks():
15                 destination.write(chunk)
16             destination.close()
17     except Exception, e:
18         print e
19     return file_name
View Code

2)加載上傳頁面

1 @login_required
2 def tofileUpload(request):
3     return render(request, "knowledge_graph/file_upload.html", )
View Code

3)上傳文件並存入數據庫中

 1 @login_required
 2 def fileUpload(request):
 3     success_url = '/knowledgeGraph/'
 4     failed_url = '/knowledgeGraph/toFileUpload'
 5     return common_file_upload(request, save_data, success_url, failed_url, MODEL)
 6 
 7 def common_file_upload(request, save_data, success_url, failed_url, MODEL):
 8     """
 9     批量導入文件
10     :param request:
11     :param save_data: 針對每一個model,在對應的view文件中自定義
12     :param success_url: 導入成功時返回的url
13     :param failed_url: 導入失敗時返回的url
14     :param MODEL: 對應的模型
15     :return: 返回對應的頁面
16     """
17     file_path = file_upload.handle_uploaded_file(request.FILES['file'])
18     try:
19         text = list(set(open(file_path).readlines()))
20     except Exception as e:
21         log.error(MODEL._meta.object_name + " 文件打開錯誤"+str(e))
22         messages.info(request, "文件打開錯誤"+str(e))
23         return HttpResponseRedirect(failed_url)
24     except_info, failed = save_data(text, request)
25     if failed == 0:
26         messages.success(request,"400")
27         messages.info(request, "導入成功")
28         log.info(MODEL._meta.object_name + " 文件上傳成功")
29         return HttpResponseRedirect(success_url)
30     else:
31         log.warning(MODEL._meta.object_name + " " + except_info)
32         messages.info(request, except_info)
33         return HttpResponseRedirect(failed_url)
View Code

4)url設置

1     # toFileUpload
2     url(r'^knowledgeGraph/toFileUpload/$', knowledge_graph.tofileUpload, name="knowledgeGraph_to_fileupload"),
3     # FileUpload
4     url(r'^knowledgeGraph/FileUpload/$', knowledge_graph.fileUpload, name="knowledgeGraph_fileupload"),
View Code

2. 文件下載:

文件下載可經過直接的url訪問而後返回response完成,注意此時不能使用ajax異步操做。

1)下載單個文件:

 1 def download_file(request,data):
 2     try:
 3         write_model(data)
 4         file_name = "/".join(str(os.path.dirname(__file__)).replace("\\", "/").split("/")[0:-2]) + "/download/" + data
 5         wrapper = FileWrapper(file(file_name))
 6         response = HttpResponse(wrapper, content_type="application/octet-stream")
 7         response['Content-Length'] = os.path.getsize(file_name)
 8         response['Content-Disposition'] = 'attachment;filename=%s'% data
 9         messages.info(request, "下載成功")
10         log.info("下載成功")
11         return response
12     except Exception as e:
13         messages.warning(request, "下載失敗 " + str(e))
14         log.warning("下載失敗 " + str(e))
15         return HttpResponseRedirect("/index/")
View Code

2)下載多個文件,此時通常狀況下使用zip下載,或者使用服務器推送服務(並不知道怎麼實現)

這種方法是網上能夠輕鬆找到,可是我實現的時候每次下載的zip包大小都是0kb,經過調試,猜想應該是臨時文件問題,沒法把臨時文件放入壓縮包內,致使壓縮包大小爲空。

 1 def download_zipfile(request,data):
 2 
 3     try:
 4         write_model(model="KnowledgeGraph")
 5         temp = tempfile.TemporaryFile()
 6         archive = zipfile.ZipFile(temp, mode='w')
 7         dir_name = "/".join(str(os.path.dirname(__file__)).replace("\\", "/").split("/")[0:-2]) + "/download/"
 8         filelist = []
 9         for root, dirlist, files in os.walk(dir_name):
10             for filename in files:
11                 filelist.append(os.path.join(root, filename))
12         for eachfile in filelist:
13             destfile = eachfile[len(dir_name):]
14             print "Zip file %s..." % destfile
15             archive.write(eachfile, destfile)
16         archive.close()
17         wrapper = FileWrapper(temp)
18         response = http.HttpResponse(wrapper, content_type='application/x-zip-compressed')
19         response['Content-Disposition'] = 'attachment; filename=model.zip'
20         response['Content-Length'] = temp.tell()
21         print temp.tell()
22         temp.seek(0)
23         return response
24     except Exception as e:
25         print e
26         messages.info(request, "下載失敗")
27         return HttpResponseRedirect("/index/")
View Code

第二種方法成功實現壓縮包下載,這種方法是在github上找到,供參考:

 1 def download_zipfile(request,data):
 2     try:
 3         dir_name = "/".join(str(os.path.dirname(__file__)).replace("\\", "/").split("/")[0:-2]) + "/download/"
 4         files = []
 5         for ev in data:
 6             input_file = dir_name + ev
 7             text = open(input_file).readlines()
 8             #建立臨時文件
 9             output_file = tempfile.NamedTemporaryFile(mode='w+b', prefix='base', suffix='.txt', delete=False)
10             #output_file = tempfile.NamedTemporaryFile(mode='w+b', prefix='editor', suffix='.xml', delete=False)
11             output_file.writelines(text)
12             files.append(output_file.name)
13             output_file.close()
14         zip_filename = "model.zip"
15         s = StringIO.StringIO()
16         zf = zipfile.ZipFile(s, "a")
17         #將臨時文件加入zip包
18         for i in range(0, len(files)):
19             #設置文件名
20             zip_path = os.path.join(data[i])
21             zf.write(files[i], zip_path)
22         zf.close()
23         response = HttpResponse(s.getvalue(), content_type="application/x-zip-compressed")
24         response['Content-Disposition'] = 'attachment; filename=%s' % zip_filename
25         messages.info(request, "下載成功")
26         log.info("下載成功")
27         return response
28     except Exception as e:
29         messages.warning(request, "下載失敗 " + str(e))
30         log.warning("下載失敗 " + str(e))
31         return HttpResponseRedirect("/index/")
View Code
相關文章
相關標籤/搜索