Django Form and Modelform Admin定義 高級查詢)

Django的form表單通常具備兩種功能css

1. 驗證輸入html

2.輸入HTML前端

---------模板-----------
from django import forms
class BookForm(forms.Form):
    name = forms.CharField(max_length=10)
    publish_date = forms.DateField()

-------視圖-----------
def forms(request):
    Forms = form_models.BookForm()
    if request.method == 'POST':
        print(request.POST)
        Forms = form_models.BookForm(request.POST)
        if Forms.is_valid():
            print("form is ok")
            form_data = Forms.cleaned_data
            print('form1---',form_data)
            form_data['publisher_id'] = request.POST.get('publisher_id')
            print('form2---',form_data)
            book_obj = models.Book(**form_data)
            book_obj.save()
        else:
            print(Forms.errors)
    publisher_list = models.Publisher.objects.all()
    return render(request,'formspage/forms.html',{'forms':Forms,
                                                  "publishers":publisher_list})
--------------html------------
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<form action="" method="post">{% csrf_token %}
{{ forms }}
<select name="publisher_id">
    {% for publisher in publishers %}
        <option value="{{ publisher.id }}">{{ publisher.name }}</option>
    {% endfor %} }}
</select>
<input type="submit" value="submit">
</form>
</body>
</html>
簡單Form實例

-----增長複雜度python

#!/usr/bin/env python
# -*- coding:utf-8 -*-
import re
from django import forms
from django.core.exceptions import ValidationError


def mobile_validate(value):
    mobile_re = re.compile(r'^(13[0-9]|15[012356789]|17[678]|18[0-9]|14[57])[0-9]{8}$')
    if not mobile_re.match(value):
        raise ValidationError('手機號碼格式錯誤')


class PublishForm(forms.Form):

    user_type_choice = (
        (0, u'普通用戶'),
        (1, u'高級用戶'),
    )

    user_type = forms.IntegerField(widget=forms.widgets.Select(choices=user_type_choice,
                                                                  attrs={'class': "form-control"}))

    title = forms.CharField(max_length=20,
                            min_length=5,
                            error_messages={'required': u'標題不能爲空',
                                            'min_length': u'標題最少爲5個字符',
                                            'max_length': u'標題最多爲20個字符'},
                            widget=forms.TextInput(attrs={'class': "form-control",
                                                          'placeholder': u'標題5-20個字符'}))

    memo = forms.CharField(required=False,
                           max_length=256,
                           widget=forms.widgets.Textarea(attrs={'class': "form-control no-radius", 'placeholder': u'詳細描述', 'rows': 3}))

    phone = forms.CharField(validators=[mobile_validate, ],
                            error_messages={'required': u'手機不能爲空'},
                            widget=forms.TextInput(attrs={'class': "form-control",
                                                          'placeholder': u'手機號碼'}))

    email = forms.EmailField(required=False,
                            error_messages={'required': u'郵箱不能爲空','invalid': u'郵箱格式錯誤'},
                            widget=forms.TextInput(attrs={'class': "form-control", 'placeholder': u'郵箱'}))

'''
def __init__(self, *args, **kwargs):
    super(SampleImportForm, self).__init__(*args, **kwargs)

    self.fields['idc'].widget.choices = models.IDC.objects.all().order_by('id').values_list('id','display')
    self.fields['business_unit'].widget.choices = models.BusinessUnit.objects.all().order_by('id').values_list('id','name')

Forms
'''

先寫好一個form
先寫好一個Form
def test_form_view(request):
    if request.method == 'POST':
        request_form = PublishForm(request.POST)
        if request_form.is_valid():
            request_dict = request_form.clean()
            print(request_dict)
        return render(request,'test.html', {'pub_form':request_form})
    else:
        pub_form = PublishForm()
        return render(request,'test.html',{'pub_form':pub_form})

寫好視圖
寫好視圖
<div>
    <form method="post" action="{% url 'test_form' %}">{% csrf_token %}

        <div>{{ pub_form.user_type }} {{ pub_form.errors.title }}</div>
        <div>{{ pub_form.title }}</div>
        <div>{{ pub_form.email }}</div>
        <div>{{ pub_form.phone }}</div>
        <div>{{ pub_form.memo }}</div>


        {% if pub_form.errors %}
            {{ pub_form.errors }}
        {% endif %}
        <input type="submit" value="提交">
    </form>

</div>

模版文件
模板文件

擴展:ModelFormgit

在使用Model和Form時,都須要對字段進行定義並指定類型,經過ModelForm則能夠省去From中字段的定義sql

class ModelForm(forms.ModelForm):
    class Meta:
        model = models.Book
        # fields = ('name','publish_date') #選擇指定關聯字段在前端顯示
        exclude = ()# 若是不指定選擇顯示的字段,必須指定exclude ,選擇不顯示的字段 空表示無
        widgets = {
            'name':forms.TextInput(attrs={'class':"form_control"}), # name字段加樣式
        }
Modelform模型文件
def book_modelform(request):
    form = form_models.ModelForm()
    print(form)
    if request.method == "POST":
        print(request.POST)
        form = form_models.ModelForm(request.POST)
        if form.is_valid():
            print("form is ok")
            form.save()
    print(form.errors)
    return render(request,'formspage/modelform.html',{"forms":form})
Model視圖
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <style>
        .form_control{
            background-color: blue;
        }
    </style>
</head>
<body>
<form action="" method="post">{% csrf_token %}
<div>
    {% for ele in forms %}
        <div class="form-ele">
            <label style="width: 100px ;float: left">{{ ele.name }}</label>
            <label>{{ ele }}{{ ele.errors }}</label>
        </div>
    {% endfor %}
</div>
<input type="submit" value="submit">
</form>
</body>
</html>
模板文件

Django Admin定製數據庫

django amdin是django提供的一個後臺管理頁面,改管理頁面提供完善的html和css,使得你在經過Model建立完數據庫表以後,就能夠對數據進行增刪改查,而使用django admin 則須要如下步驟:express

  • 建立後臺管理員
  • 配置url
  • 註冊和配置django admin後臺管理頁面

一、建立後臺管理員django

python manage.py createsuperuser

二、配置後臺管理urlapp

url(r'^admin/', include(admin.site.urls))

三、註冊和配置django admin後臺頁面

a、在admin中執行以下配置

from django.contrib import admin
   
from books import models
admin.site.register(models.UserType) 
admin.site.register(models.UserInfo)
admin.site.register(models.UserGroup)
admin.site.register(models.Asset)

b、設置數據表名稱

class Author(models.Model):
    name = models.CharField(max_length=50)
    email = models.EmailField()
    class Meta:
        verbose_name = '認證名字'#verbose_name的意思很簡單,就是給你的模型類起一個更可讀的名字
        verbose_name_plural = '認證名字'#若是不指定Django會自動在模型名稱後加一個’s’

 

c、定製自定義顯示字段

rom django.contrib import admin

class entry(admin.ModelAdmin):
    list_display = ('headline','body_text','pub_date','mod_date','n_comments','n_pingbacks')#自定義顯示字段
# Register your models here.
from blog import models
admin.site.register(models.Blog)
admin.site.register(models.Author)
admin.site.register(models.Entry,entry)

d、添加頁面搜索過濾等功能

#admin 定製功能
class BookAdmin(admin.ModelAdmin):
    list_display = ('id','name','publisher','publish_date','status','colored_status') #顯示的字段信息,# 注: 不能顯示多對多字段
    search_fields = ('name','publisher__name',) #添加搜索框
    list_filter = ('publisher','publish_date',) # 過濾功能
    list_editable = ('name','publish_date',) # 前端可直接修改的字段
    list_per_page = 10 #每頁內容
    filter_horizontal = ('authors',) # 針對多對多的水平篩選搜索
    raw_id_fields = ('publisher',) #搜索外鍵
    actions = [make_forbidden,] # d定製admin action
# Register your models here.
from books import models
admin.site.register(models.Author)
admin.site.register(models.Publisher)
admin.site.register(models.Book,BookAdmin) #BookAdmin 是將本身寫的類做爲參數封裝到註冊admin

經常使用ORM操做

from django.db import models

class Blog(models.Model):
    name = models.CharField(max_length=100)
    tagline = models.TextField()

    def __str__(self):              # __unicode__ on Python 2
        return self.name

class Author(models.Model):
    name = models.CharField(max_length=50)
    email = models.EmailField()

    def __str__(self):              # __unicode__ on Python 2
        return self.name

class Entry(models.Model):
    blog = models.ForeignKey(Blog)
    headline = models.CharField(max_length=255)
    body_text = models.TextField()
    pub_date = models.DateField()
    mod_date = models.DateField()
    authors = models.ManyToManyField(Author)
    n_comments = models.IntegerField()
    n_pingbacks = models.IntegerField()
    rating = models.IntegerField()

    def __str__(self):              # __unicode__ on Python 2
        return self.headline

示例models
事例模板

我的示例代碼

# 建立一個py腳原本來方便調試增刪改查
import os
from django.db.models import F,Q,Count,Sum,Avg,Min,Max
os.environ['DJANGO_SETTINGS_MODULE']='day16.settings' #將setting模板加入環境變量
import django # 導入django
django.setup()
from blog import models
 # foreignkey關聯
# entry = models.Entry.objects.get(pk=1) # 查詢主鍵爲1
# print(entry.blog)
# blog = models.Blog.objects.get(id=2)
# print(blog)
# entry.blog = blog
# entry.save()

 # manytomany關聯
# NZ = models.Author.objects.create(name='小哪吒')
# LH = models.Author.objects.create(name='老虎')
# entry.authors.add(NZ,LH)

# 單表內查詢語句鏈式查詢
#all_entries = Entry.objects.all() #查詢全部
# Entry.objects.filter(pub_date__year=2006) #查詢全部pub_date爲2006年的紀錄
# Entry.objects.all().filter(pub_date__year=2006) #與上面那句同樣
# >>> Entry.objects.filter(   #鏈式查詢
# ...     headline__startswith='What'
# ... ).exclude(
# ...     pub_date__gte=datetime.date.today()
# ... ).filter(
# ...     pub_date__gte=datetime(2005, 1, 30)
# ... )
#
# one_entry = Entry.objects.get(pk=1) #單條查詢
#
# Entry.objects.all()[:5] #查詢前5條
# Entry.objects.all()[5:10] #查詢第五條-第十條
#
# Entry.objects.order_by('headline')[0] #按headline排序取第一條
#obj = models.Entry.objects.get(blog__name__contains='生活') 查找出blog字段中對應的外鍵Blog name=生活的板塊
# Entry.objects.filter(pub_date__lte='2006-01-01') #至關於sql語句SELECT * FROM blog_entry WHERE pub_date <= '2006-01-01';
#
# Entry.objects.get(headline__exact="Cat bites dog") #至關於SELECT ... WHERE headline = 'Cat bites dog';
# Blog.objects.get(name__iexact="beatles blog") #與上面相同,只是大小寫不敏感
#
# Entry.objects.get(headline__contains='Lennon') #至關 於SELECT ... WHERE headline LIKE '%Lennon%';
#


# objs = models.Entry.objects.filter(n_comments__lte=F('n_pingbacks'))
# print(objs)
# addblog = models.Blog.objects.create(name='python')
objs = models.Entry.objects.filter(Q(mod_date=('2016-05-21')) and Q(n_comments__lt=F('n_pingbacks')) | Q(pub_date__lt='2016-05-17'))
print(objs)
# print(models.Entry.objects.all().aggregate(Avg('n_pingbacks'),
#                                            Sum('n_pingbacks'),
#                                            Min('n_pingbacks')
#                                            ))
# print('=============================')
from books import models as book_models
# pub_obj = book_models.Publisher.objects.first()
# print(pub_obj.name,pub_obj.book_set.select_related())# 反向關聯查詢 #book_set是反向關聯自動生成的一個字段
# print("=================================")
pub_objs = book_models.Publisher.objects.annotate(book_nums=Count('book')) #分類聚合
for publisher in pub_objs:
    print(publisher.book_nums)
我的示例代碼

 

處理帶外鍵關聯或多對多關聯的對象 

>>> from blog.models import Entry
>>> entry = Entry.objects.get(pk=1)
>>> cheese_blog = Blog.objects.get(name="Cheddar Talk")
>>> entry.blog = cheese_blog
>>> entry.save()

ManyToManyField關聯

NZ = models.Author.objects.create(name='小哪吒')
LH = models.Author.objects.create(name='老虎')
entry.authors.add(NZ,LH)

單表內查詢語句鏈式查詢

all_entries = Entry.objects.all() #查詢全部
Entry.objects.filter(pub_date__year=2006) #查詢全部pub_date爲2006年的紀錄
Entry.objects.all().filter(pub_date__year=2006) #與上面那句同樣
>>> Entry.objects.filter(   #鏈式查詢
...     headline__startswith='What'
... ).exclude(
...     pub_date__gte=datetime.date.today()
... ).filter(
...     pub_date__gte=datetime(2005, 1, 30)
... )

one_entry = Entry.objects.get(pk=1) #單條查詢

Entry.objects.all()[:5] #查詢前5條
Entry.objects.all()[5:10] #查詢第五條-第十條

Entry.objects.order_by('headline')[0] #按headline排序取第一條
obj = models.Entry.objects.get(blog__name__contains='生活') 查找出blog字段中對應的外鍵Blog name=生活的板塊
Entry.objects.filter(pub_date__lte='2006-01-01') #至關於sql語句SELECT * FROM blog_entry WHERE pub_date <= '2006-01-01';

Entry.objects.get(headline__exact="Cat bites dog") #至關於SELECT ... WHERE headline = 'Cat bites dog';
Blog.objects.get(name__iexact="beatles blog") #與上面相同,只是大小寫不敏感

Entry.objects.get(headline__contains='Lennon') #至關 於SELECT ... WHERE headline LIKE '%Lennon%';

關聯查詢

#This example retrieves all Entry objects with a Blog whose name is 'Beatles Blog':
Entry.objects.filter(blog__name='Beatles Blog')

Blog.objects.filter(entry__headline__contains='Lennon')

對同一表內不一樣的字段進行對比查詢,In the examples given so far, we have constructed filters that compare the value of a model field with a constant. But what if you want to compare the value of a model field with another field on the same model?

Django provides expressions to allow such comparisons. Instances of F() act as a reference to a model field within a query. These references can then be used in query filters to compare the values of two different fields on the same model instance.

For example, to find a list of all blog entries that have had more comments than pingbacks, we construct an F() object to reference the pingback count, and use that F() object in the query:

>>> from django.db.models import F
>>> Entry.objects.filter(n_comments__gt=F('n_pingbacks'))

Django supports the use of addition, subtraction, multiplication, division, modulo, and power arithmetic with F() objects, both with constants and with other F() objects. To find all the blog entries with more than twice as many comments as pingbacks, we modify the query:

>>> Entry.objects.filter(n_comments__gt=F('n_pingbacks') * 2)

To find all the entries where the rating of the entry is less than the sum of the pingback count and comment count, we would issue the query:

>>> Entry.objects.filter(rating__lt=F('n_comments') + F('n_pingbacks'))

For date and date/time fields, you can add or subtract a timedelta object. The following would return all entries that were modified more than 3 days after they were published:

>>> from datetime import timedelta
>>> Entry.objects.filter(mod_date__gt=F('pub_date') + timedelta(days=3))

Caching and QuerySets

Each QuerySet contains a cache to minimize database access. Understanding how it works will allow you to write the most efficient code.

In a newly created QuerySet, the cache is empty. The first time a QuerySet is evaluated – and, hence, a database query happens – Django saves the query results in the QuerySet’s cache and returns the results that have been explicitly requested (e.g., the next element, if the QuerySet is being iterated over). Subsequent evaluations of the QuerySet reuse the cached results.

Keep this caching behavior in mind, because it may bite you if you don’t use your QuerySets correctly. For example, the following will create two QuerySets, evaluate them, and throw them away:

>>> print([e.headline for e in Entry.objects.all()])
>>> print([e.pub_date for e in Entry.objects.all()])

That means the same database query will be executed twice, effectively doubling your database load. Also, there’s a possibility the two lists may not include the same database records, because an Entry may have been added or deleted in the split second between the two requests.

To avoid this problem, simply save the QuerySet and reuse it:

>>> queryset = Entry.objects.all()
>>> print([p.headline for p in queryset]) # Evaluate the query set.
>>> print([p.pub_date for p in queryset]) # Re-use the cache from the evaluation.

When QuerySets are not cached

Querysets do not always cache their results. When evaluating only part of the queryset, the cache is checked, but if it is not populated then the items returned by the subsequent query are not cached. Specifically, this means that limiting the querysetusing an array slice or an index will not populate the cache.

For example, repeatedly getting a certain index in a queryset object will query the database each time:

>>> queryset = Entry.objects.all()
>>> print queryset[5] # Queries the database
>>> print queryset[5] # Queries the database again

However, if the entire queryset has already been evaluated, the cache will be checked instead:

>>> queryset = Entry.objects.all()
>>> [entry for entry in queryset] # Queries the database
>>> print queryset[5] # Uses cache
>>> print queryset[5] # Uses cache

Complex lookups with Q objects(複雜查詢)

Keyword argument queries – in filter(), etc. – are 「AND」ed together. If you need to execute more complex queries (for example, queries with OR statements), you can use objects.

object (django.db.models.Q) is an object used to encapsulate a collection of keyword arguments. These keyword arguments are specified as in 「Field lookups」 above.

For example, this Q object encapsulates a single LIKE query:

from django.db.models import Q
Q(question__startswith='What')

Q objects can be combined using the & and | operators. When an operator is used on two Q objects, it yields a new Q object.

For example, this statement yields a single Q object that represents the 「OR」 of two "question__startswith" queries:

Q(question__startswith='Who') | Q(question__startswith='What')

This is equivalent to the following SQL WHERE clause:

WHERE question LIKE 'Who%' OR question LIKE 'What%'

You can compose statements of arbitrary complexity by combining Q objects with the & and | operators and use parenthetical grouping. Also, Q objects can be negated using the ~ operator, allowing for combined lookups that combine both a normal query and a negated (NOT) query:

Q(question__startswith='Who') | ~Q(pub_date__year=2005)

Each lookup function that takes keyword-arguments (e.g. filter()exclude()get()) can also be passed one or more Qobjects as positional (not-named) arguments. If you provide multiple Q object arguments to a lookup function, the arguments will be 「AND」ed together. For example:

Poll.objects.get(
    Q(question__startswith='Who'),
    Q(pub_date=date(2005, 5, 2)) | Q(pub_date=date(2005, 5, 6))
)

... roughly translates into the SQL:

SELECT * from polls WHERE question LIKE 'Who%'
    AND (pub_date = '2005-05-02' OR pub_date = '2005-05-06')

Lookup functions can mix the use of Q objects and keyword arguments. All arguments provided to a lookup function (be they keyword arguments or Q objects) are 「AND」ed together. However, if a Q object is provided, it must precede the definition of any keyword arguments. For example:

Poll.objects.get(
    Q(pub_date=date(2005, 5, 2)) | Q(pub_date=date(2005, 5, 6)),
    question__startswith='Who')

... would be a valid query, equivalent to the previous example; but:

# INVALID QUERY
Poll.objects.get(
    question__startswith='Who',
    Q(pub_date=date(2005, 5, 2)) | Q(pub_date=date(2005, 5, 6)))

更新 

Updating multiple objects at once

# Update all the headlines with pub_date in 2007.
Entry.objects.filter(pub_date__year=2007).update(headline='Everything is the same')

在原有數據的基礎上批量自增

Calls to update can also use expressions to update one field based on the value of another field in the model. This is especially useful for incrementing counters based upon their current value. For example, to increment the pingback count for every entry in the blog:

>>> Entry.objects.all().update(n_pingbacks=F('n_pingbacks') + 1)

However, unlike F() objects in filter and exclude clauses, you can’t introduce joins when you use F() objects in an update – you can only reference fields local to the model being updated. If you attempt to introduce a join with an F() object, a FieldErrorwill be raised:

# THIS WILL RAISE A FieldError
>>> Entry.objects.update(headline=F('blog__name'))

Aggregation(聚合)

from django.db import models

class Author(models.Model):
    name = models.CharField(max_length=100)
    age = models.IntegerField()

class Publisher(models.Model):
    name = models.CharField(max_length=300)
    num_awards = models.IntegerField()

class Book(models.Model):
    name = models.CharField(max_length=300)
    pages = models.IntegerField()
    price = models.DecimalField(max_digits=10, decimal_places=2)
    rating = models.FloatField()
    authors = models.ManyToManyField(Author)
    publisher = models.ForeignKey(Publisher)
    pubdate = models.DateField()

class Store(models.Model):
    name = models.CharField(max_length=300)
    books = models.ManyToManyField(Book)
    registered_users = models.PositiveIntegerField()

示例models
示例模板
# Total number of books.
>>> Book.objects.count()

# Total number of books with publisher=BaloneyPress
>>> Book.objects.filter(publisher__name='BaloneyPress').count()

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

# Max price across all books.
>>> from django.db.models import Max
>>> Book.objects.all().aggregate(Max('price'))
{'price__max': Decimal('81.20')}

# Cost per page
>>> Book.objects.all().aggregate(
...    price_per_page=Sum(F('price')/F('pages'), output_field=FloatField()))
{'price_per_page': 0.4470664529184653}

# All the following queries involve traversing the Book<->Publisher
# foreign key relationship backwards.

# Each publisher, each with a count of books as a "num_books" attribute.
>>> from django.db.models import Count
>>> pubs = Publisher.objects.annotate(num_books=Count('book'))
>>> pubs
[<Publisher BaloneyPress>, <Publisher SalamiPress>, ...]
>>> pubs[0].num_books

# The top 5 publishers, in order by number of books.
>>> pubs = Publisher.objects.annotate(num_books=Count('book')).order_by('-num_books')[:5]
>>> pubs[0].num_books

經常使用聚合場景需求
經常使用聚合場景需求

更多聚合查詢例子:https://docs.djangoproject.com/en/1.9/topics/db/aggregation/ 

用戶認證 

 

from django.contrib.auth import authenticate
user = authenticate(username='john', password='secret')
if user is not None:
    # the password verified for the user
    if user.is_active:
        print("User is valid, active and authenticated")
    else:
        print("The password is valid, but the account has been disabled!")
else:
    # the authentication system was unable to verify the username and password
    print("The username and password were incorrect.")

How to log a user out

from django.contrib.auth import logout
 
def logout_view(request):
    logout(request)
    # Redirect to a success page.
相關文章
相關標籤/搜索