Day24-ModelForm操做及驗證

Day23內容回顧--缺失,遺憾成狗。html

 

一:Model(2個功能)前端

  -數據庫操做;python

  -驗證,只有一個clean方法能夠做爲鉤子。正則表達式

 

二:Form(專門來作驗證的)--------根據form裏面寫的類,類裏面有字段,這個字段是內置的正則表達式。數據庫

 

  例如:-class LoginForm(Form): email=fields.EmailField()django

  -is_valid(觸發驗證功能) ->每個字段進行正則(用的是字段內置的正則)+clean_字段 -> clean(__all__) -> _post_clean。json

      form的鉤子,先進行每個字段正則表達式驗證,而後每個字段的方法,而後進行clean,clean完了之後是post cleanapp

 

      email的錯誤信息放在email [大列表裏面了], 總體的錯誤信息放在了 __all__  裏面了。函數

  -cleaned_datapost

  -error

建議分開使用上面的兩個模塊:Model+Form,這樣能夠下降耦合。可是代碼有重複。

 

Day24:  環境搭建,參考http://www.cnblogs.com/momo8238/p/7508677.html

一,基於form來作。

建立2張表備用,2張表之間用ForeignKey進行關聯:

models.py

from django.db import models

# Create your models here.
class UserType(models.Model):
    caption=models.CharField(max_length=32)

class UserInfo(models.Model):
    username = models.CharField(max_length=32)
    email=models.EmailField()
    user_type=models.ForeignKey(to='UserType',to_field='id')

 建立

python manage.py makemigrations
python manage.py migrate

 

2. 若是我想在index.html頁面上對UserInfo表進行操做,那麼應該把UserInfo 表中的全部信息從後臺傳送過來。把全部的字段從新建立一遍。

用Form方法的話,須要本身寫field字段。 用ModelForm的話,字段是本身從類裏面提取過來的。

views.py

# Create your views here. 用Form方式實現
from django.shortcuts import render
from django import forms
from django.forms import fields
from app01 import models


class UserInfoForm(forms.Form):
    username = fields.CharField(max_length=32)
    email=fields.EmailField()
    user_type=fields.ChoiceField(
        choices=models.UserType.objects.values_list('id','caption')
        #forms下面是用field字段來進行驗證的。forms下面沒有foreignKey字段,只有choicefield,而後經過choices把另一張表裏面的內容都關聯過來。在頁面上把用戶類型做爲一個列表展現出來
    )


def index(request):
    obj=UserInfoForm()
    return render(request,'index.html',{'obj':obj})

 

index.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
        {% csrf_token %}
        {{obj.as_p}}
</body>
</html>

 運行效果:

 

3. 讓user_type每一次都作更新操做,須要重構函數

說明見下圖:

 

 

 

具體說明能夠參考day23

   def __init__(self,*args,**kwargs):
        super(UserInfoForm,self).__init__(*args,**kwargs)
        self.fields['user_type'].choices=models.UserType.objects.values_list('id','caption')

 

 

4. 完善index.html函數,用form表單提交

{% csrf_token %} 密文顯示
{{csrf_token }} 在前端頁面生成字符串
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    <form action="/index/" method="POST">
        {% csrf_token %}
        {{obj.as_p}}
        <input type="submit" value="提交"/>
    </form>
</body>
</html>

 頁面效果:

 

5. 一點提交,數據就傳到了後臺。

obj.is_valid() #是否經過驗證
obj.cleaned_data() #全部的正確信息
obj.errors() #全部的錯誤信息
models.UserInfo.objects.create(**obj.cleaned_data) #若是數據正確,則建立。是字典格式。
models.UserInfo.objects.filter(id=1).update(**obj.cleaned_data) #找到主鍵後自動更新

程序粘貼:

views.py
# Create your views here. 用Form方式實現
from django.shortcuts import render
from django import forms
from django.forms import fields
from app01 import models


class UserInfoForm(forms.Form):
    username = fields.CharField(max_length=32)
    email=fields.EmailField()
    #user_type=fields.ForeignKey(to='UserType',to_field='id') fields中沒有foreignkey
    user_type=fields.ChoiceField(
        choices=models.UserType.objects.values_list('id','caption')
        #在頁面上把用戶類型做爲一個列表展現出來
    )

    def __init__(self,*args,**kwargs):
        super(UserInfoForm,self).__init__(*args,**kwargs)
        self.fields['user_type'].choices=models.UserType.objects.values_list('id','caption')

def index(request):
    if request.method=='GET':
        obj=UserInfoForm()
        return render(request,'index.html',{'obj':obj})
    elif request.method=='POST':
        obj=UserInfoForm(request.POST)
        obj.is_valid()
        obj.cleaned_data()
        obj.errors()
        #models.UserInfo.objects.create(**obj.cleaned_data)
        #models.UserInfo.objects.filter(id=1).update(**obj.cleaned_data)
        return render(request, 'index.html', {'obj': obj})

index.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    <form action="/index/" method="POST">
        {% csrf_token %}
        {{obj.as_p}}
        <input type="submit" value="提交"/>
    </form>
</body>
</html>

 models.py

from django.db import models

# Create your models here.
class UserType(models.Model):
    caption=models.CharField(max_length=32)

class UserInfo(models.Model):
    username = models.CharField(verbose_name='用戶名',max_length=32)
    email=models.EmailField()
    user_type=models.ForeignKey(to='UserType',to_field='id')

 urls.py

from django.conf.urls import url
from django.contrib import admin
from app01 import views

urlpatterns = [
    url(r'^admin/', admin.site.urls),
    url(r'^index/', views.index),
]

 

 

二,基於ModelForm來作。

1. class UserInfoModelForm(forms.ModelForm): 它也能幫咱們自動生成HTML標籤。



views.py
# 基於ModelForm方式來實現
from django.shortcuts import render
from app01 import models

from django import forms
from django.forms import fields

class UserInfoModelForm(forms.ModelForm):
    class Meta:
        model=models.UserInfo  #指去哪一個類裏面去獲取字段。
        fields='__all__'       #代指的是全部的field字段
        #fields=['username']   #還能夠是一個列表,能夠選擇要展現哪幾列,只展現username這一列
        #exclude=['username']   #把username列排除在外了。

def index(request):
    if request.method=='GET':
        obj=UserInfoModelForm()
        return render(request,'index.html',{'obj':obj})
    elif request.method=='POST':
        obj=UserInfoModelForm(request.POST)
        return render(request, 'index.html', {'obj': obj})

  效果:




2.用Form時,字段是本身定義的。因此若是想顯示中文的話,用label標籤就能夠了。

views.py
# 基於Form方式來實現
from django.shortcuts import render
from django import forms
from django.forms import fields
from app01 import models


class UserInfoForm(forms.Form):
    username = fields.CharField(max_length=32,label='用戶名')
    email=fields.EmailField()
    #user_type=fields.ForeignKey(to='UserType',to_field='id') fields中沒有foreignkey
    user_type=fields.ChoiceField(
        choices=models.UserType.objects.values_list('id','caption')
        #在頁面上把用戶類型做爲一個列表展現出來
    )

    def __init__(self,*args,**kwargs):
        super(UserInfoForm,self).__init__(*args,**kwargs)
        self.fields['user_type'].choices=models.UserType.objects.values_list('id','caption')

def index(request):
    if request.method=='GET':
        obj=UserInfoForm()
        return render(request,'index.html',{'obj':obj})
    elif request.method=='POST':
        obj=UserInfoForm(request.POST)
        obj.is_valid()
        obj.cleaned_data()
        obj.errors()
        #models.UserInfo.objects.create(**obj.cleaned_data)
        #models.UserInfo.objects.filter(id=1).update(**obj.cleaned_data)
        return render(request, 'index.html', {'obj': obj})
效果以下:

 


用ModelForm時,前端頁面中的字段是從相關聯的類裏面直接提取過來的,二者之間有耦合。本身不用再寫了。




若是想要顯示中文字段名的話,須要verbose_name='用戶'

效果:



3.
model=models.UserInfo  #指去哪一個類裏面去獲取字段,之後也能夠作增刪改查。
fields='__all__'       #代指的是全部的field字段 
fields=['username'] #還能夠是一個列表,能夠選擇要展現哪幾列,只展現username這一列
exclude=['username'] #把username列排除在外了。

效果展現1:

 

效果展現2:

 

4. 往UserType裏面寫一條數據備用:

 

用form方法的時候,驗證功能的函數實際上是寫在BaseForm裏的:UserInfoForm-->繼承了Form--->繼承了BaseForm(is_valid......)

點擊提交的時候,modelform也能夠作驗證。UserInfoModelForm-->繼承了ModelForm--->繼承了BaseModelForm--->繼承了BaseForm(is_valid......)

UserInfoModelForm下面也應該有obj.is_valid(), obj.cleaned_data, obj.errors 等方法。

ModelForm 作驗證的時候與Form方法是同樣的。

效果1:

 

效果2:

 

三,程序粘貼:

1. 基於form方法的views.py

# 基於Form方式來實現
from django.shortcuts import render
from django import forms
from django.forms import fields
from app01 import models


class UserInfoForm(forms.Form):
    username = fields.CharField(max_length=32,label='用戶名')
    email=fields.EmailField()
    #user_type=fields.ForeignKey(to='UserType',to_field='id') fields中沒有foreignkey
    user_type=fields.ChoiceField(
        choices=models.UserType.objects.values_list('id','caption')
        #在頁面上把用戶類型做爲一個列表展現出來
    )

    def __init__(self,*args,**kwargs):
        super(UserInfoForm,self).__init__(*args,**kwargs)
        self.fields['user_type'].choices=models.UserType.objects.values_list('id','caption')

def index(request):
    if request.method=='GET':
        obj=UserInfoForm()
        return render(request,'index.html',{'obj':obj})
    elif request.method=='POST':
        obj=UserInfoForm(request.POST)
        obj.is_valid()
        obj.cleaned_data()
        obj.errors()
        #models.UserInfo.objects.create(**obj.cleaned_data)
        #models.UserInfo.objects.filter(id=1).update(**obj.cleaned_data)
        return render(request, 'index.html', {'obj': obj})

 

2. 基於modelform方法的views.py

# 基於ModelForm方式來實現
from django.shortcuts import render,HttpResponse
from app01 import models

from django import forms
from django.forms import fields

def orm(request):
    #models.UserType.objects.create(caption='Alex')
    return HttpResponse('orm')

class UserInfoModelForm(forms.ModelForm):
    class Meta:
        model=models.UserInfo  #指去哪一個類裏面去獲取字段,之後也能夠作增刪改查。
        fields='__all__'       #代指的是全部的field字段
        #fields=['username']   #還能夠是一個列表,能夠選擇要展現哪幾列,只展現username這一列
        #exclude=['username']   #把username列排除在外了。

class UserInfoForm(forms.Form):
    username = fields.CharField(max_length=32)
    email=fields.EmailField()
    #user_type=fields.ForeignKey(to='UserType',to_field='id')
    user_type=fields.ChoiceField(
        choices=models.UserType.objects.values_list('id','caption')
    )

    def __init__(self,*args,**kwargs):
        super(UserInfoForm,self).__init__(*args,**kwargs)
        self.fields['user_type'].choices=models.UserType.objects.values_list('id','caption')

def index(request):
    if request.method=='GET':
        obj=UserInfoModelForm()
        return render(request,'index.html',{'obj':obj})
    elif request.method=='POST':
        obj=UserInfoModelForm(request.POST)
        print(obj.is_valid())
        print(obj.cleaned_data)
        print(obj.errors)
        return render(request, 'index.html', {'obj': obj})

 

3.index.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    <form action="/index/" method="POST">
        {% csrf_token %}
        {{obj.as_p}}
        <input type="submit" value="提交"/>
    </form>
</body>
</html>

 

4.models.py

from django.db import models

# Create your models here.
class UserType(models.Model):
    caption=models.CharField(max_length=32)

class UserInfo(models.Model):
    username = models.CharField(verbose_name='用戶',max_length=32)
    email=models.EmailField()
    user_type=models.ForeignKey(to='UserType',to_field='id')

 5.urls.py

from django.conf.urls import url
from django.contrib import admin
from app01 import views

urlpatterns = [
    url(r'^admin/', admin.site.urls),
    url(r'^index/', views.index),
    url(r'^orm/', views.orm),
]

 

四,Django之ModelForm組件

 

4.1 labels=None,                     # 提示信息

若是不想在Models原表中寫verbose_name的話,能夠在定義類的時候在ModelForm中寫提示信息。

原來的效果:

 

如今也能夠在modelform中寫提示信息:labels是個字典格式,能夠寫多個。

 

 

4.2  help_texts=None,                 # 幫助提示信息

 

4.3 widgets=None,                    # 自定義插件以及樣式。

 

 

4.4 錯誤信息 error_messages=None,             # 自定義錯誤信息(總體錯誤信息from django.core.exceptions import NON_FIELD_ERRORS)

 

前端:

後臺收集的錯誤信息:

 

 

錯誤信息的顯示:

 

總體的錯誤信息也能夠在這裏用一樣的方法定義,用的是__all__:{  }。 每一項的錯誤信息應該放到一個字典中。

 

 

 

4.5  field_classes=None               # 自定義字段類 (也能夠自定義字段)

我想把郵箱格式的正則表達式改成url的格式進行驗證。

 

 

# 基於ModelForm方式來實現
from django.shortcuts import render,HttpResponse
from app01 import models
from django import forms
from django.forms import fields as Ffields
from django.forms import widgets as Fwidgets
def orm(request):
    #models.UserType.objects.create(caption='Alex')
    return HttpResponse('orm')

class UserInfoModelForm(forms.ModelForm):
    class Meta:
        model=models.UserInfo  #指去哪一個類裏面去獲取字段,之後也能夠作增刪改查。
        fields='__all__'       #代指的是全部的field字段
        #fields=['username']   #還能夠是一個列表,能夠選擇要展現哪幾列,只展現username這一列
        #exclude=['username']   #把username列排除在外了。
        #labels={'username':'請填入用戶名'}
        #help_texts={'username':'請把你的名字寫對'}
        #widgets={'username':Fwidgets.Textarea(attrs={'class':'c1'})}
        error_messages={
            '__all__':{},
            'email':{
                'required':'郵箱不能爲空',
                'invalid':'郵箱格式錯誤',
            }
        }
        field_classes={
            'email':Ffields.URLField  #這裏只能填類,不能加括號,加上括號就變成對象了。
        }
class UserInfoForm(forms.Form):
    username = Ffields.CharField(max_length=32)
    email=Ffields.EmailField()
    #user_type=fields.ForeignKey(to='UserType',to_field='id')
    user_type=Ffields.ChoiceField(
        choices=models.UserType.objects.values_list('id','caption')
    )

    def __init__(self,*args,**kwargs):
        super(UserInfoForm,self).__init__(*args,**kwargs)
        self.fields['user_type'].choices=models.UserType.objects.values_list('id','caption')

def index(request):
    if request.method=='GET':
        obj=UserInfoModelForm()
        return render(request,'index.html',{'obj':obj})
    elif request.method=='POST':
        obj=UserInfoModelForm(request.POST)
        print(obj.is_valid())
        print(obj.cleaned_data)
        print(obj.errors.as_json())
        return render(request, 'index.html', {'obj': obj})

 效果:

 

 4.6 把時間本地化的時候,須要在setting裏面進行一下當前時區的設置。

             localized_fields = ( 'birth_date' ,) # 本地化,如:根據不一樣時區顯示數據
             如:
                 數據庫中
                     2016 - 12 - 27 04 : 10 : 57
                 setting中的配置
                     TIME_ZONE = 'Asia/Shanghai'
                     USE_TZ = True
                 則顯示:
                     2016 - 12 - 27 12 : 10 : 57

   

4.7 切記 class Meta裏面最容易犯的錯誤就是加逗號。千萬不要加逗號

 

 

ModelForm的全部字段

    a.  class Meta:

            model,                           # 對應Model的哪一個類,哪張表。

            fields=None,                     # 字段

            exclude=None,                    # 排除字段

            labels=None,                     # 提示信息

            help_texts=None,                 # 幫助提示信息

            widgets=None,                    # 自定義插件

            error_messages=None,             # 自定義錯誤信息(總體錯誤信息from django.core.exceptions import NON_FIELD_ERRORS)

            field_classes=None               # 自定義字段類 (也能夠自定義字段)

            localized_fields=('birth_date',) # 本地化,如:根據不一樣時區顯示數據

            如:

                數據庫中

                    2016-12-27 04:10:57

                setting中的配置

                    TIME_ZONE = 'Asia/Shanghai'

                    USE_TZ = True

                則顯示:

                    2016-12-27 12:10:57

    b. 驗證執行過程

        is_valid -> full_clean -> 鉤子 -> 總體錯誤

 

    c. 字典字段驗證

        def clean_字段名(self):

            # 能夠拋出異常

            # from django.core.exceptions import ValidationError

            return "新值"

    d. 用於驗證

        model_form_obj = XXOOModelForm()

        model_form_obj.is_valid()

        model_form_obj.errors.as_json()

        model_form_obj.clean()

        model_form_obj.cleaned_data

    e. 用於建立

        model_form_obj = XXOOModelForm(request.POST)

        #### 頁面顯示,並提交 #####

        # 默認保存多對多

            obj = form.save(commit=True)

        # 不作任何操做,內部定義 save_m2m(用於保存多對多)

            obj = form.save(commit=False)

            obj.save()      # 保存單表信息

            obj.save_m2m()  # 保存關聯多對多信息

 

    f. 用於更新和初始化

        obj = model.tb.objects.get(id=1)

        model_form_obj = XXOOModelForm(request.POST,instance=obj)

        ...

 

        PS: 單純初始化

            model_form_obj = XXOOModelForm(initial={...})

 

五  第一個省事的地方是不用寫字段了。第二個省事的地方是驗證經過之後,用save方式就能夠直接添加到數據庫中了。

程序:

 

效果:

 

六,再新建一張表,作多對多的示例。

 

6.1 models.py

from django.db import models

class UserType(models.Model):
    caption=models.CharField(max_length=32)

class UserGroup(models.Model):
    name=models.CharField(max_length=32)

class UserInfo(models.Model):
    #username = models.CharField(verbose_name='用戶',max_length=32)
    username = models.CharField(max_length=32)
    email=models.EmailField()
    user_type=models.ForeignKey(to='UserType',to_field='id')
    u2g=models.ManyToManyField(UserGroup)

 在usergroup表中新建幾條數據

def orm(request):
    models.UserGroup.objects.create(name='CEO')
    models.UserGroup.objects.create(name='CFO')
    models.UserGroup.objects.create(name='COO')
    return HttpResponse('orm')

 以下:

 

頁面效果:發現多對多也顯示出來了。

 

6.2 頁面上新建而後保存數據

點擊提交,就保存到數據庫表中了。

多對多表中數據也增長了。

 

這個save的功能太強大了。

 

 

6.3 views.py

# 基於ModelForm方式來實現
from django.shortcuts import render,HttpResponse
from app01 import models
from django import forms
from django.forms import fields as Ffields
from django.forms import widgets as Fwidgets
def orm(request):
    #models.UserGroup.objects.create(name='CEO')
    #models.UserGroup.objects.create(name='CFO')
    #models.UserGroup.objects.create(name='COO')
    return HttpResponse('orm')

class UserInfoModelForm(forms.ModelForm):
    class Meta:
        model=models.UserInfo  #指去哪一個類裏面去獲取字段,之後也能夠作增刪改查。
        fields='__all__'       #代指的是全部的field字段
        #fields=['username']   #還能夠是一個列表,能夠選擇要展現哪幾列,只展現username這一列
        #exclude=['username']   #把username列排除在外了。
        #labels={'username':'請填入用戶名'}
        #help_texts={'username':'請把你的名字寫對'}
        #widgets={'username':Fwidgets.Textarea(attrs={'class':'c1'})}
        error_messages={
            '__all__':{},
            'email':{
                'required':'郵箱不能爲空',
                'invalid':'郵箱格式錯誤',
            }
        }
        #field_classes={'email':Ffields.URLField}
class UserInfoForm(forms.Form):
    username = Ffields.CharField(max_length=32)
    email=Ffields.EmailField()
    #user_type=fields.ForeignKey(to='UserType',to_field='id')
    user_type=Ffields.ChoiceField(
        choices=models.UserType.objects.values_list('id','caption')
    )

    def __init__(self,*args,**kwargs):
        super(UserInfoForm,self).__init__(*args,**kwargs)
        self.fields['user_type'].choices=models.UserType.objects.values_list('id','caption')

def index(request):
    if request.method=='GET':
        obj=UserInfoModelForm()
        return render(request,'index.html',{'obj':obj})
    elif request.method=='POST':
        obj=UserInfoModelForm(request.POST)
        if obj.is_valid():
            obj.save()
        #print(obj.is_valid())
        #print(obj.cleaned_data)
        #print(obj.errors.as_json())
        return render(request, 'index.html', {'obj': obj})

 七,obj.save()的拆分

查看源碼可知,save包含兩部分:

       instance.save(當前這個model對象,意思就是能夠把當前表save一下)

       obj.save_m2m( )  save ManyToMany,其實就是把兩步save拆開了。

 

7.1 測試 instance.save

 

 

測試效果:

 

 

7.2 小結:ModelForm能夠幫咱們生成HTML標籤,也能夠幫忙作驗證,驗證完了之後還能夠直接保存在數據庫中。

 

八,基於modelform實現添加數據的功能

models.UserInfo.objects.all().select_related('user_type','u2g') #跨表

8.1 添加user_list函數

# 基於ModelForm方式來實現
from django.shortcuts import render,HttpResponse
from app01 import models
from django import forms
from django.forms import fields as Ffields
from django.forms import widgets as Fwidgets
def orm(request):
    #models.UserGroup.objects.create(name='CEO')
    #models.UserGroup.objects.create(name='CFO')
    #models.UserGroup.objects.create(name='COO')
    return HttpResponse('orm')

class UserInfoModelForm(forms.ModelForm):
    class Meta:
        model=models.UserInfo  #指去哪一個類裏面去獲取字段,之後也能夠作增刪改查。
        fields='__all__'       #代指的是全部的field字段
        #fields=['username']   #還能夠是一個列表,能夠選擇要展現哪幾列,只展現username這一列
        #exclude=['username']   #把username列排除在外了。
        #labels={'username':'請填入用戶名'}
        #help_texts={'username':'請把你的名字寫對'}
        #widgets={'username':Fwidgets.Textarea(attrs={'class':'c1'})}
        error_messages={
            '__all__':{},
            'email':{
                'required':'郵箱不能爲空',
                'invalid':'郵箱格式錯誤',
            }
        }
        #field_classes={'email':Ffields.URLField}
class UserInfoForm(forms.Form):
    username = Ffields.CharField(max_length=32)
    email=Ffields.EmailField()
    #user_type=fields.ForeignKey(to='UserType',to_field='id')
    user_type=Ffields.ChoiceField(
        choices=models.UserType.objects.values_list('id','caption')
    )

    def __init__(self,*args,**kwargs):
        super(UserInfoForm,self).__init__(*args,**kwargs)
        self.fields['user_type'].choices=models.UserType.objects.values_list('id','caption')

def index(request):
    if request.method=='GET':
        obj=UserInfoModelForm()
        return render(request,'index.html',{'obj':obj})
    elif request.method=='POST':
        obj=UserInfoModelForm(request.POST)
        if obj.is_valid():
            #obj.save()#這個save實現的時候,其實內部包含了2個步驟。能夠拆開。
            instance=obj.save(False) #什麼也沒幹
            instance.save() #只會保存當前這個類,而不會保存manytomany
            obj.save_m2m() #保存manytomany
        #print(obj.is_valid())
        #print(obj.cleaned_data)
        #print(obj.errors.as_json())
        return render(request, 'index.html', {'obj': obj})

def user_list(request):
    li=models.UserInfo.objects.all().select_related('user_type') #先把userinfo中的數據取出來
    return render(request,'user_list.html',{'li':li})

 

user_list.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    <ul>
        {% for row in li %}
            <li>{{row.username}}-{{row.user_type.caption}}</li>
        {% endfor %}
    </ul>
</body>
</html>

 頁面效果:

 

8.2  最終想要達到的效果:

程序粘貼:

models.py

from django.db import models

class UserType(models.Model):
    caption=models.CharField(max_length=32)

class UserGroup(models.Model):
    name=models.CharField(max_length=32)

class UserInfo(models.Model):
    #username = models.CharField(verbose_name='用戶',max_length=32)
    username = models.CharField(max_length=32)
    email=models.EmailField()
    user_type=models.ForeignKey(to='UserType',to_field='id')
    u2g=models.ManyToManyField(UserGroup)

 views.py

# 基於ModelForm方式來實現
from django.shortcuts import render,HttpResponse
from app01 import models
from django import forms
from django.forms import fields as Ffields
from django.forms import widgets as Fwidgets
def orm(request):
    #models.UserGroup.objects.create(name='CEO')
    #models.UserGroup.objects.create(name='CFO')
    #models.UserGroup.objects.create(name='COO')
    return HttpResponse('orm')

class UserInfoModelForm(forms.ModelForm):
    class Meta:
        model=models.UserInfo  #指去哪一個類裏面去獲取字段,之後也能夠作增刪改查。
        fields='__all__'       #代指的是全部的field字段
        #fields=['username']   #還能夠是一個列表,能夠選擇要展現哪幾列,只展現username這一列
        #exclude=['username']   #把username列排除在外了。
        #labels={'username':'請填入用戶名'}
        #help_texts={'username':'請把你的名字寫對'}
        #widgets={'username':Fwidgets.Textarea(attrs={'class':'c1'})}
        error_messages={
            '__all__':{},
            'email':{
                'required':'郵箱不能爲空',
                'invalid':'郵箱格式錯誤',
            }
        }
        #field_classes={'email':Ffields.URLField}
class UserInfoForm(forms.Form):
    username = Ffields.CharField(max_length=32)
    email=Ffields.EmailField()
    #user_type=fields.ForeignKey(to='UserType',to_field='id')
    user_type=Ffields.ChoiceField(
        choices=models.UserType.objects.values_list('id','caption')
    )

    def __init__(self,*args,**kwargs):
        super(UserInfoForm,self).__init__(*args,**kwargs)
        self.fields['user_type'].choices=models.UserType.objects.values_list('id','caption')

def index(request):
    if request.method=='GET':
        obj=UserInfoModelForm()
        return render(request,'index.html',{'obj':obj})
    elif request.method=='POST':
        obj=UserInfoModelForm(request.POST)
        if obj.is_valid():
            #obj.save()#這個save實現的時候,其實內部包含了2個步驟。能夠拆開。
            instance=obj.save(False) #什麼也沒幹
            instance.save() #只會保存當前這個類,而不會保存manytomany
            obj.save_m2m() #保存manytomany
        #print(obj.is_valid())
        #print(obj.cleaned_data)
        #print(obj.errors.as_json())
        return render(request, 'index.html', {'obj': obj})

def user_list(request):
    li=models.UserInfo.objects.all().select_related('user_type') #先把userinfo中的數據取出來
    return render(request,'user_list.html',{'li':li})

def user_edit(request,nid):
    #獲取當前id對應的用戶信息
    #顯示用戶已經存在的數據
    if request.method=='GET':
        user_obj=models.UserInfo.objects.filter(id=nid).first() #獲取對象
        mf=UserInfoModelForm(instance=user_obj) #幫我們生成標籤
        return render(request, 'user_edit.html',{'mf':mf,'nid':nid})
    elif request.method=='POST':
        user_obj = models.UserInfo.objects.filter(id=nid).first() #獲取對象
        mf = UserInfoModelForm(request.POST,instance=user_obj) #instance傳進來表示更新,不加的話表示新建了一條數據。
        if mf.is_valid():
            mf.save()
        else:
            print(mf.errors.as_json())
        return render(request, 'user_edit.html', {'mf': mf, 'nid': nid})

 

 user_edit.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    <form method="POST" action="/edit-{{nid}}/">
        {% csrf_token %}
        {{mf.as_p}}
        <input type="submit" value="提交"/>
    </form>

</body>
</html>

 

 

 user_list.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    <ul>
        {% for row in li %}
            <li>{{row.username}}-{{row.user_type.caption}}-<a href="/edit-{{row.id}}/">編輯</a></li>
        {% endfor %}
    </ul>
</body>
</html>

 index.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    <form action="/index/" method="POST">
        {% csrf_token %}
        {{obj.as_p}}
        <input type="submit" value="提交"/>
    </form>
</body>
</html>

 urls.py

from django.conf.urls import url
from django.contrib import admin
from app01 import views

urlpatterns = [
    url(r'^admin/', admin.site.urls),
    url(r'^index/', views.index),
    url(r'^user_list/', views.user_list),
    url(r'^edit-(\d+)/', views.user_edit),
    url(r'^orm/', views.orm),
]

 8.3 補充

ModelForm:經過配置生成標籤,用is_valid 進行驗證,經過save進行保存。

ModelForm也能夠本身定義鉤子,與Form的用法同樣。

 

 

在UserInfoModelForm中也能夠定義新的字段。好比 username+password 能夠從數據庫中獲取,可是像一個月內免登錄就不須要提交到數據庫。像這個字段咱們就能夠在UserInfoModelForm中單獨定義。

views.py

# 基於ModelForm方式來實現
from django.shortcuts import render,HttpResponse
from app01 import models
from django import forms
from django.forms import fields as Ffields
from django.forms import widgets as Fwidgets
def orm(request):
    #models.UserGroup.objects.create(name='CEO')
    #models.UserGroup.objects.create(name='CFO')
    #models.UserGroup.objects.create(name='COO')
    return HttpResponse('orm')

class UserInfoModelForm(forms.ModelForm):
    #自定義額外的字段,好比是否要保存一個月內免登錄。
    is_remember=Ffields.CharField(
        widget=Fwidgets.CheckboxInput()
    )
    class Meta:
        model=models.UserInfo  #指去哪一個類裏面去獲取字段,之後也能夠作增刪改查。
        fields='__all__'       #代指的是全部的field字段
        #fields=['username']   #還能夠是一個列表,能夠選擇要展現哪幾列,只展現username這一列
        #exclude=['username']   #把username列排除在外了。
        #labels={'username':'請填入用戶名'}
        #help_texts={'username':'請把你的名字寫對'}
        #widgets={'username':Fwidgets.Textarea(attrs={'class':'c1'})}
        error_messages={
            '__all__':{},
            'email':{
                'required':'郵箱不能爲空',
                'invalid':'郵箱格式錯誤',
            }
        }
        #field_classes={'email':Ffields.URLField}
    def clean_username(self):
        old=self.cleaned_data['username']
        return old

class UserInfoForm(forms.Form):
    username = Ffields.CharField(max_length=32)
    email=Ffields.EmailField()
    #user_type=fields.ForeignKey(to='UserType',to_field='id')
    user_type=Ffields.ChoiceField(
        choices=models.UserType.objects.values_list('id','caption')
    )

    def __init__(self,*args,**kwargs):
        super(UserInfoForm,self).__init__(*args,**kwargs)
        self.fields['user_type'].choices=models.UserType.objects.values_list('id','caption')

def index(request):
    if request.method=='GET':
        obj=UserInfoModelForm()
        return render(request,'index.html',{'obj':obj})
    elif request.method=='POST':
        obj=UserInfoModelForm(request.POST)
        if obj.is_valid():
            #obj.save()#這個save實現的時候,其實內部包含了2個步驟。能夠拆開。
            instance=obj.save(False) #什麼也沒幹
            instance.save() #只會保存當前這個類,而不會保存manytomany
            obj.save_m2m() #保存manytomany
        #print(obj.is_valid())
        #print(obj.cleaned_data)
        #print(obj.errors.as_json())
        return render(request, 'index.html', {'obj': obj})

def user_list(request):
    li=models.UserInfo.objects.all().select_related('user_type') #先把userinfo中的數據取出來
    return render(request,'user_list.html',{'li':li})

def user_edit(request,nid):
    #獲取當前id對應的用戶信息
    #顯示用戶已經存在的數據
    if request.method=='GET':
        user_obj=models.UserInfo.objects.filter(id=nid).first() #獲取對象
        mf=UserInfoModelForm(instance=user_obj) #幫我們生成標籤
        return render(request, 'user_edit.html',{'mf':mf,'nid':nid})
    elif request.method=='POST':
        user_obj = models.UserInfo.objects.filter(id=nid).first() #獲取對象
        mf = UserInfoModelForm(request.POST,instance=user_obj) #instance傳進來表示更新,不加的話表示新建了一條數據。
        if mf.is_valid():
            mf.save()
        else:
            print(mf.errors.as_json())
        return render(request, 'user_edit.html', {'mf': mf, 'nid': nid})

 效果:

 

 

九,總結

 

一,ModelForm => 能夠作驗證,能夠作數據庫操做。
	Model+Form => 驗證+數據庫操做
	-class LoginModelForm(XXXX):
		利用model.A中的字段
	1.生成html標籤: class Meta:...
	2.mf=xxxModelForm(instance=ModelObj)
	3.額外的標籤,
	4.各類驗證 is_valid()->各類鉤子...
	    跟form的鉤子如出一轍,先進行每個字段正則表達式驗證,而後每個字段的方法,而後進行clean,clean完了之後是post clean
	5.mf.save()
	  ############或者下面的###############
	  instance=mf.save(False)
	  instance.save()
	  mf.save_m2m()
相關文章
相關標籤/搜索