管理員頁面註冊表單用
form組件相關設置
模型存放
業務邏輯
圖片文件存儲
項目名稱以及路由存放
bootstrap文件網上下載的
jq文件
頁面文件存放
settings.py
css
""" Django settings for BBS project. Generated by 'django-admin startproject' using Django 1.11.22. For more information on this file, see https://docs.djangoproject.com/en/1.11/topics/settings/ For the full list of settings and their values, see https://docs.djangoproject.com/en/1.11/ref/settings/ """ import os # Build paths inside the project like this: os.path.join(BASE_DIR, ...) BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) # Quick-start development settings - unsuitable for production # See https://docs.djangoproject.com/en/1.11/howto/deployment/checklist/ # SECURITY WARNING: keep the secret key used in production secret! SECRET_KEY = 's0x+v@gqeoxs4ruj58cq5&*5#7on_h$n4-$hwb3cr&h(@qcmoc' # SECURITY WARNING: don't run with debug turned on in production! DEBUG = True ALLOWED_HOSTS = [] # Application definition INSTALLED_APPS = [ 'django.contrib.admin', 'django.contrib.auth', 'django.contrib.contenttypes', 'django.contrib.sessions', 'django.contrib.messages', 'django.contrib.staticfiles', 'app.apps.AppConfig', ] MIDDLEWARE = [ 'django.middleware.security.SecurityMiddleware', 'django.contrib.sessions.middleware.SessionMiddleware', 'django.middleware.common.CommonMiddleware', 'django.middleware.csrf.CsrfViewMiddleware', 'django.contrib.auth.middleware.AuthenticationMiddleware', 'django.contrib.messages.middleware.MessageMiddleware', 'django.middleware.clickjacking.XFrameOptionsMiddleware', ] ROOT_URLCONF = 'BBS.urls' TEMPLATES = [ { 'BACKEND': 'django.template.backends.django.DjangoTemplates', 'DIRS': [os.path.join(BASE_DIR, 'templates')] , 'APP_DIRS': True, 'OPTIONS': { 'context_processors': [ 'django.template.context_processors.debug', 'django.template.context_processors.request', 'django.contrib.auth.context_processors.auth', 'django.contrib.messages.context_processors.messages', ], }, }, ] WSGI_APPLICATION = 'BBS.wsgi.application' # Database # https://docs.djangoproject.com/en/1.11/ref/settings/#databases DATABASES = { 'default': { 'ENGINE': 'django.db.backends.sqlite3', 'NAME': os.path.join(BASE_DIR, 'db.sqlite3'), } } # Password validation # https://docs.djangoproject.com/en/1.11/ref/settings/#auth-password-validators AUTH_PASSWORD_VALIDATORS = [ { 'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator', }, { 'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator', }, { 'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator', }, { 'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator', }, ] # Internationalization # https://docs.djangoproject.com/en/1.11/topics/i18n/ LANGUAGE_CODE = 'en-us' TIME_ZONE = 'UTC' USE_I18N = True USE_L10N = True USE_TZ = True # Static files (CSS, JavaScript, Images) # https://docs.djangoproject.com/en/1.11/howto/static-files/ STATIC_URL = '/static/' STATICFILES_DIRS=( os.path.join(BASE_DIR,'static'), ) #由於我建立模型的時候用到了user的類 AUTH_USER_MODEL='app.Userinfo'
models.pyhtml
from django.db import models from django.contrib.auth.models import AbstractUser class UserInfo(AbstractUser): nid = models.AutoField(primary_key=True) # 頭像:FileField文件(varchar類型),default:默認值,upload_to上傳的路徑 avatar = models.FileField(upload_to='avatar/', default='avatar/default.png') #跟blog表一對一 #OneToOneField本質就是ForeignKey,只不過有個惟一性約束 blog = models.OneToOneField(to='Blog', to_field='nid',null=True) # blog = models.ForeignKey(to='Blog', to_field='nid',null=True,unique=True) class Meta: # db_table='xxxx' # 在admin中顯示的表名 verbose_name='用戶表' #去掉 用戶表 後的s verbose_name_plural = verbose_name class Blog(models.Model): nid = models.AutoField(primary_key=True) #站點名稱 title = models.CharField(max_length=64) #站點副標題 site_name = models.CharField(max_length=32) #不一樣人不一樣主題 theme = models.CharField(max_length=64) def __str__(self): return self.site_name #分類表 class Category(models.Model): nid = models.AutoField(primary_key=True) #分類名稱 title = models.CharField(max_length=64) #跟博客是一對多的關係,關聯字段寫在多的一方 #to 是跟哪一個表關聯 to_field跟表中的哪一個字段作關聯, null=True 表示能夠爲空 blog = models.ForeignKey(to='Blog', to_field='nid', null=True) def __str__(self): return self.title class Tag(models.Model): nid = models.AutoField(primary_key=True) #標籤名字 title = models.CharField(max_length=64) # 跟博客是一對多的關係,關聯字段寫在多的一方 blog = models.ForeignKey(to='Blog', to_field='nid', null=True) def __str__(self): return self.title class Article(models.Model): nid = models.AutoField(primary_key=True) #verbose_name在admin中顯示該字段的中文 title = models.CharField(max_length=64,verbose_name='文章標題') #文章摘要 desc = models.CharField(max_length=255) #文章內容 大文本 content = models.TextField() #DateTimeField 年月日時分秒(注意跟datafield的區別) #auto_now_add=True:插入數據會存入當前時間 #auto_now=True 修改數據會存入當前時間 create_time = models.DateTimeField(auto_now_add=True) commit_num=models.IntegerField(default=0) up_num=models.IntegerField(default=0) down_num=models.IntegerField(default=0) #一對多的關係 blog = models.ForeignKey(to='Blog', to_field='nid', null=True) # 一對多的關係 category = models.ForeignKey(to='Category', to_field='nid', null=True) #多對多關係 through_fields 不能寫反了: tag = models.ManyToManyField(to='Tag', through='ArticleTOTag', through_fields=('article', 'tag')) def __str__(self): return self.title+'----'+self.blog.userinfo.username class ArticleTOTag(models.Model): nid = models.AutoField(primary_key=True) article = models.ForeignKey(to='Article', to_field='nid') tag = models.ForeignKey(to='Tag', to_field='nid') class Commit(models.Model): #誰對那篇文章評論了什麼內容 nid = models.AutoField(primary_key=True) user = models.ForeignKey(to='UserInfo', to_field='nid') article = models.ForeignKey(to='Article', to_field='nid') content = models.CharField(max_length=255) #評論時間 create_time = models.DateTimeField(auto_now_add=True) #自關聯() parent = models.ForeignKey(to='self', to_field='nid',null=True,blank=True) class UpAndDown(models.Model): #誰對那篇文章點贊或點踩 nid = models.AutoField(primary_key=True) user = models.ForeignKey(to='UserInfo', to_field='nid') article = models.ForeignKey(to='Article', to_field='nid') #布爾類型,本質也仍是0和1 is_up = models.BooleanField() class Meta: #聯合惟一,一個用戶只能給一片文章點贊或點踩 unique_together = (('user', 'article'),)
admin.pypython
from django.contrib import admin # Register your models here. #先導入模型 from app import models #註冊表 admin.site.register(models.UserInfo) admin.site.register(models.Blog) admin.site.register(models.Category) admin.site.register(models.Tag) admin.site.register(models.Article) admin.site.register(models.ArticleTOTag) admin.site.register(models.Commit) admin.site.register(models.UpAndDown)
urls.pyjquery
from django.conf.urls import url from django.contrib import admin #主路由導入視圖內函數 from app import views urlpatterns = [ url(r'^admin/', admin.site.urls), url(r'^register/', views.register), ]
from django import forms from django.forms import widgets from django.core.exceptions import ValidationError from app import models #寫一個類,繼承Form 沒有頭像校驗的字段 class Register(forms.Form): username=forms.CharField(max_length=18,min_length=3,label="用戶名", error_messages={'max_length':'太長了', 'min_length':'過短了', 'required':'不能爲空'}, widget=widgets.TextInput(attrs={'class':'form-control'}), ) password=forms.CharField(max_length=18,min_length=3,label="密碼", error_messages={'max_length':'太長了', 'min_length':'過短了', 'required':'不能爲空'}, widget=widgets.PasswordInput(attrs={'class':'form-control'}), ) re_pwd=forms.CharField(max_length=18,min_length=3,label="確認密碼", error_messages={'max_length':'太長了', 'min_length':'過短了', 'required':'不能爲空'}, widget=widgets.PasswordInput(attrs={'class':'form-control'}), ) email=forms.EmailField(max_length=18,min_length=3,label="郵箱", error_messages={'max_length':'太長了', 'min_length':'過短了', 'required':'不能爲空'}, widget=widgets.EmailInput(attrs={'class':'form-control'}), ) #局部鉤子,局部校驗 def clean_username(self): #取出name對應的值 name=self.cleaned_data.get('username') # if name.startswith('sb'): # #校驗不經過,拋異常 # raise ValidationError('不能以sb開頭') # #校驗經過,直接return name值 # else: # return name user=models.UserInfo.objects.filter(username=name).first() if user: #用戶存在,拋異常 raise ValidationError('用戶已經存在') else: return name #全局鉤子,全局校驗 def clean(self): pwd=self.cleaned_data.get('password') r_pwd=self.cleaned_data.get('re_pwd') if pwd==r_pwd: #校驗經過,返回清洗後的數據 return self.cleaned_data else: #校驗不經過,拋異常 raise ValidationError('兩次密碼不一致')
views.pyajax
from django.shortcuts import render,HttpResponse,redirect from django.http import JsonResponse #Image導入 #ImageDraw在圖片上寫字 #ImageFont 寫字的格式 from PIL import Image,ImageDraw,ImageFont import random # 至關於把文件以byte格式存到內存中 from io import BytesIO from django.contrib import auth from app.bbsforms import Register from app import models from django.db.models import Count from django.db.models.functions import TruncMonth from django.db.models import F # Create your views here. def register(request): if request.method=='GET': form=Register() return render(request,'register.html',{'form':form}) elif request.is_ajax(): response={'code':100,'msg':None} form = Register(request.POST) if form.is_valid(): #校驗經過的數據 clean_data=form.cleaned_data #把re_pwd剔除 clean_data.pop('re_pwd') #取出頭像 avatar=request.FILES.get('avatar') if avatar: #由於用的是FileField,只須要把文件對象賦值給avatar字段,自動作保存 clean_data['avatar']=avatar user=models.UserInfo.objects.create_user(**clean_data) if user: response['msg'] = '建立成功' else: response['code'] = 103 # 把校驗不經過的數據返回 response['msg'] = '建立失敗' else: response['code']=101 #把校驗不經過的數據返回 response['msg']=form.errors print(type(form.errors)) return JsonResponse(response,safe=False)
jq.htmlsql
<script src="/static/jquery-3.4.1.min.js"></script>
bootstrap.htmldjango
<link rel="stylesheet" href='/static/bootstrap-3.3.7-dist/css/bootstrap.min.css'> <script src="/static/bootstrap-3.3.7-dist/js/bootstrap.min.js"></script>
register.htmlbootstrap
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>註冊</title> {% include 'bootstrap.html' %} </head> <body> <div class="container-fluid"> <div class="row"> <div class="col-md-6 col-md-offset-3"> <h1>註冊</h1> <form id="my_form"> {% csrf_token %} {% for foo in form %} <div class="form-group"> {#foo.auto_id 就是foo生成的input的id#} <label for="{{ foo.auto_id }}">{{ foo.label }}</label> {{ foo }} <span style="color: red" class="error pull-right"></span> </div> {% endfor %} <div class="form-group"> <label for="id_file">頭像 <img src="/static/img/default.png" width="80" height="80" style="margin-left: 20px" id="id_img"> </label> <input type="file" name="file" id="id_file" style="display: none"> </div> <input type="button" class="btn btn-success" value="提交" id="id_submit"> </form> </div> </div> </div> </body> {% include 'jq.html' %} <script> //當該控件發生變化,響應該事件 $("#id_file").change(function () { //alert(1) //取到文件對象 var file = $("#id_file")[0].files[0] //放到img控件上,藉助於filereader 中間的東西,文件閱讀器 //生成一個文件閱讀器對象賦值給filereader var filereader = new FileReader() //把文件讀到filereader對象中 //讀文件須要時間,須要文件讀完再去操做img filereader.readAsDataURL(file) filereader.onload = function () { $("#id_img").attr('src', filereader.result) } }) $("#id_submit").click(function () { //ajax 上傳文件 var formdata = new FormData() //一個一個往裏添加,稍微複雜,用簡便方法 // formdata.append('name',$("#id_name").val()) // formdata.append('pwd',$("#id_pwd").val()) //簡便方法 //form 對象的serializeArray,它會把form中的數據包裝到一個對象中(不包含文件) var my_form_data = $("#my_form").serializeArray() //console.log(typeof my_form_data) //console.log(my_form_data) //jq的循環,傳兩個參數,第一個是要循環的對象,第二個參數是一個匿名函數 $.each(my_form_data, function (k, v) { {#console.log(k)#} {#console.log(v)#} formdata.append(v.name, v.value) }) formdata.append('avatar', $("#id_file")[0].files[0]) $.ajax({ url: '/register/', type: 'post', processData: false, //告訴jQuery不要去處理髮送的數據 contentType: false,// 告訴jQuery不要去設置Content-Type請求頭 data: formdata, success: function (data) { //console.log(data) if(data.code==100){ location.href='/login/' }else if(data.code==101){ $.each(data.msg,function (k,v) { console.log(k) console.log(v) $("#id_"+k).next().html(v[0]) if(k=='__all__'){ $("#id_re_pwd").next().html(v[0]) } }) } //定時器 setTimeout(function () { $(".error").html("") },3000) } }) }) </script> </html>