1. 程式人生 > >第八章(5)

第八章(5)

pip3 des 分組 最大值 url scrip 字典 length driver

  1. 元信息
  2. 多表關系
  3. 反向查找
  4. ORM操作
  5. 進階操作
  6. 其它操作
  7. 高效率關聯表
  8. models自帶驗證
  9. models內置鉤子
  10. from,choices
  11. Form類
  12. From內置鉤子驗證
  13. obj.is_valid()錯誤信息

1,元信息

class UserInfo(models.Model):
        nid = models.AutoField(primary_key=True)
        username = models.CharField(max_length=32)
        class Meta:
            # 數據庫中生成的表名稱 默認 app名稱 + 下劃線 + 類名
            db_table = "table_name"


# 聯合索引
            index_together = [
                ("pub_date", "deadline"),
            ]


# 聯合唯一索引
            unique_together = (("driver", "restaurant"),)

            # admin中顯示的表名稱
            verbose_name

            # verbose_name加s
            verbose_name_plural


#最前綴的模式
			select * from where name=‘xxx‘
			select * from where name=‘xxx‘ and email=‘xx‘
			select * from where email=‘xx‘ 無法命中
			
			unique_together = (("driver","restaurant"),)

https://www.cnblogs.com/wupeiqi/articles/6216618.html

2,多表關系

ForeignKey(ForeignObject) # ForeignObject(RelatedField)
        to,                         # 要進行關聯的表名
        to_field=None,              # 要關聯的表中的字段名稱
        on_delete=None,             # 當刪除關聯表中的數據時,當前表與其關聯的行的行為
                                        - models.CASCADE,刪除關聯數據,與之關聯也刪除
                                        - models.DO_NOTHING,刪除關聯數據,引發錯誤IntegrityError
                                        - models.PROTECT,刪除關聯數據,引發錯誤ProtectedError
                                        - models.SET_NULL,刪除關聯數據,與之關聯的值設置為null(前提FK字段需要設置為可空)
                                        - models.SET_DEFAULT,刪除關聯數據,與之關聯的值設置為默認值(前提FK字段需要設置默認值)
                                        - models.SET,刪除關聯數據,
                                                      a. 與之關聯的值設置為指定值,設置:models.SET(值)
                                                      b. 與之關聯的值設置為可執行對象的返回值,設置:models.SET(可執行對象)

                                                        def func():
                                                            return 10

                                                        class MyModel(models.Model):
                                                            user = models.ForeignKey(
                                                                to="User",
                                                                to_field="id"
                                                                on_delete=models.SET(func),)
																
																
        related_name=None,          # 反向操作時,使用的字段名,用於代替 【表名_set】 如: obj.表名_set.all()
        related_query_name=None,    # 反向操作時,使用的連接前綴,用於替換【表名】     如: models.UserGroup.objects.filter(表名__字段名=1).values(‘表名__字段名‘)
        limit_choices_to=None,      # 在Admin或ModelForm中顯示關聯數據時,提供的條件:
                                    # 如:
                                            - limit_choices_to={‘nid__gt‘: 5}
                                            - limit_choices_to=lambda : {‘nid__gt‘: 5}

                                            from django.db.models import Q
                                            - limit_choices_to=Q(nid__gt=10)
                                            - limit_choices_to=Q(nid=8) | Q(nid__gt=10)
                                            - limit_choices_to=lambda : Q(Q(nid=8) | Q(nid__gt=10)) & Q(caption=‘root‘)
											
											
        db_constraint=True          # 是否在數據庫中創建外鍵約束
        parent_link=False           # 在Admin中是否顯示關聯數據


    OneToOneField(ForeignKey)
        to,                         # 要進行關聯的表名
        to_field=None               # 要關聯的表中的字段名稱
        on_delete=None,             # 當刪除關聯表中的數據時,當前表與其關聯的行的行為

                                    ###### 對於一對一 ######
                                    # 1. 一對一其實就是 一對多 + 唯一索引
                                    # 2.當兩個類之間有繼承關系時,默認會創建一個一對一字段
                                    # 如下會在A表中額外增加一個c_ptr_id列且唯一:
                                            class C(models.Model):
                                                nid = models.AutoField(primary_key=True)
                                                part = models.CharField(max_length=12)

                                            class A(C):
                                                id = models.AutoField(primary_key=True)
                                                code = models.CharField(max_length=1)

    ManyToManyField(RelatedField)
        to,                         # 要進行關聯的表名
        related_name=None,          # 反向操作時,使用的字段名,用於代替 【表名_set】 如: obj.表名_set.all()
        related_query_name=None,    # 反向操作時,使用的連接前綴,用於替換【表名】     如: models.UserGroup.objects.filter(表名__字段名=1).values(‘表名__字段名‘)
        limit_choices_to=None,      # 在Admin或ModelForm中顯示關聯數據時,提供的條件:
                                    # 如:
                                            - limit_choices_to={‘nid__gt‘: 5}
                                            - limit_choices_to=lambda : {‘nid__gt‘: 5}

                                            from django.db.models import Q
                                            - limit_choices_to=Q(nid__gt=10)
                                            - limit_choices_to=Q(nid=8) | Q(nid__gt=10)
                                            - limit_choices_to=lambda : Q(Q(nid=8) | Q(nid__gt=10)) & Q(caption=‘root‘)
											
											
        symmetrical=None,           # 僅用於多對多自關聯時,symmetrical用於指定內部是否創建反向操作的字段
                                    # 做如下操作時,不同的symmetrical會有不同的可選字段
                                        models.BB.objects.filter(...)

                                        # 可選字段有:code, id, m1
                                            class BB(models.Model):

                                            code = models.CharField(max_length=12)
                                            m1 = models.ManyToManyField(‘self‘,symmetrical=True)

                                        # 可選字段有: bb, code, id, m1
                                            class BB(models.Model):

                                            code = models.CharField(max_length=12)
                                            m1 = models.ManyToManyField(‘self‘,symmetrical=False)

        through=None,               # 自定義第三張表時,使用字段用於指定關系表
        through_fields=None,        # 自定義第三張表時,使用字段用於指定關系表中那些字段做多對多關系表
                                        from django.db import models

                                        class Person(models.Model):
                                            name = models.CharField(max_length=50)

                                        class Group(models.Model):
                                            name = models.CharField(max_length=128)
                                            members = models.ManyToManyField(
                                                Person,
                                                through=‘Membership‘,
                                                through_fields=(‘group‘, ‘person‘),
                                            )

                                        class Membership(models.Model):
                                            group = models.ForeignKey(Group, on_delete=models.CASCADE)
                                            person = models.ForeignKey(Person, on_delete=models.CASCADE)
                                            inviter = models.ForeignKey(
                                                Person,
                                                on_delete=models.CASCADE,
                                                related_name="membership_invites",
                                            )
                                            invite_reason = models.CharField(max_length=64)
        db_constraint=True,         # 是否在數據庫中創建外鍵約束
        db_table=None,              # 默認創建第三張表時,數據庫中表的名稱

3,反向操作

from django db import models

class UserType(models.Model):
	name = models.CharField(max_length=32)
	
class User(models.Model):
	user = models.CharField(max_length=64)
	pwd = models.CharField(max_length=64)
	ut = models.FareignKey(to=‘UserType‘,to_field=‘id‘)
	
v = User.objects.all()
for item in v:
	item.user
	item.pwd
	item.ut.name

User.objects.all().values(‘user‘,‘ut_name‘)


###
v = UserType.objects.all()
for item in v:
	item.name
	item.id
	item.user_set.all()
	
UserType.objects.all().values(‘name‘,‘user_set‘)

4,ORM操作

# 增
        #
        # models.Tb1.objects.create(c1=‘xx‘, c2=‘oo‘)  增加一條數據,可以接受字典類型數據 **kwargs

        # obj = models.Tb1(c1=‘xx‘, c2=‘oo‘)
        # obj.save()

        # 查
        #
        # models.Tb1.objects.get(id=123)         # 獲取單條數據,不存在則報錯(不建議)
        # models.Tb1.objects.all()               # 獲取全部
        # models.Tb1.objects.filter(name=‘seven‘) # 獲取指定條件的數據
        # models.Tb1.objects.exclude(name=‘seven‘) # 獲取指定條件的數據

        # 刪
        #
        # models.Tb1.objects.filter(name=‘seven‘).delete() # 刪除指定條件的數據

        # 改
        # models.Tb1.objects.filter(name=‘seven‘).update(gender=‘0‘)  # 將指定條件的數據更新,均支持 **kwargs
        # obj = models.Tb1.objects.get(id=1)
        # obj.c1 = ‘111‘
        # obj.save()                                                 # 修改單條數據基本操作

5,進階操作

# 獲取個數
        #
        # models.Tb1.objects.filter(name=‘seven‘).count()

        # 大於,小於
        #
        # models.Tb1.objects.filter(id__gt=1)              # 獲取id大於1的值
        # models.Tb1.objects.filter(id__gte=1)              # 獲取id大於等於1的值
        # models.Tb1.objects.filter(id__lt=10)             # 獲取id小於10的值
        # models.Tb1.objects.filter(id__lte=10)             # 獲取id小於10的值
        # models.Tb1.objects.filter(id__lt=10, id__gt=1)   # 獲取id大於1 且 小於10的值

        # in
        #
        # models.Tb1.objects.filter(id__in=[11, 22, 33])   # 獲取id等於11、22、33的數據
        # models.Tb1.objects.exclude(id__in=[11, 22, 33])  # not in

        # isnull 是否為空 
        # Entry.objects.filter(pub_date__isnull=True)

        # contains (like)
        #
        # models.Tb1.objects.filter(name__contains="ven")
        # models.Tb1.objects.filter(name__icontains="ven") # icontains大小寫不敏感
        # models.Tb1.objects.exclude(name__icontains="ven")

        # range  範圍
        #
        # models.Tb1.objects.filter(id__range=[1, 2])   # 範圍bettwen and

        # 其他類似 xxx開頭 xx結尾
        #
        # startswith,istartswith, endswith, iendswith,

        # order by 排序
        #
        # models.Tb1.objects.filter(name=‘seven‘).order_by(‘id‘)    # asc  正向排序
        # models.Tb1.objects.filter(name=‘seven‘).order_by(‘-id‘)   # desc  逆向排序

        # group by  分組 統計
        #
        # from django.db.models import Count, Min, Max, Sum
        # models.Tb1.objects.filter(c1=1).values(‘id‘).annotate(c=Count(‘num‘))
        # SELECT "app01_tb1"."id", COUNT("app01_tb1"."num") AS "c" FROM "app01_tb1" WHERE "app01_tb1"."c1" = 1 GROUP BY "app01_tb1"."id"

        # limit 、offset 分頁
        #
        # models.Tb1.objects.all()[10:20]

        # regex正則匹配,iregex 不區分大小寫
        #
        # Entry.objects.get(title__regex=r‘^(An?|The) +‘)
        # Entry.objects.get(title__iregex=r‘^(an?|the) +‘)
        
        按時間查找
        # date
        #
        # Entry.objects.filter(pub_date__date=datetime.date(2005, 1, 1))
        # Entry.objects.filter(pub_date__date__gt=datetime.date(2005, 1, 1))

        # year
        #
        # Entry.objects.filter(pub_date__year=2005)
        # Entry.objects.filter(pub_date__year__gte=2005)

        # month
        #
        # Entry.objects.filter(pub_date__month=12)
        # Entry.objects.filter(pub_date__month__gte=6)

        # day
        #
        # Entry.objects.filter(pub_date__day=3)
        # Entry.objects.filter(pub_date__day__gte=3)

        # week_day
        #
        # Entry.objects.filter(pub_date__week_day=2)
        # Entry.objects.filter(pub_date__week_day__gte=2)

        # hour
        #
        # Event.objects.filter(timestamp__hour=23)
        # Event.objects.filter(time__hour=5)
        # Event.objects.filter(timestamp__hour__gte=12)

        # minute
        #
        # Event.objects.filter(timestamp__minute=29)
        # Event.objects.filter(time__minute=46)
        # Event.objects.filter(timestamp__minute__gte=29)

        # second
        #
        # Event.objects.filter(timestamp__second=31)
        # Event.objects.filter(time__second=2)
        # Event.objects.filter(timestamp__second__gte=31)

6,其他操作

##################################################################
# PUBLIC METHODS THAT ALTER ATTRIBUTES AND RETURN A NEW QUERYSET #
##################################################################

def all(self)
    # 獲取所有的數據對象

def filter(self, *args, **kwargs)
    # 條件查詢
    # 條件可以是:參數,字典,Q

def exclude(self, *args, **kwargs)
    # 條件查詢
    # 條件可以是:參數,字典,Q

def select_related(self, *fields)
     性能相關:表之間進行join連表操作,一次性獲取關聯的數據。
     model.tb.objects.all().select_related()
     model.tb.objects.all().select_related(‘外鍵字段‘)
     model.tb.objects.all().select_related(‘外鍵字段__外鍵字段‘)

def prefetch_related(self, *lookups)
    性能相關:多表連表操作時速度會慢,使用其執行多次SQL查詢在Python代碼中實現連表操作。
            # 獲取所有用戶表
            # 獲取用戶類型表where id in (用戶表中的查到的所有用戶ID)
            models.UserInfo.objects.prefetch_related(‘外鍵字段‘)



            from django.db.models import Count, Case, When, IntegerField
            Article.objects.annotate(
                numviews=Count(Case(
                    When(readership__what_time__lt=treshold, then=1),
                    output_field=CharField(),
                ))
            )

            students = Student.objects.all().annotate(num_excused_absences=models.Sum(
                models.Case(
                    models.When(absence__type=‘Excused‘, then=1),
                default=0,
                output_field=models.IntegerField()
            )))

def annotate(self, *args, **kwargs)
    # 用於實現聚合group by查詢

    from django.db.models import Count, Avg, Max, Min, Sum

    v = models.UserInfo.objects.values(‘u_id‘).annotate(uid=Count(‘u_id‘))
    # SELECT u_id, COUNT(ui) AS `uid` FROM UserInfo GROUP BY u_id

    v = models.UserInfo.objects.values(‘u_id‘).annotate(uid=Count(‘u_id‘)).filter(uid__gt=1)
    # SELECT u_id, COUNT(ui_id) AS `uid` FROM UserInfo GROUP BY u_id having count(u_id) > 1

    v = models.UserInfo.objects.values(‘u_id‘).annotate(uid=Count(‘u_id‘,distinct=True)).filter(uid__gt=1)
    # SELECT u_id, COUNT( DISTINCT ui_id) AS `uid` FROM UserInfo GROUP BY u_id having count(u_id) > 1

def distinct(self, *field_names)
    # 用於distinct去重
    models.UserInfo.objects.values(‘nid‘).distinct()
    # select distinct nid from userinfo

    註:只有在PostgreSQL中才能使用distinct進行去重

def order_by(self, *field_names)
    # 用於排序
    models.UserInfo.objects.all().order_by(‘-id‘,‘age‘)

def extra(self, select=None, where=None, params=None, tables=None, order_by=None, select_params=None)
    # 構造額外的查詢條件或者映射,如:子查詢

    Entry.objects.extra(select={‘new_id‘: "select col from sometable where othercol > %s"}, select_params=(1,))
    Entry.objects.extra(where=[‘headline=%s‘], params=[‘Lennon‘])
    Entry.objects.extra(where=["foo=‘a‘ OR bar = ‘a‘", "baz = ‘a‘"])
    Entry.objects.extra(select={‘new_id‘: "select id from tb where id > %s"}, select_params=(1,), order_by=[‘-nid‘])

 def reverse(self):
    # 倒序
    models.UserInfo.objects.all().order_by(‘-nid‘).reverse()
    # 註:如果存在order_by,reverse則是倒序,如果多個排序則一一倒序


 def defer(self, *fields):
    models.UserInfo.objects.defer(‘username‘,‘id‘)
    或
    models.UserInfo.objects.filter(...).defer(‘username‘,‘id‘)
    #映射中排除某列數據

 def only(self, *fields):
    #僅取某個表中的數據
     models.UserInfo.objects.only(‘username‘,‘id‘)
     或
     models.UserInfo.objects.filter(...).only(‘username‘,‘id‘)

 def using(self, alias):
     指定使用的數據庫,參數為別名(setting中的設置)


##################################################
# PUBLIC METHODS THAT RETURN A QUERYSET SUBCLASS #
##################################################

def raw(self, raw_query, params=None, translations=None, using=None):
    # 執行原生SQL
    models.UserInfo.objects.raw(‘select * from userinfo‘)

    # 如果SQL是其他表時,必須將名字設置為當前UserInfo對象的主鍵列名
    models.UserInfo.objects.raw(‘select id as nid from 其他表‘)

    # 為原生SQL設置參數
    models.UserInfo.objects.raw(‘select id as nid from userinfo where nid>%s‘, params=[12,])

    # 將獲取的到列名轉換為指定列名
    name_map = {‘first‘: ‘first_name‘, ‘last‘: ‘last_name‘, ‘bd‘: ‘birth_date‘, ‘pk‘: ‘id‘}
    Person.objects.raw(‘SELECT * FROM some_other_table‘, translations=name_map)

    # 指定數據庫
    models.UserInfo.objects.raw(‘select * from userinfo‘, using="default")

    ################### 原生SQL ###################
    from django.db import connection, connections
    cursor = connection.cursor()  # cursor = connections[‘default‘].cursor()
    cursor.execute("""SELECT * from auth_user where id = %s""", [1])
    row = cursor.fetchone() # fetchall()/fetchmany(..)


def values(self, *fields):
    # 獲取每行數據為字典格式

def values_list(self, *fields, **kwargs):
    # 獲取每行數據為元祖

def dates(self, field_name, kind, order=‘ASC‘):
    # 根據時間進行某一部分進行去重查找並截取指定內容
    # kind只能是:"year"(年), "month"(年-月), "day"(年-月-日)
    # order只能是:"ASC"  "DESC"
    # 並獲取轉換後的時間
        - year : 年-01-01
        - month: 年-月-01
        - day  : 年-月-日

    models.DatePlus.objects.dates(‘ctime‘,‘day‘,‘DESC‘)

def datetimes(self, field_name, kind, order=‘ASC‘, tzinfo=None):
    # 根據時間進行某一部分進行去重查找並截取指定內容,將時間轉換為指定時區時間
    # kind只能是 "year", "month", "day", "hour", "minute", "second"
    # order只能是:"ASC"  "DESC"
    # tzinfo時區對象
    models.DDD.objects.datetimes(‘ctime‘,‘hour‘,tzinfo=pytz.UTC)
    models.DDD.objects.datetimes(‘ctime‘,‘hour‘,tzinfo=pytz.timezone(‘Asia/Shanghai‘))

    """
    pip3 install pytz
    import pytz
    pytz.all_timezones
    pytz.timezone(‘Asia/Shanghai’)
    """

def none(self):
    # 空QuerySet對象


####################################
# METHODS THAT DO DATABASE QUERIES #
####################################

def aggregate(self, *args, **kwargs):
   # 聚合函數,獲取字典類型聚合結果
   from django.db.models import Count, Avg, Max, Min, Sum
   result = models.UserInfo.objects.aggregate(k=Count(‘u_id‘, distinct=True), n=Count(‘nid‘))
   ===> {‘k‘: 3, ‘n‘: 4}

def count(self):
   # 獲取個數

def get(self, *args, **kwargs):
   # 獲取單個對象

def create(self, **kwargs):
   # 創建對象

def bulk_create(self, objs, batch_size=None):
    # 批量插入
    # batch_size表示一次插入的個數
    objs = [
        models.DDD(name=‘r11‘),
        models.DDD(name=‘r22‘)
    ]
    models.DDD.objects.bulk_create(objs, 10)

def get_or_create(self, defaults=None, **kwargs):
    # 如果存在,則獲取,否則,創建
    # defaults 指定創建時,其他字段的值
    obj, created = models.UserInfo.objects.get_or_create(username=‘root1‘, defaults={‘email‘: ‘1111111‘,‘u_id‘: 2, ‘t_id‘: 2})

def update_or_create(self, defaults=None, **kwargs):
    # 如果存在,則更新,否則,創建
    # defaults 指定創建時或更新時的其他字段
    obj, created = models.UserInfo.objects.update_or_create(username=‘root1‘, defaults={‘email‘: ‘1111111‘,‘u_id‘: 2, ‘t_id‘: 1})

def first(self):
   # 獲取第一個

def last(self):
   # 獲取最後一個

def in_bulk(self, id_list=None):
   # 根據主鍵ID進行查找
   id_list = [11,21,31]
   models.DDD.objects.in_bulk(id_list)

def delete(self):
   # 刪除

def update(self, **kwargs):
    # 更新

def exists(self):
   # 是否有結果

其他操作
select id,count(id) from tab1 group by id having count(id) > 15;

#Entry 跨表查詢 select,where
#select 
Entry.objects.filter().extra(select={‘cid‘: "%s"},select_params=[1])
select * 1 as cid from tab1;

Entry.objects.extra(select={‘new_id‘: "select col from sometable where othercol = %s" },select_params=[1])

select * (select name from tab2 where nid = id) as new_id from tab1;

Entry.objects.extra(select={‘new_id‘: "func(id)"})
select * (select name from tb2 where nid = id) as new_id from tab1;

#where
Entry.objects.extra(where=[‘headline=1‘,‘nid>1‘])
Entry.objects.extra(where=[‘headline=1 or nid=1‘])
Entry.objects.extra(where=[‘func(ctime)=1 or nid=1‘],params=[])

7,高效率關聯表

select_related
	users = models.User.objects.all().select_related(‘ut‘)
	for row in users:
		print(row.user,row.pwd,row.ut_id)
		print(row.ut.name)
		print(row.tu.name)  #再發一次SQL請求
		
prefetch_related
	users = models.User.objects.filter(id_gt=30).prefetch_related(‘ut‘,‘tu‘)
	select * from users where id > 30
	select * from user_type where id in [1,2]
	
	for row in users:
		print(row.user,row.pwd,row.ut_id)
		print(row.ut.name)	

8,models自帶驗證

obj = models.UserInfo(name=‘alex‘,email=‘alex‘)
obj.full_clean()
obj.save()

return HttpResponse(‘index‘)

9,models內置鉤子

class UserInfo(models.Model):
	name = models.CharField(max_length=32)
	c = UserInfo.objects.filter(name=self.name).count()
	if c:
		raise ValidationError(message=‘用戶名已經存在‘,code=‘li‘)

##############
from django.forms import vidgets

class UserInForm(forms.Form):
	user = fields.CharField(
		required=False,
		widget=widgets.Textarea(attrs={‘class‘:‘c1‘})
		)
		pwd = fields.CharField(
			max_length=12,
			widget=widgets.PasswordInput(attrs={‘class‘:‘c1‘})
			)
			
			#f 驗證
			#生成HTML (保留上一次提交的數據)
			
			#新URL方式操作(Form方式)
			#Ajax請求 驗證(*) + 生成HTML 驗證(*)

10,from,choices

models.py

from django.db import models

# Create your models here.
class UserInfo(models.Model):
    name = models.CharField(max_length=32)
    email = models.EmailField()

    def clean(self):
        from django.core.exceptions import ValidationError
        c = UserInfo.objects.filter(name=self.name).count()
        if c:
            raise ValidationError(message=‘用戶名已經存在‘,code=‘li‘)

class UserType(models.Model):
    name = models.CharField(max_length=32)
    
   def __str__(self):
        return self.name

###########
from.py

from django.forms import widgets
from django import forms
from django.forms import fields
from app import models
from django.forms.models import ModelChoiceField,ModelMultipleChoiceField

class UserInfoForm(forms.Form):
    user = fields.CharField(
        required=False,
        widget=widgets.Textarea(attrs={‘class‘:‘c1‘})
    )
    pwd = fields.CharField(
        max_length=12,
        widget=widgets.PasswordInput(attrs={‘class‘:‘c1‘})
    )

    user_type = fields.ChoiceField(
    choices = [],
    widget=widgets.Select
    )

    user_type2 = fields.ChoiceField(widget=widgets.Select(choices=[]))
    
    #django自帶
    #ModelMultipleChoiceField多選
     user_type3 = ModelChoiceField(
        empty_label=‘請選擇類型‘,
        queryset=models.UserType.objects.all(),
        to_field_name=‘id‘

    )

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

        self.fields[‘user_type‘].choices = models.UserType.objects.values_list(‘id‘,‘name‘)
        self.fields[‘user_type2‘].widget.choices = models.UserType.objects.values_list(‘id‘,‘name‘)


#########
index.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    <p>{{ obj.user }}</p>
    <p>{{ obj.pwd }}</p>
    <p>{{ obj.user_type }}</p>
    <p>{{ obj.user_type2 }}</p>
    <p>{{ obj.user_type3 }}</p>
</body>
</html>

11,Form類

創建Form類時,主要涉及到 【字段】 和 【插件】,字段用於對用戶請求數據的驗證,插件用於自動生成HTML;

1、Django內置字段如下:

http://www.cnblogs.com/wupeiqi/articles/6144178.html

Field required=True, 是否允許為空 widget=None, HTML插件 label=None, 用於生成Label標簽或顯示內容 initial=None, 初始值 help_text=‘‘, 幫助信息(在標簽旁邊顯示) error_messages=None, 錯誤信息 {‘required‘: ‘不能為空‘, ‘invalid‘: ‘格式錯誤‘} show_hidden_initial=False, 是否在當前插件後面再加一個隱藏的且具有默認值的插件(可用於檢驗兩次輸入是否一直) validators=[], 自定義驗證規則 localize=False, 是否支持本地化 disabled=False, 是否可以編輯 label_suffix=None Label內容後綴 CharField(Field) max_length=None, 最大長度 min_length=None, 最小長度 strip=True 是否移除用戶輸入空白 IntegerField(Field) max_value=None, 最大值 min_value=None, 最小值 FloatField(IntegerField) ... DecimalField(IntegerField) max_value=None, 最大值 min_value=None, 最小值 max_digits=None, 總長度 decimal_places=None, 小數位長度 BaseTemporalField(Field) input_formats=None 時間格式化 DateField(BaseTemporalField) 格式:2015-09-01 TimeField(BaseTemporalField) 格式:11:12 DateTimeField(BaseTemporalField)格式:2015-09-01 11:12 DurationField(Field) 時間間隔:%d %H:%M:%S.%f ... RegexField(CharField) regex, 自定制正則表達式 max_length=None, 最大長度 min_length=None, 最小長度 error_message=None, 忽略,錯誤信息使用 error_messages={‘invalid‘: ‘...‘} EmailField(CharField) ... FileField(Field) allow_empty_file=False 是否允許空文件 ImageField(FileField) ... 註:需要PIL模塊,pip3 install Pillow 以上兩個字典使用時,需要註意兩點: - form表單中 enctype="multipart/form-data" - view函數中 obj = MyForm(request.POST, request.FILES) URLField(Field) ... BooleanField(Field) ... NullBooleanField(BooleanField) ... ChoiceField(Field) ... choices=(), 選項,如:choices = ((0,‘上海‘),(1,‘北京‘),) required=True, 是否必填 widget=None, 插件,默認select插件 label=None, Label內容 initial=None, 初始值 help_text=‘‘, 幫助提示 ModelChoiceField(ChoiceField) ... django.forms.models.ModelChoiceField queryset, # 查詢數據庫中的數據 empty_label="---------", # 默認空顯示內容 to_field_name=None, # HTML中value的值對應的字段 limit_choices_to=None # ModelForm中對queryset二次篩選 ModelMultipleChoiceField(ModelChoiceField) ... django.forms.models.ModelMultipleChoiceField TypedChoiceField(ChoiceField) coerce = lambda val: val 對選中的值進行一次轉換 empty_value= ‘‘ 空值的默認值 MultipleChoiceField(ChoiceField) ... TypedMultipleChoiceField(MultipleChoiceField) coerce = lambda val: val 對選中的每一個值進行一次轉換 empty_value= ‘‘ 空值的默認值 ComboField(Field) fields=() 使用多個驗證,如下:即驗證最大長度20,又驗證郵箱格式 fields.ComboField(fields=[fields.CharField(max_length=20), fields.EmailField(),]) MultiValueField(Field) PS: 抽象類,子類中可以實現聚合多個字典去匹配一個值,要配合MultiWidget使用 SplitDateTimeField(MultiValueField) input_date_formats=None, 格式列表:[‘%Y--%m--%d‘, ‘%m%d/%Y‘, ‘%m/%d/%y‘] input_time_formats=None 格式列表:[‘%H:%M:%S‘, ‘%H:%M:%S.%f‘, ‘%H:%M‘] FilePathField(ChoiceField) 文件選項,目錄下文件顯示在頁面中 path, 文件夾路徑 match=None, 正則匹配 recursive=False, 遞歸下面的文件夾 allow_files=True, 允許文件 allow_folders=False, 允許文件夾 required=True, widget=None, label=None, initial=None, help_text=‘‘ GenericIPAddressField protocol=‘both‘, both,ipv4,ipv6支持的IP格式 unpack_ipv4=False 解析ipv4地址,如果是::ffff:192.0.2.1時候,可解析為192.0.2.1, PS:protocol必須為both才能啟用 SlugField(CharField) 數字,字母,下劃線,減號(連字符) ... UUIDField(CharField) uuid類型

12,From內置鉤子驗證

#####
views.py

from django.shortcuts import render
from app.forms import  RegisterForm
# Create your views here.

def index(request):
    if request.method == "GET":
        obj =  RegisterForm()
        #傳遞默認值
        #obj =  RegisterForm({‘user‘:‘alex‘})
        return render(request,‘index.html‘,{‘obj‘:obj})

    elif request.method == "POST":
        obj =  RegisterForm(request.POST,request.FILES)
        obj.is_valid()

####
froms.py

from django.core.exceptions import ValidationError
class RegisterForm(forms.Form):
    user = fields.CharField()
    email = fields.EmailField


    def clean_user(self):
        c = models.UserInfo.objects.filter(name=self.cleaned_data[‘user‘]).count()
        if not c:
            return self.cleaned_data[‘user‘]
        else:
            raise ValidationError(‘用戶名已經存在‘,code=‘xx‘)

    def clean_email(self):
        return self.cleaned_data[‘email‘]

class LoginFrom(forms.Form):
    user = fields.CharField()
    pwd = fields.CharField()
    #自定義表達式
    #pwd = fields.CharField(validators=[])
    
    #驗證用戶是否存在
    def clean_user(self):
        c = models.UserInfo.objects.filter(name=self.cleaned_data[‘user‘]).count()
        if not c:
            return self.cleaned_data[‘user‘]
        else:
            raise ValidationError(‘用戶名已經存在‘, code=‘xx‘)
   
   
    #驗證密碼是否正確
    def clean(self):
        c = models.UserInfo.objects.filter(name=self.cleaned_data[‘user‘],pwd=self.cleaned_data[‘password‘]).count()
        if c:
            return self.cleaned_data
        else:
            raise ValidationError(‘用戶名或密碼錯誤‘)
   
   #其他鉤子
    def _post_clean(self):
        pass

from驗證

urls.py

from django.contrib import admin
from django.urls import path
from django.conf.urls import url,include
#from app import views
from app.views import test
from app.views import account
urlpatterns = [
    #path(‘admin/‘, admin.site.urls),
    url(r‘^index/‘,test.index),
    url(r‘^login.html$‘,account.login),
]

####
index.py

from django.shortcuts import render
from app.forms import UserInfoForm
# Create your views here.

def index(request):
    if request.method == "GET":
        obj = UserInfoForm()
        #傳遞默認值
        #obj = UserInfoForm({‘user‘:‘alex‘})
        return render(request,‘index.html‘,{‘obj‘:obj})

    elif request.method == "POST":
        obj = UserInfoForm(request.POST,request.FILES)
        obj.is_valid()


####
login.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>login</title>
</head>
<body>
    <form id="fm">
        {% csrf_token %}
        <p><input type="text" name="username" /></p>
        <p><input type="text" name="password" /></p>
        <a id="submit">提交</a>
    </form>
    <script src="/static/jquery-1.12.4.js"></script>
    <script>
        $(function(){
            $(‘$submit‘).click(function(){
                $.ajax({
                    url:‘/login.html‘,
                    type: ‘POST‘,
                    data: $(‘#fm‘).serialize(),
                    success: function(arg){
                        arg = JSON.parse(arg);
                        console.log(arg);
                    },
                    error: function(){

                    }
                })
            })
        })
    </script>
</body>
</html>

####
account.py

from django.forms import fields
from django.forms import widgets
from django import forms
from django.shortcuts import render,HttpResponse
class LoginFrom(forms.Form):
    username = fields.CharField()
    password = fields.CharField(
        max_length=64,
        min_length=12,
    )

###自定義jsnon 默認json只支持python類型
from django.core.exceptions import ValidationError
import json
class JsonCustomEncoder(json.JSONEncoder):
    def default(self,field):
        if isinstance(field,ValidationError):
            return {‘code‘: field.code,‘messages‘:field.message}
        else:
            return json.JSONEncoder.default(self,field)


def login(request):
    if request.method == ‘GET‘:
        return render(request,‘login.html‘)
    elif request.method == "POST":
        ret = {‘status‘:True,‘error‘:None,‘date‘:None}
        obj = LoginFrom(request.POST)
        if obj.is_valid():
            print(obj.cleaned_data)
        else:
            ret[‘error‘] = obj.error.as_data()
        result = json.dumps(ret,cls=JsonCustomEncoder)
        return HttpResponse(result)  

自定義json

第一種
	from django.core import serializrs
	
	v = models.tb.objects.all()
	data = serializers.serialize("json",v)
	
第二種
	import json
	from datetime import date
	from datetime import datetime
	
	class JsonCustomEncoder(json.JSONEncoder):
		def default(self,field):
			if isinstance(field,datetime):
				return field.atrftime(‘%Y-%m-%d %H:%M:%s‘)
			elif isinstance(field,date):
				return field.strftime(‘%Y-%m-%d‘)
			else:
            	return json.JSONEncoder.default(self,field)
     v = models.tb.objects.values(‘id‘,‘name‘,‘ctime‘)
     v = list(v)
     v = json.dumps(v,cls=JsonCustomEncoder)
     
     
     #####################
     v = models.UserType.objects.values(‘id‘,‘name‘)
     v = list(v)
     return HttpResponse(json.dumps(v))

登錄驗證嗎

if request,method == POST:
	if request.session[‘CheckCode‘].upper() == request.POST.get(‘check_code‘).upper():
		pass
	else:
    	print(‘驗證碼錯誤‘)
return render(request,‘login.html‘)    	

12,obj.is_valid()錯誤信息

from app01.forms import RegisterForm
from django.core.excptions import NON_FIELD_ERRORS
#NON_FIELD_ERRORS = __all__

obj = RegisterForm(request.POST)
if obj.is_valid():
	obj.cleand_data
else:
	obj.errros
	{
        "__all__": [],
        ‘user‘:[{‘code‘:‘required‘,‘message‘:‘xxx‘}],
        ‘pwd‘:[{‘code‘:‘required‘,‘message‘:‘xxx‘}],
	}

  

第八章(5)