Django-多對多建表與Form表單


一、多對多建表的三種創建方式:

 1.全自動型:(一般情況下使用)

class Book(models.Model):
    title = models.CharField(max_length=32)
    authors = models.ManyToManyField(to='Authors')# 多對多關系字段

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

全自動型:

  優點:至始至終都沒有操作第三張表,全部都是由ORM自動創建的,還內置了四個操作第三張表的方法。(add,添加、remove,刪除、set,設置、clear,清空)

  缺點:全自動創建的表無法擴展修改字段,表的擴展性較差。

 2.純手擼型:(了解即可)

class Book(models.Model):
    title = models.CharField(max_length=32)
    
class Authors(models.Model):
    name = models.CharField(max_length=32)

class Book2Authors(models.Model):
    book = models.ForeignKey(to="Book")
    author = models.ForeignKey(to="Authors")
    create_time = models.DateField(auto_now_add = True)

純手擼型:

  優點:第三張表中的字段個數和字段名稱全都可以自定義,

  缺點:不再支持ORM跨表查詢,不再有正反向的概念,沒有,add,remove,set,clear方法。

 3.半自動型:(推薦使用)

class Book(models.Model):
    title = models.CharField(max_length=32)
    # 多對多關系字段
    authors = models.ManyToManyField(to='Authors',through='Book2Author',through_fields=("book","authors"))
    """
    當你的ManyToManyField只有一個參數to的情況下 orm會自動幫你創建第三張表;
    如果你加了through和through_fields那么orm就不會自動幫你創建第三張表 ;
   但是它會在內部幫你維護關系,讓你能夠繼續使用orm的跨表查詢 through 指自定義的第三張關系表 through_fields 自動指定第三張關系表中,到底哪兩個字段維護者表與表之間的多對多關系
""" class Authors(models.Model): name = models.CharField(max_length=32) # 多對多關系字段 等價於上面的book表中的多對多關系字段 books = models.ManyToManyField(to='Book', through='Book2Author', through_fields=("authors","book")) class Book2Author(models.Model): book = models.ForeignKey(to='Book') authors = models.ForeignKey(to='Authors')

半自動型:

  優點:可以任意的添加和修改第三張表中的字段,並且支持ORM跨表查詢

  缺點:不支持add,remove,set,clear方法

二、Forms組件:

1.Forms組件介紹:

Form組件可以做的幾件事情:

  1.用戶請求數據的驗證;

  2.自動生成錯誤信息;

  3.打包用戶提交的正確信息;

  4.如果其中有一個錯誤了,其他的正確,保留上次輸入的內容

  5.自動創建input標簽並可以設置樣式

2.Form組件的使用:

  (1).創建規則:

class Foo(Form): #必須繼承
    username = xxx
    password = xxx
    email = xxx
注意這里的字段必須和input的name字段一致

  (2).數據和規則進行匹配先導入view.py

from django.forms import Form
from django.forms import fields
from django.forms import widgets
使用forms組件的第一步,必須先寫一個類:
from django import forms
from django.core.validators import RegexValidator
from django.forms import widgets
from django.core.exceptions import ValidationError
class MyForm(forms.Form):
                                 # username字段 最少三位 最多八位,label設置input前面的字段,inital設置默認值
    username = forms.CharField(max_length=8,min_length=3,label='用戶名',initial='默認值',
                               #通過error_messages,設置中文提示的錯誤信息
                               error_messages={
                                   'max_length':'用戶名最長八位',
                                   'min_length':'用戶名最短三位',
                                   'required':'用戶名不能為空'
                               },required=False,# False可以不進行Form驗證,默認為True
                                #通過widget=forms.widgets可以對標簽屬性設置,
                               widget=forms.widgets.TextInput({'class':'form-control c1 c2','username':'jason'})
                               )
    # password字段 最少三位  最多八位
    password = forms.CharField(max_length=8,min_length=3,label='密碼',
                               error_messages={
                                   'max_length': '密碼最長八位',
                                   'min_length': '密碼最短三位',
                                   'required': '密碼不能為空'
                               },widget=forms.widgets.PasswordInput()
                               )
    confirm_password = forms.CharField(max_length=8, min_length=3, label='確認密碼',
                               error_messages={
                                   'max_length': '確認密碼最長八位',
                                   'min_length': '確認密碼最短三位',
                                   'required': '確認密碼不能為空'
                               },
                               )
    # email字段 必須是郵箱格式
    email = forms.EmailField(label='郵箱',error_messages={
                            'required':'郵箱不能為空',
                            'invalid':'郵箱格式錯誤'
    })

當你覺得上面的所有的校驗還不能滿足你的需求,你可以考慮使用鈎子函數,函數體內你可以寫任意的校驗代碼
利用鈎子函數進行限定用戶輸入:
# 校驗用戶名中不能含有666     局部鈎子
  def clean_username(self):
      username = self.cleaned_data.get('username')
      if '666' in username:
          # 給username所對應的框展示錯誤信息
          # self.add_error('username','光喊666是不行的')
          raise ValidationError('到底對不對啊')
      # 將username數據返回
      return username

# 校驗密碼 確認密碼是否一致     全局鈎子
  def clean(self):
      password = self.cleaned_data.get("password")
      confirm_password = self.cleaned_data.get("confirm_password")
      if not password == confirm_password:
        self.add_error('confirm_password','兩次密碼不一致')
      # 將全局的數據返回
      return self.cleaned_data

函數調用:
def index(request):
    # 渲染標簽 第一步 需要生成一個空的forms類的對象
    form_obj = MyForm()
    # 如何校驗前端用戶傳入的數據
    if request.method == 'POST':
        # 獲取用戶的數據  request.POST中  forms組件校驗數據
        form_obj = MyForm(request.POST)  # 改變量名一定要跟上面的form_obj變量名一致

        if form_obj.is_valid():  # forms組件入口就是is_valid()
            print(form_obj.cleaned_data)
            return HttpResponse('數據全部OK')
    # 直接將生成的對象 傳遞給前端頁面
    return render(request,'index.html',locals())

數據的校驗通常前后端都必須有的,但是前端的校驗可有可無,並且弱不禁風,后端的校驗必須有並且必須非常全面,
如何告訴瀏覽器不做校驗,form表單中加一個novalidate參數即可。
#<form action="" method="post" novalidate>





index.html文件:

form action="" method="post" novalidate>
    {% for forms in form_obj %}
    <p>
        {{ forms.label }}{{ forms }}
        <span>{{ forms.errors.0 }}</span>
    </p>  <!--<span>{{ forms.errors.0 }}獲取錯誤信息添加input的后面-->
    {% endfor %}
    <input type="submit">
</form>

2.Form組件的其他方法使用:

  radioSelect,單radio值為字符串
gender = forms.fields.ChoiceField(
        choices=((1, ""), (2, ""), (3, "保密")),
        label="性別",
        initial=3,
        widget=forms.widgets.RadioSelect()
    )

單選Select
hobby = forms.ChoiceField(
        choices=((1, "籃球"), (2, "足球"), (3, "雙色球"), ),
        label="愛好",
        initial=3,
        widget=forms.widgets.Select()
    )

多選Select

hobby = forms.MultipleChoiceField(
        choices=((1, "籃球"), (2, "足球"), (3, "雙色球"), ),
        label="愛好",
        initial=[1, 3],
        widget=forms.widgets.SelectMultiple()
    )

單選checkbox

keep = forms.ChoiceField(
        label="是否記住密碼",
        initial="checked",
        widget=forms.widgets.CheckboxInput()
    )

多選checkbox

hobby = forms.MultipleChoiceField(
        choices=((1, "籃球"), (2, "足球"), (3, "雙色球"),),
        label="愛好",
        initial=[1, 3],
        widget=forms.widgets.CheckboxSelectMultiple()
    )

 Form所有內置字段

Field
    required=True,               是否允許為空
    widget=None,                 HTML插件
    label=None,                  用於生成Label標簽或顯示內容
    initial=None,                初始值
    help_text='',                幫助信息(在標簽旁邊顯示)
    error_messages=None,         錯誤信息 {'required': '不能為空', 'invalid': '格式錯誤'}
    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類型
Form所有內置字段

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM