Django-Course
Django-Course copied to clipboard
Python Django Web开发 入门到实践 搭建博客网站 Blog 视频地址:
Django_Course
Python Django Webå¼å å ¥é¨å°å®è·µ è§é¢å°åï¼https://space.bilibili.com/252028233/
å ¶å®å¦ä¹ èµæ
- èªå¼ºå¦å Djangoæç¨
- Django 2 é¶åºç¡ - å¾ åæ¸ åç½ç«
- åéDjangoè§é¢æç¨
- Django 宿¹ææ¡£
- python æ°æ®ç»æä¸ç®æ³ç³»å课ç¨
- python æä½MysqlãRedisãMongoDBæ°æ®åº
- Python Web å ¥åæå
- Python æ°æ®ç»æä¸ç®æ³ - å大
- ç®æ³å¾è§£ , å¾è§£çå½¢å¼å¾éåæ°æï¼ç¤ºä¾ä½¿ç¨çæ¯ pythonã
- python é¢è¯é¢
- Stack Overflowå ³äºPythonçé¨å
- Python Cookbook
- The Python Standard Library
- Python HOWTOs
- Python 3 Module of the Week
- Cpython æºç
- python-regex-cheatsheet
- python code examples
çè§é¢æ´çè¦ç¹ç¬è®°:
- Django_Course
- å ¶å®å¦ä¹ èµæ
- 01.ä»ä¹æ¯Django
- 02.å ¥é¨ Hello World
- 03.Djangoåºæ¬åºç¨ç»æ
- 04.ä½¿ç¨æ¨¡çæ¾ç¤ºå 容
- 05.å®å¶åå°åä¿®æ¹æ¨¡å
- 06.å¼å§å®æ´å¶ä½ç½ç«
- 07.æå»ºä¸ªäººå客ç½ç«
- 08.常ç¨çæ¨¡çæ ç¾åè¿æ»¤å¨
- 09.模çåµå¥
- 10.使ç¨CSSç¾å页é¢
- 11.CSSæ¡æ¶åå©å端å¸å±
- 12.Bootstrapååºå¼å¸å±
- 13.å页åshellå½ä»¤è¡æ¨¡å¼
- 14.ä¼åå页å±ç¤º
- 15.ä¸ä¸ç¯å客忿åç±»
- 16.ç»è®¡åç±»åå®¢çæ°é
- 17.å客åå°å¯ææ¬ç¼è¾
- 18.å客é 读ç®å计æ°
- 19.å客é 读计æ°ä¼å
- 20.é 读计æ°ç»è®¡åæ¾ç¤º
- 21.çé¨é 读å客æè¡åç¼åæé
- 22.è¯è®ºåè½è®¾è®¡åç¨æ·ç»å½
- 23.html表åæäº¤è¯è®º
- 24.使ç¨Django Form表å
- 25.表å坿æ¬ç¼è¾åajax弿¥æäº¤è¯è®º
- 26.åå¤åè½è®¾è®¡åæ ç»æ
- 27.è·åè¯è®ºæ°åç»èå¤ç
- 28.å®ç°ç¹èµåè½, çä¼¼ç®åï¼å 容å¾å¤
- 29.å®åç¹èµåè½
- 30.å¯¼èªæ æ·»å ç¨æ·æä½
- 31.èªå®ä¹ç¨æ·æ¨¡å
- 32.ä¿®æ¹ç¨æ·ä¿¡æ¯
- 33.忥é®ç®±çä½ç¨
- 34.è¯è®ºåéé®ä»¶éç¥
- 35.é¨ç½²åå¤ï¼ä¸ï¼ï¼Git
- 36.é¨ç½²åå¤ï¼äºï¼ï¼MySQL
- 37.é¨ç½²åå¤ï¼ä¸ï¼ï¼æå¡å¨
- 38.ç¨Apache+mod_wsgié¨ç½²
01.ä»ä¹æ¯Django
1. ä»ä¹æ¯Django
- å®ç½ï¼https://www.djangoproject.com
- ææ¡£ï¼https://docs.djangoproject.com/en/2.0/
- The web framework for perfectionists with deadlines.
- 卿ªæ¢æ¥æå ï¼å®ç¾ä¸»ä¹è 使ç¨çWebæ¡æ¶ã
- Django was invented to meet fast-moving newsroom deadlines, while satisfying the tough requirements of experienced Web developers.
- Djangoçåææ¯ä¸ºäºæ»¡è¶³ç´§æ¥æ°é»ç¼è¾é¨çæåæéï¼åæ¶æ»¡è¶³ç»éªä¸°å¯çWebå¼å人åçèå»è¦æ±ã
- Django makes it easier to build better Web apps more quickly and with less code.
- Django让æ´å¿«æå»ºå¥½çWebåºç¨å徿´ç®åï¼å¹¶ä¸ä»£ç æ´å°ã
- å¼åå¿«å°ç¦»è°±ï¼å è´¹å¼æºï¼å¤çäºè®¸å¤Webå¼åç¹ççäºï¼ä»¤ä½¿ç¨è 䏿³¨ä¸å¡
- 令人æ¾å¿çå®å ¨
- 坿屿§å¼º
2. Djangoçæ¬éæ©
- https://www.djangoproject.com/download/
- æ¬é¡¹ç®åºäº Python3.6+ å Django2.0

02.å ¥é¨ Hello World
- å ¥é¨ä»ªå¼ï¼å建项ç®ï¼è¾åºHello, world
- å建项ç®å½ä»¤ï¼
django-admin startproject mysite - Django项ç®åºæ¬ç»æ
mysite
â mysite Pyhton å
â â - _init__.py
â â - settings.py å
¨å±è®¾ç½®æä»¶
â â - urls.py å
¨å±è·¯ç±æ§å¶
â â - wsgi.py æå¡å¨ä½¿ç¨çwsgié¨ç½²æä»¶
â manage.py 项ç®ç®¡ç
- ååºè¯·æ±
- 客æ·ç«¯ æå¼ç½ååé请æ±-ãUrls å¤çè¯·æ± -ãViews ååºè¯·æ±ï¼è¿åå 容
- å¯å¨æ¬å°æå¡
python manage.py runserver - æ§è¡æ°æ®åºè¿ç§»ï¼æ°å»ºæ°æ®åº
python manage.py migrate - å建è¶
级管çåç¨æ·
python manage.py createsuperuser - 管çåé¡µé¢ http://127.0.0.1:8000/admin/
03.Djangoåºæ¬åºç¨ç»æ
- å建Django App
python manage.py startapp article - 妿页颿¯è¾å¤ï¼å°ç¸ä¼¼çå å®¹ç¨æ¨¡çæ¥ç®¡çï¼æ°æ®æ½è±¡ä¸ºæ¨¡åModels
- åå»ºæ°æ®ç模åmodels
from django.db import models
# Create your models here.
class Article(models.Model):
title = models.CharField(max_length=30)
content = models.TextField()
- å建模ååï¼å
éè¦çææ°åºè¿ç§»æä»¶ï¼åæ§è¡æ°æ®åºè¿ç§»
- é¦å
è¦å¨
settings.pyä¸ï¼INSTALLED_APPSæ·»å app name python manage.py makemigrationspython manage.py migrate
- é¦å
è¦å¨
# çæçæ°æ®åºè¿ç§»æä»¶
class Migration(migrations.Migration):
initial = True
dependencies = [
]
operations = [
migrations.CreateModel(
name='Article',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('title', models.CharField(max_length=30)),
('content', models.TextField()),
],
),
]
- å°æ¨¡å注åå°åå°ç®¡ç页é¢
# admin.py
from .models import Article
# Register your models here.
admin.site.register(Article)
- è¿å ¥åå°æ¾å°Article 管çï¼æ·»å ä¿®æ¹æ°æ®
- 设置è¯è¨åæ¶åº
settings.py
# LANGUAGE_CODE = 'en-us'
LANGUAGE_CODE = 'zh-Hans'
# TIME_ZONE = 'UTC'
TIME_ZONE = 'Asia/Shanghai'
04.ä½¿ç¨æ¨¡çæ¾ç¤ºå 容
- æ¥çæç« 页é¢
- å¦ä½éè¿ä¸ä¸ªå¤çæ¹æ³è·åæç« å¯ä¸çæ è¯
path('article/<int:article_id>', article_detail, name='article_detail'),<int:article_id>é»è®¤æ¯åç¬¦ä¸²ï¼æ·»å intæå®æ´å
- 模åç
objectsæ¯è·ååæä½æ¨¡åç对象
from .models import Article
Article.objects.get(æ¡ä»¶) # æ ¹æ®æ¡ä»¶è·åæ°æ®
Article.objects.all() # è·åæææ°æ®
Article.objects.filter(æ¡ä»¶) # æ ¹æ®æ¡ä»¶è¿æ»¤æ°æ®
article = Article.objects.get(id=article_id)
return HttpResponse('<h2>æç« æ é¢ï¼%s </h2><hr> æç« å
容ï¼%s' % (article.title, article.content))
- è·åä¸åå¨çæç« ï¼è¿å404页é¢
try:
article = Article.objects.get(id=article_id)
except Article.DoesNotExist:
raise Http404('not exit')
-
ä½¿ç¨æ¨¡çï¼å端页é¢åå端代ç å离ï¼éä½è¦åæ§
-
æ¥ç django æºç ï¼äºè§£å½æ°åè½
- VS code å³é® éè§å®ä¹ å¯ä»¥æ¾ç¤ºæºç
- æ¾å°å®è£
è·¯å¾
pip show django - è¿å ¥æ¥çæºç æä»¶
-
ç®åï¼ç¨render_to_responseçç¥è¯·æ±åæ°ï¼ç¨get_object_or_404代æ¿å¼å¸¸å¤ç
# article = Article.objects.get(id=article_id)
article = get_object_or_404(Article, pk=article_id)
context = {}
context['article_obj'] = article
# return render(request, 'article_detail.html', context)
return render(request, 'article_detail.html', context) # ä¸éè¦requeståæ°l
- è·åæç« å表
- ç¨url模ç代æ¿ç¡¬ç¼ç ï¼æ¹ä¾¿åç»ä¿®æ¹
<a href="/article/{{ article.pk }}"><a href="{% url 'article_detail' article.pk %}">
def article_list(request):
articles = Article.objects.all()
context = {}
context['articles'] = articles
return render(request, 'article_list.html', context)
- è·¯ç±ç®¡çï¼æ»urlså å«appçurlsï¼æ»åç»æï¼ä¾¿äºç»´æ¤
# æ»è·¯ç±
urlpatterns = [
path('admin/', admin.site.urls),
path('', views.index),
path('article/', include('article.urls'))
]
# app è·¯ç±
urlpatterns = [
# localhost:8000/article/
path('', views.article_list, name='article_list'),
path('<int:article_id>', views.article_detail, name='article_detail'),
]
05.å®å¶åå°åä¿®æ¹æ¨¡å
- å®å¶åå°
- è®¾ç½®æ¨¡åæ¾ç¤º
__str__ - å®å¶æ¨¡åadminåå°ç®¡ç页é¢
- è®¾ç½®æ¨¡åæ¾ç¤º
# è®¾ç½®æ¨¡åæ¾ç¤º models.py
class Article(models.Model):
title = models.CharField(max_length=30)
content = models.TextField()
def __str__(self):
return '<Article: %s>' % self.title
# admin.py
# Register your models here.
@admin.register(Article) # 使ç¨è£
饰卿´æ¹ä¾¿éç®
class ArticleAdmin(admin.ModelAdmin):
list_display = ('id', 'title', 'content')
# ordering = ('-id', ) ååº
ordering = ('id', )
#admin.site.register(Article, ArticleAdmin)
- ä¿®æ¹æ¨¡åmodelsï¼ä¿®æ¹åå°æ¾ç¤ºå段
- æ¯æ¬¡ä¿®æ¹æ¨¡åéè¦æ´æ°æ°æ®åº
python manage.py makemigrationspython manage.py migrate- éè¦è®¾ç½®é»è®¤å¼
class Article(models.Model):
title = models.CharField(max_length=30)
content = models.TextField()
# created_time = models.DateTimeField(default=timezone.now)
created_time = models.DateTimeField(auto_now_add=True)
last_updated_time = models.DateTimeField(auto_now=True)
author = models.ForeignKey(User, on_delete=models.CASCADE, default=1)
is_deleted = models.BooleanField(default=False)
readed_num = models.IntegerField(default=0)
# admin.py åå°æ¾ç¤ºå段
@admin.register(Article)
class ArticleAdmin(admin.ModelAdmin):
list_display = ('id', 'title', 'author','is_deleted', 'created_time', 'last_updated_time', 'content')
# ordering = ('-id', ) ååº
ordering = ('id', )
# 使ç¨ï¼è¿æ»¤å é¤ç views.py
def article_list(request):
# articles = Article.objects.all()
articles = Article.objects.filter(is_deleted=False)
- æ°æ®åºçå 个æ¦å¿µï¼ä¸»é®ï¼å¤é®ï¼ç´¢å¼ï¼å¯ä¸ç´¢å¼
- 主é®
primary keyï¼æ¯è½ç¡®å®ä¸æ¡è®°å½çå¯ä¸æ è¯ï¼å¦id - å¤é®
foreign keyï¼å¤é®ç¨äºä¸å¦ä¸å¼ 表çå ³èï¼ç¨äºä¿ææ°æ®çä¸è´æ§ï¼è¡¨çå¤é®æ¯å¦ä¸è¡¨ç主é®ã - ç´¢å¼
indexï¼ä¸ºäºæé«æ¥è¯¢æåºçé度ã - èéç´¢å¼ï¼å¨ç´¢å¼é¡µéç´æ¥åæ¾æ°æ®ï¼èéèéç´¢å¼å¨ç´¢å¼é¡µéåæ¾çæ¯ç´¢å¼ï¼è¿äºç´¢å¼æåä¸é¨çæ°æ®é¡µçæ°æ®ã
- 主é®åå¤é®æ¯æå¤ä¸ªè¡¨ç»ç»ä¸ºä¸ä¸ªææçå ³ç³»æ°æ®åºçç²ååã主é®åå¤é®ç设计对ç©çæ°æ®åºçæ§è½åå¯ç¨æ§é½æçå³å®æ§çå½±åã
- 主é®
06.å¼å§å®æ´å¶ä½ç½ç«
- æ³æ¸
æ¥ä¸ºä»ä¹åç½ç«ï¼å¨åå½±åå¦ä¹ çæ
ï¼åå å³å®æç»ç»æ
- å ´è¶£ç±å¥½
- å¦ä¹ ä¸é¨ææ¯
- å·¥ä½éè¦ï¼ä¸å¡éæ±
- åä¸é¡¹ç®éè¦
- å¦ä½ç¨Djangoå¼åç½ç«
- è¦åä»ä¹ï¼è®¾è®¡ç½ç«åå
- ä¸å¡æµç¨
- åè½æ¨¡å
- å端å¸å±
- å端模å
- è¦åä»ä¹ï¼è®¾è®¡ç½ç«åå
- æ¥ä¸æ¥çæç¨
- ç®ç
- éè¿å®æ´çå¼åè¿ç¨å¦ä¹ Django
- 对ä¸è¬çç½ç«å¼åæå ¨é¢ç认è¯
- éå¾
- å¶ä½ä¸ªäººå客ç½ç«
- ç®ç
- 个人å客ç½ç«
- 项ç®ç®¡ç
- IDE
- æ¬å°èæå¼åç¯å¢
- çæ¬æ§å¶Gitï¼Github
- å端å¼å
- html+javascript+CSS
- jQuery
- Bootstrap
- ajax
- å端å¼å
- å客管çåå±ç¤º
- ç¨æ·ç»å½å注å
- è¯è®ºååå¤
- ç¹èµ
- æ°æ®åºåæå¡å¨
- MySQL
- Linux
- ç½ç«é¨ç½²
- 项ç®ç®¡ç
07.æå»ºä¸ªäººå客ç½ç«
-
ç½ç«çåè½æ¨¡å å³ Django App
- å客
- åæ
- å客åç±»
- å客æ ç¾
- è¯è®º
- ç¹èµ
- é 读
- ç¨æ·
- å客
-
å¼å¯æ¬å°èæç¯å¢
- éå¼python项ç®çè¿è¡ç¯å¢
- é¿å å¤ä¸ªé¡¹ç®ä¹åpythonåºçå²çª
- 宿´ä¾¿æ·å¯¼åºpythonåºçå表
pip install virtualenv
virtualevn mysit_env # å建 èæç¯å¢
activate
deactivate
pip freeze > requirements.txt # ä¸é®å¯¼åº
pip install -r requirements.txt # ä¸é®å®è£
- 忥å建blogåºç¨
- åæ + å客åç±»
- 为äºå¥½ç®¡çï¼çº¦å®ä¸ç¯å客åªå±äºä¸ä¸ªåç±»
django-admin startproject mysite
cd mysite
python manage.py startapp blog
python manage.py migrate
python manage.py createsuperuser
# ä¿®æ¹æ¨¡åï¼å
å¨INSTALLED_APPS䏿·»å app name
python manage.py makemigrations
python manage.py migrate
- å建Blog模ååæ³¨åadminåå°æ¨¡å管ç页é¢
# models.py
# Create your models here.
class BlogType(models.Model):
type_name = models.CharField(max_length=15)
def __str__(self):
return self.type_name
class Blog(models.Model):
title = models.CharField(max_length=50)
blog_type = models.ForeignKey(BlogType, on_delete=models.CASCADE)
content = models.TextField()
author = models.ForeignKey(User, on_delete=models.CASCADE)
created_time = models.DateTimeField(auto_now_add=True)
last_updated_time = models.DateTimeField(auto_now=True)
def __str__(self):
return '<Blog: %s>' % self.title
# admin.py
from django.contrib import admin
from .models import BlogType, Blog
# Register your models here.
@admin.register(BlogType)
class BlogTypeAdmin(admin.ModelAdmin):
list_display = ('id', 'type_name')
@admin.register(Blog)
class BlogAdmin(admin.ModelAdmin):
list_display = ('id', 'title', 'blog_type', 'author', 'created_time', 'last_updated_time')
ordering = ('id',)
08.常ç¨çæ¨¡çæ ç¾åè¿æ»¤å¨
-
ç»§ç»æå»ºblog
- models
- admin
- views
- urls
- templates
-
常ç¨çæ¨¡çæ ç¾
- å¾ªç¯ for
- æ¡ä»¶ if, ifequal, ifnoequal
- 龿¥ url
- 模çåµå¥ blockãextendsãinclude
- 注é {# #}
-
常ç¨çè¿æ»¤å¨
- æ¥æ data
- åæ°æªå truncatechars truncatechars_html
- é¿åº¦ length
<p>ä¸å
±æ {{ blogs|length }} ç¯å客 </p>
context['blogs_count'] = Blog.objects.all().count
{{ blogs_count }}
09.模çåµå¥
-
{% extends "base.html" %}å¼ç¨åºç¡æ¨¡ç -
<title>{% block title %}{% endblock title %}</title>å -
{% block content %}{% endblock content %} -
å ¨å±æ¨¡çæä»¶å¤¹, åæ¾å ¬å ±æ¨¡çæä»¶
- å¨
manage.pyç®å½å建æä»¶å¤¹templatesï¼åæ¾å ¬å ±æ¨¡çæä»¶ - 设置è½å¤æ¾å°ç®å½
settings - TEMPLATES - DIRS os.path.join(BASE_DIR, 'templates'),- å°
base.htmlæ¾å°å ¬å ±æ¨¡çæä»¶å¤¹
- å¨
-
模çæä»¶è®¾ç½®å»ºè®®ï¼ä¸ºäºæ¹ä¾¿è¿ç§»åå ¬æï¼æ¾å°projectçtemplatesæä»¶å¤¹
- 为äºé²æ¢ååå²çªï¼å¨templatesæ°å»ºapp nameçæä»¶å¤¹ï¼é²æ¢æ··æ·
- ä¿®æ¹views.pyéçæä»¶è·¯å¾
10.使ç¨CSSç¾å页é¢
-
页é¢è®¾è®¡
- å¯¼èªæ ï¼xxxçç½ç« é¦é¡µ
- 主ä½å 容
- 尾注
-
使ç¨CSS å±å æ ·å¼è¡¨ï¼ä¿®é¥°html
- 使ç¨Chromeæµè§å¨å®¡æ¥å ç´ ï¼æ¹ä¾¿è°è¯ä¿®æ¹cssï¼æ¹å¥½äºåå¤å¶æ ·å¼
-
æ°å»ºstaticæä»¶å¤¹ï¼ä¸é¨åæ¾éææä»¶ï¼css js å¾ç
- å¨
manage.pyç®å½å建æä»¶å¤¹staticï¼åæ¾éææä»¶ - 设置è½å¤æ¾å°ç®å½
settings - STATICFILES_DIRS os.path.join(BASE_DIR, 'static')- å¼ç¨
<link rel="stylesheet" href="/static/base.css"> - æè
å
{% load staticfiles %} - å
<link rel="stylesheet" href="{% static 'base.css' %}">
- å¨
11.CSSæ¡æ¶åå©å端å¸å±
- 为ä»ä¹ä½¿ç¨CSSæ¡æ¶
- 让webå¼åæ´è¿ éãç®å
- 使ç¨ç°æçæ¡æ¶ çæ¶åçå
- å¦ä½éæ©CSSæ¡æ¶
- æç¨æ§
- å ¼å®¹æ§
- 大å°ãææååè½
- Bootstrap
- ææ¡£é½å ¨ï¼ä½¿ç¨ç®å
- å ¼å®¹è¾å¤æµè§å¨ï¼éè½»é级
- ååºå¼å¸å±ãç§»å¨è®¾å¤ä¼å
- ç»ä»¶é½å ¨ï¼æå¹³ç®æ´
- é¨ç½²Bootstrap
- æå¼å®ç½ http://www.Bootcss.com
- ä¸è½½ 龿¥ ãå¼ç¨ã使ç¨
miniæ¯å缩è¿çä½ç§¯å°- ç»ä»¶ åä½å¾æ
- å¸å±å®¹å¨
- æ æ ¼ç³»ç»
- html èªå¨è¡¥å ¨æå·§ div.nav li*2>2 æå车
12.Bootstrapååºå¼å¸å±
- æ·»å å客å表åå类两æ ï¼å¹¶æ ¹æ®å±å¹èªéåºè°æ´ä½ç½®å¤§å°
- æ æ ¼ç³»ç»åçå代ç
- å客å类使ç¨ç颿¿ä»£ç
- æ·»å æ¡æ¶èªå¸¦ç徿
- Djangoéææä»¶å½å空é´
- 为äºé¿å
å²çªé®é¢
static/appname/xxx.css
- 为äºé¿å
å²çªé®é¢
13.å页åshellå½ä»¤è¡æ¨¡å¼
-
éè¿è®²è§£å页åè½è¿ä¸æ¥å¤¯å®åºç¡ï¼å æ¬shellå½ä»¤è¡æ¨¡å¼ã模åæä½ãæ¨¡çæ ç¾ãå页å¨ãGET请æ±ã
-
为ä»ä¹éè¦å页?
- å½å客æç« æ°è¿å¤ï¼å ¨é¨å è½½è¿æ ¢ï¼å°±éè¦å页å è½½
-
shell å½ä»¤è¡æ¨¡å¼å¿«éå¦ä¹ å®è·µï¼æ·»å å客
python manage.py shell- for æ§è¡æ°å¢å客代ç
-
æ¨¡åæ°å¢å¯¹è±¡
python manage.py shell
from blog.models import Blog
blog = Blog() # å®ä¾å
blog.title = 'xxx'
...
blog.save()
- shell å½ä»¤è¡ æ¨¡å¼ æä½æ¨¡å
>>> from blog.models import Blog
>>> dir()
['Blog', '__builtins__']
>>> Blog.objects.all()
<QuerySet [<Blog: <Blog: 第ä¸ç¯å客>>, <Blog: <Blog: 第äºç¯å客>>, <Blog: <Blog: 第ä¸ç¯å客>>, <Blog: <Blog: 第åç¯é¿å
容>>]>
>>> Blog.objects.count()
4
>>> blog = Blog()
>>> dir()
['Blog', '__builtins__', 'blog']
>>> blog.title = 'shell ä¸ç¬¬1ç¯'
>>> blog.content = 'xxxx'
>>> from blog.models import BlogType
>>> BlogType.objects.all()
<QuerySet [<BlogType: éç¬>, <BlogType: ææ>, <BlogType: å
¶ä»>]>
>>> BlogType.objects.all()[2]
<BlogType: å
¶ä»>
>>> blog_type = BlogType.objects.all()[2]
>>> blog.blog_type = blog_type
>>> from django.contrib.auth.models import User
>>> User.objects.all()
<QuerySet [<User: able>]>
>>> user = User.objects.all()[0]
>>> blog.author = user
>>> blog.save()
>>> Blog.objects.all()
<QuerySet [<Blog: <Blog: 第ä¸ç¯å客>>, <Blog: <Blog: 第äºç¯å客>>, <Blog: <Blog: 第ä¸ç¯å客>>, <Blog: <Blog: 第åç¯é¿å
容>>, <Blog: <Blog: shell ä¸ç¬¬1ç¯>>]>
>>> dir(blog) # æ¥çææ å±æ§åæ¹æ³ï¼æ¹ä¾¿ç¨åè°ç¨
# æ¹éæ·»å
>>> for i in range(1, 31):
... blog = Blog()
... blog.title = 'for %s' % i
... blog.content = 'xxxx:%s' % i
... blog.blog_type = blog_type
... blog.author = user
... blog.save()
...
>>> Blog.objects.all().count()
35
- å页å¨å®ç°å页
- 导å
¥
from django.core.paginator import Paginator - å®ä¾å
paginator = Paginator(object_list, each_page_count) - å
·ä½é¡µé¢
page1 = paginator.page(1)
- 导å
¥
>>> from django.core.paginator import Paginator
>>> from blog.models import Blog
>>> blogs = Blog.objects.all()
>>> blogs.count()
35
>>> paginator = Paginator(blogs, 10)
<string>:1: UnorderedObjectListWarning: Pagination may yield inconsistent results with an unordered object_list: <class 'blog.models.Blog'> QuerySet.
# éè¦ç»æ¨¡åæ·»å æåºæ¹å¼
class Meta:
ordering = ['-created_time']
# ç¶åæ°æ®è¿ç§»
python manage.py makemigrations
python manage.py migrate
>>> paginator = Paginator(blogs, 10)
>>> paginator
<django.core.paginator.Paginator object at 0x1021de550>
>>> dir(paginator)
>> paginator.count
35
>>> paginator.num_pages
4
>>> page1 = paginator.page(1)
>>> page1
<Page 1 of 4>
>>> page1.object_list
14.ä¼åå页å±ç¤º
- ä¼åå页æ¾ç¤ºï¼æåç¨æ·ä½éª
- ä¸è¦æ¾ç¤ºå¤ªå¤é¡µç éæ©ï¼å½±å页é¢å¸å±
- é«äº®æ¾ç¤ºå½å页ç
- é¡µç æ ï¼ä¼åæ¾ç¤ºç页ç èå´ï¼è¿é¨åçä¼¼ç®åï¼å 容ä¸å°
current_page_num = page_of_blogs.number # è·åå½å页ç
# è·åå½å页çåå2页ç页ç èå´
page_range = [x for x in range(current_page_num - 2, current_page_num + 3) if x in paginator.page_range ]
# å ä¸çç¥å·é´é页ç
if page_range[0] - 1 >= 2:
page_range.insert(0, '...')
if paginator.num_pages - page_range[-1] >= 2:
page_range.append('...')
# å ä¸é¦é¡µå尾页
if page_range[0] != 1:
page_range.insert(0, 1)
if page_range[-1] != paginator.num_pages:
page_range.append(paginator.num_pages)
-
å ¬ç¨å ¨å±è®¾ç½®æ¾å¨settingä¸ï¼ç»ä¸ç®¡ç
- å¼ç¨
from django.conf import settings; settings.xxx
- å¼ç¨
15.ä¸ä¸ç¯å客忿åç±»
- 对æ¯å½åå客ï¼å¾å°ä¸ä¸ç¯æä¸ä¸ç¯
blog = get_object_or_404(Blog, pk=blog_pk)
context['previous_blog'] = Blog.objects.filter(created_time__gt=blog.created_time).last()
context['next_blog'] = Blog.objects.filter(created_time__lt=blog.created_time).first()
context['blog'] = blog
.objects.filter()ç鿡件- æ¯è¾
__gt__gte__lt__lte - å
å«
__contains - å¼å¤´æ¯
__startswith - ç»å°¾æ¯
__endswith __in__range
- æ¯è¾
>>> from blog.models import Blog
>>> Blog.objects.filter(title__contains='shell')
<QuerySet [<Blog: <Blog: shell ä¸ç¬¬1ç¯>>]>
>>> Blog.objects.filter(title__startswith='shell')
<QuerySet [<Blog: <Blog: shell ä¸ç¬¬1ç¯>>]>
>>> Blog.objects.filter(id__in=[1,2,3])
<QuerySet [<Blog: <Blog: 第ä¸ç¯å客>>, <Blog: <Blog: 第äºç¯å客>>, <Blog: <Blog: 第ä¸ç¯å客>>]>
>>> Blog.objects.filter(id__range=(1, 3))
<QuerySet [<Blog: <Blog: 第ä¸ç¯å客>>, <Blog: <Blog: 第äºç¯å客>>, <Blog: <Blog: 第ä¸ç¯å客>>]>
.objects.exclude()æåºæ¡ä»¶ï¼åfilterç¸åï¼é½æ¯å¾å°æ¥è¯¢QuerySet- å å
¥åä¸å线çéï¼ç¨äº
- åæ®µæ¥è¯¢ç±»å
- å¤é®æå±ï¼ä»¥å客å类为ä¾
- æ¥ææå±ï¼ä»¥ææä»½ä¸ºä¾
- æ¯æé¾å¼éæ°ï¼å¯ä»¥ä¸ç´é¾æ¥ä¸å»
- ææ¥ææ¥è¯¢ .objects.dates()
- "month" returns a list of all distinct year/month values for the field.
Blog.objects.dates('created_time', 'month', order='DESC')- asc æååºæå, desc æéåºæå
16.ç»è®¡åç±»åå®¢çæ°é
- è·åå客åç±»ç对åºå客æ°é
- æ¹æ³ä¸ï¼éå ä¸ä¸ªæ°é屿§
# è·åå客åç±»ç对åºå客æ°é
blog_types = BlogType.objects.all()
blog_types_list = []
for blog_type in blog_types:
blog_type.blog_count = Blog.objects.filter(blog_type=blog_type).count()
blog_types_list.append(blog_type)
# context['blog_types'] = BlogType.objects.all()
context['blog_types'] = blog_types_list
- æ¹æ³äºï¼ä½¿ç¨annotateæå±æ¥è¯¢åæ®µï¼æ³¨éç»è®¡ä¿¡æ¯
from django.db.models import Count
BlogType.objects.annotate(blog_count=Count('blog'))
context['blog_types'] = BlogType.objects.annotate(blog_count=Count('blog'))
- è·åæ¥æå½æ¡£å¯¹åºçå客æ°é
blog_dates = Blog.objects.dates('created_time', 'month', order='DESC')
blog_dates_dict = {}
for blog_date in blog_dates:
blog_count = Blog.objects.filter(created_time__year=blog_date.year, created_time__month=blog_date.month).count()
blog_dates_dict[blog_date] = blog_count
context['blog_dates'] = blog_dates_dict
17.å客åå°å¯ææ¬ç¼è¾
- 使ç¨html丰å¯é¡µé¢
- ç®åææ¬ç¼è¾ -ãç´æ¥è´´å ¥html代ç
{{ blog.content|safe }} # å®å
¨çï¼å¯ä»¥è¯å«html tab
{{ blog.content|striptags|truncatechars:120 }} # ææ¶ä¸ç¨æ¾ç¤ºtagï¼è¿æ»¤ætag
- 坿æ¬ç¼è¾ -ã æç»è§£ææhtmlï¼å¯ææ¬ç¼è¾å¨ãmarkdownç¼è¾å¨
- 使ç¨django-ckeditor, éæ©æ å
- å ·æåºæ¬ç坿æ¬ç¼è¾åè½
- ææç»æ´æ°ç»´æ¤
- å¯ä»¥æ¥çæºç
- å¯ä»¥ä¸ä¼ å¾ç
- å®è£
django-ckeditor 龿¥
pip install django-ckeditor- 注ååºç¨
ckeditor - é ç½®models, æåæ®µæ¹æRichTextField
- æ§è¡æ°æ®åºè¿ç§»ï¼è¿åå°ç¼è¾å客就å¯ä»¥çå°
- æ·»å ä¸ä¼ å¾çåè½
pip install pillow- 注ååºç¨
ckeditor_uploader - é ç½®setting, mediaè·¯å¾
- é ç½®url
- é ç½®modelï¼æåæ®µæ¹æRichTextUploadingField
# media
MEDIA_URL = '/media/'
MEDIA_ROOT = os.path.join(BASE_DIR, 'media')
# é
ç½®ckeditor
CKEDITOR_UPLOAD_PATH = 'upload/'
# urls.py
from django.contrib import admin
from django.urls import path, include
from django.conf import settings
from django.conf.urls.static import static
# from blog.views import blog_list
from . import views
urlpatterns = [
path('', views.home, name='home'),
path('admin/', admin.site.urls),
path('ckeditor', include('ckeditor_uploader.urls')),
path('blog/', include('blog.urls')),
]
urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
# models
from ckeditor_uploader.fields import RichTextUploadingField
content = RichTextUploadingField()
18.å客é 读ç®å计æ°
-
ç®å计æ°å¤ç
- Blogæ¨¡åæ·»å æ°ååæ®µè®°å½
- æ¯æ¬¡æå¼é¾æ¥ï¼è®°å½+1
-
èªå®ä¹è®¡æ°è§åï¼ ææ ·æç®é è¯»ä¸æ¬¡
- æ è§æ¯å¦åä¸ä¸ªäººï¼æ¯æ¬¡æå¼é½è®°å½ï¼ä¼é æå·é 读éï¼å·æ°å³å¯
- è¥åä¸ä¸ªäººï¼é´éå¤ä¹ æç®é 读1次
-
éè¿è®¾ç½®æµè§å¨cookie计æ°ï¼é²æ¢ä¸äººå¤æ¬¡è®¡æ°
# 妿æµè§å¨ä¸æ²¡æè®¾ç½®çcookieäºï¼å°±è®¡æ°
if not request.COOKIES.get('blog_%s_readed' % blog_pk):
blog.readed_num += 1
blog.save()
response = render(request, 'blog/blog_detail.html', context)
# response.set_cookie('blog_%s_readed' % blog_pk, 'true', max_age=60) # 60s 失æ
response.set_cookie('blog_%s_readed' % blog_pk, 'true') # é»è®¤éåºæµè§å¨å¤±æ
return response
- COOKIES è®¡æ°æ¹æ³ç缺ç¹
- åå°ç¼è¾å客å¯è½å½±å计æ°ï¼èä¸è®¡æ°çæ´æ°ä¹ä¼æ´æ°äºåå®¢çæ¶é´
- åè½åä¸ï¼æ æ³ç»è®¡æä¸å¤©çé 读é
19.å客é 读计æ°ä¼å
æ¹æ³ä¸
- æ·»å æ°çè®¡æ°æ¨¡åï¼è®¡æ°åè½ç¬ç«ï¼åå°å¯¹åå客çå½±å
- 计æ°å段 å å客 éè¿ å¤é® å ³è
class ReadNum(models.Model):
read_num = models.IntegerField(default=0)
blog = models.OneToOneField(Blog, on_delete=models.CASCADE)
# æè
blog = models.ForeignKey(Blog, on_delete=models.CASCADE)
@admin.register(ReadNum)
class ReadNumAdmin(admin.ModelAdmin):
list_display = ('read_num', 'blog')
if not request.COOKIES.get('blog_%s_readed' % blog_pk):
# blog.readed_num += 1
# blog.save()
if ReadNum.objects.filter(blog=blog):
# åå¨è®°å½
readnum = ReadNum.objects.get(blog=blog)
else:
# ä¸åå¨è®°å½
readnum = ReadNum(blog=blog)
# 计æ°å 1
readnum.read_num += 1
readnum.save()
æ¹æ³äº
-
å建ä¸é¨ç¨äºè®¡æ°çåºç¨ï¼ç¬ç«åºæ´å éç¨ç计æ°åè½ï¼å¯ä»¥å¯¹ä»»ææ¨¡å计æ°
- 计æ°ï¼ å ³èåªä¸ªæ¨¡å + 对åºä¸»é®å¼
- ContentType
-
å建ä¸é¨ç¨äºè®¡æ°çåºç¨
python manage.py startapp read_statistics
-
æ·»å è®¡æ° models
from django.db import models
from django.contrib.contenttypes.fields import GenericForeignKey
from django.contrib.contenttypes.models import ContentType
# Create your models here.
class ReadNum(models.Model):
read_num = models.IntegerField(default=0)
content_type = models.ForeignKey(ContentType, on_delete=models.CASCADE)
object_id = models.PositiveIntegerField()
content_object = GenericForeignKey('content_type', 'object_id')
- 注ååºç¨
- æ°æ®è¿ç§»
- æ·»å åå°ç®¡ç
from django.contrib import admin
from .models import ReadNum
# Register your models here.
@admin.register(ReadNum)
class ReadNumAdmin(admin.ModelAdmin):
list_display = ('read_num', 'content_object')
- å¨Blog模åä¸å¼ç¨æ·»å ReadNum
# shell ä¸å®è·µ 使ç¨
>>> from read_statistics.models import ReadNum
>>> from blog.models import Blog
>>> from django.contrib.contenttypes.models import ContentType
>>> ContentType.objects.filter(model='blog')
<QuerySet [<ContentType: blog>]>
>>> ContentType.objects.get_for_model(Blog)
<ContentType: blog>
>>> ct = ContentType.objects.get_for_model(Blog)
>>> blog = Blog.objects.first()
>>> blog.pk
1
>>> ReadNum.objects.filter(content_type=ct, object_id=blog.pk)
<QuerySet [<ReadNum: ReadNum object (2)>]>
>>> rn = ReadNum.objects.filter(content_type=ct, object_id=blog.pk)[0]
>>> rn
<ReadNum: ReadNum object (2)>
>>> rn.read_num
11
- æåï¼æåä¼åï¼éæ°å°è£ å ¬å ±åºç¨ï¼æ½åºå ¬ç¨çæ¹æ³
20.é 读计æ°ç»è®¡åæ¾ç¤º
- æ·»å ç»è®¡æ¯å¤©çé 读é
class ReadDetail(models.Model):
date = models.DateField(default=timezone.now)
read_num = models.IntegerField(default=0)
content_type = models.ForeignKey(ContentType, on_delete=models.CASCADE)
object_id = models.PositiveIntegerField()
content_object = GenericForeignKey('content_type', 'object_id')
@admin.register(ReadDetail)
class ReadDetailAdmin(admin.ModelAdmin):
list_display = ('date', 'read_num', 'content_object')
# æ¯å¤©é
读é + 1
date = timezone.now().date()
if ReadDetail.objects.filter(content_type=ct, object_id=obj.pk, date=date).count():
# åå¨è®°å½
readDetail = ReadDetail.objects.get(content_type=ct, object_id=obj.pk, date=date)
else:
# ä¸åå¨è®°å½
readDetail = ReadDetail(content_type=ct, object_id=obj.pk, date=date)
# 计æ°å 1
readDetail.read_num += 1
readDetail.save()
- ç®å代ç ï¼ä½¿ç¨ .objects.get_or_create
# æ¯å¤©é
读é + 1
date = timezone.now().date()
readDetail, created = ReadDetail.objects.get_or_create(content_type=ct, object_id=obj.pk, date=date)
readDetail.read_num += 1
readDetail.save()
- ç»è®¡æè¿7天çé 读é
# ç»è®¡æè¿7天é
读é
def get_seven_days_read_data(content_type):
today = timezone.now().date()
read_nums = []
for i in range(6, -1, -1):
date = today - datetime.timedelta(days=i)
read_details = ReadDetail.objects.filter(
content_type=content_type, date=date)
result = read_details.aggregate(read_num_sum=Sum('read_num')) # èå
read_nums.append(result['read_num_sum'] or 0) # 空å为0
return read_nums
def home(request):
blog_content_type = ContentType.objects.get_for_model(Blog)
read_nums = get_seven_days_read_data(blog_content_type)
context = {}
context['read_nums'] = read_nums
return render(request, 'home.html', context)
# shell å®è·µçè§£ Sum å aggregate
>>> from django.db.models import Sum
>>> from read_statistics.models import ReadDetail
>>> rds = ReadDetail.objects.all()
>>> rds.aggregate(read_num_sum=Sum('read_num')) # è¿åç»æçdict
{'read_num_sum': 8}
- 使ç¨å¾è¡¨æ¾ç¤ºæ°æ®
- åå° + åç«¯ï¼ å尿便°æ®ï¼åå°ä½¿ç¨æ°æ®
- 1 åé䏿 Highcharts
21.çé¨é 读å客æè¡åç¼åæé
è¿ä¸æ¥ä½¿ç¨é 读éçæ°æ®ï¼å¾å°çé¨å客并å°å ¶æ¾ç¤ºå¨é¦é¡µãèè·åç鍿°æ®å¯è½è®¡ç®éè¦ä¸ç¹æ¶é´ï¼å¦æå¾å¤æå¾å¤çè¯ï¼ï¼ä½¿ç¨æå¡å¨ç¼åä¿åæ°æ®ï¼è¾¾å°æéçææ
- å©ç¨é
è¯»éæ°æ®ï¼å¾å°çé¨å客并å°å
¶æ¾ç¤ºå¨é¦é¡µ
- 24å°æ¶å ä»å¤©æ°æ®ç»è®¡
- æ¨å¤©æ°æ®ç»è®¡
- ä¸å¨æ°æ®ç»è®¡
- ä¸ææ°æ®ç»è®¡
# è·å仿¥ç鍿ç«
def get_today_hot_data(content_type):
today = timezone.now().date()
read_details = ReadDetail.objects.filter(
content_type=content_type, date=today).order_by('-read_num')
return read_details[:7] # åå7æ¡
# è·åæ¨å¤©ç鍿ç«
def get_yesterday_hot_data(content_type):
today = timezone.now().date()
yesterday = today - datetime.timedelta(days=1)
read_details = ReadDetail.objects.filter(
content_type=content_type, date=yesterday).order_by('-read_num')
return read_details[:7]
# è·å7天ç鍿ç«
def get_7_days_hot_data(content_type):
today = timezone.now().date()
date = today - datetime.timedelta(days=7)
blogs = Blog.objects\
.filter(read_details__date__lt=today, read_details__date__gte=date)\
.values('id', 'title')\
.annotate(read_num_sum=Sum('read_details__read_num'))\
.order_by('-read_num_sum')
return blogs[:7]
# æ°æ®åç» èå æ¥è¯¢ å®è·µ GenericRelation
from django.contrib.contenttypes.fields import GenericRelation
class Blog(models.Model, ReadNumExpandMethod):
read_details = GenericRelation(ReadDetail)
>>> from blog.models import Blog
>>> blog = Blog.objects.first()
>>> blog
<Blog: <Blog: 第ä¸ç¯å客 éç¬>>
>>> blog.read_details.all()
<QuerySet [<ReadDetail: ReadDetail object (4)>]>
>>> import datetime
>>> from django.utils import timezone
>>> toda = timezone.now().date()
>>> today = timezone.now().date()
>>> date = today - datetime.timedelta(days=7)
>>> Blog.objects.filter(read_details__date__lt=today, read_details__date__gte=date)
<QuerySet [<Blog: <Blog: 第ä¸ç¯å客 éç¬>>, <Blog: <Blog: 第2ç¯å客 éç¬>>]>
>>> blogs = Blog.objects.filter(read_details__date__lt=today, read_details__date__gte=date)
>>> blogs.values('id', 'title')
<QuerySet [{'id': 1, 'title': '第ä¸ç¯å客 éç¬'}, {'id': 2, 'title': '第2ç¯å客 éç¬'}]>
>>> from django.db.models import Sum
>>> blogs.values('id', 'title').annotate(read_num_sum=Sum('read_details__read_num')).order_by('-read_num_sum')
<QuerySet [{'id': 2, 'title': '第2ç¯å客 éç¬', 'read_num_sum': 20}, {'id': 1, 'title': '第ä¸ç¯å客 éç¬', 'read_num_sum': 7}]>
-
æ¯æ¬¡è®¡æ°ç»è®¡æ°éï¼éå¸¸èæ¶
- çç¥ï¼ç¼åæ°æ®ï¼ä¸ç¨æ¯æ¬¡é½è®¡ç®
- Djangoâs cache framework
- å åç¼åï¼Memcached, Redis
- æ°æ®åºç¼å
- æä»¶ç¼å
-
æ°æ®åºç¼å
CACHES = {
'default': {
'BACKEND': 'django.core.cache.backends.db.DatabaseCache',
'LOCATION': 'my_cache_table', # ç¼å表å
}
}
# Creating the cache table
python manage.py createcachetable
#Basic usage¶
#The basic interface is set(key, value, timeout) and get(key):
from django.core.cache import cache
>>> cache.set('my_key', 'hello, world!', 30)
>>> cache.get('my_key')
'hello, world!'
- è·å7天çé¨å客çç¼åæ°æ®
from django.core.cache import cache
hot_data_for_7_days = cache.get('hot_data_for_7_days')
if hot_data_for_7_days is None:
hot_data_for_7_days = get_7_days_hot_data(blog_content_type)
cache.set('hot_data_for_7_days', hot_data_for_7_days, 20)
print('calc')
else:
print('use cache')
22.è¯è®ºåè½è®¾è®¡åç¨æ·ç»å½
-
主è¦è®¾è®¡è¯è®ºæ¨¡åãç¨æ·ç»å½ãç®åform表åæäº¤ä»¥åæ´æ£ä¹åçrender_to_response为render
-
å®ç°è¯è®ºåè½çæ¹å¼
- ç¬¬ä¸æ¹è¯è®ºæä»¶ï¼å¦åè¨ï¼å¤è¯´ï¼Disqusï¼ç½ææ´è´´
- Django è¯è®ºåºï¼django-comment
- èªå·±å代ç å®ç°
-
å建è¯è®ºæ¨¡å
- è¯è®ºå¯¹è±¡
- è¯è®ºè
- è¯è®ºå 容
- è¯è®ºæ¶é´
-
å®ç°è¿ç¨
- å建åºç¨
python manage.py startapp comment - åå»ºæ°æ®ç模åmodels
- 注ååå°ç®¡ç页é¢
- 注åapp
- è¿ç§»æ°æ®åº
- å建åºç¨
# models
from django.db import models
from django.contrib.contenttypes.fields import GenericForeignKey
from django.contrib.contenttypes.models import ContentType
from django.contrib.auth.models import User
class Comment(models.Model):
# ä¸é¢3è¡ç¨æ¥å
³èä»»æç±»å
content_type = models.ForeignKey(ContentType, on_delete=models.CASCADE)
object_id = models.PositiveIntegerField()
content_object = GenericForeignKey('content_type', 'object_id')
text = models.TextField()
comment_time = models.DateTimeField(auto_now_add=True)
user = models.ForeignKey(User, on_delete=models.CASCADE)
# admin
from django.contrib import admin
from .models import Comment
@admin.register(Comment)
class CommentAdmin(admin.ModelAdmin):
list_display = ('content_object', 'text', 'comment_time', 'user')
python manage.py makemigrations
python manage.py migrate
-
è¯è®ºéè¦ç¨æ·ç»å½
- åå°åå¾è¯è®º
- 使é«äºè¯è®ºé¨æ§ï¼å¯ä»¥ä½¿ç¨ç¬¬ä¸æ¹ç»å½è§£å³
- è¿å¯ä»¥åééç¥ç»ç¨æ·
-
å¦ä½å¤æç¨æ·æ¯å¦ç»å½
context['user'] = request.user # è·åç¨æ·ä¿¡æ¯render(request, 'blog/blog_detail.html', context)- å 为éè¦ä½¿ç¨requestï¼éè¦ç¨
render代æ¿render_to_response - å 为模çsettingsä¸é¢å
å¼ç¨äºauthï¼ç´æ¥ä¼ requestï¼æ¨¡çä¸å¯ä»¥ä½¿ç¨ç¨æ·
{{ user }}
#If the current user has not logged in, this attribute will be set to an instance of AnonymousUser, otherwise it will be an instance of User.
if request.user.is_authenticated:
# Do something for authenticated users.
...
else:
# Do something for anonymous users.
...
#This example shows how you might use both authenticate() and login():
from django.contrib.auth import authenticate, login
def my_view(request):
username = request.POST['username']
password = request.POST['password']
user = authenticate(request, username=username, password=password)
if user is not None:
login(request, user)
# Redirect to a success page.
...
else:
# Return an 'invalid login' error message.
...
23.html表åæäº¤è¯è®º
- è·åè¯·æ±æ¶ç½åï¼ç»å½æååè¿åå页é¢
from django.urls import reverse
# referer = request.META.get('HTTP_REFERER', '/') # è·åè¯·æ±æ¶ç½åï¼ç»å½æååè¿å
referer = request.META.get('HTTP_REFERER', reverse('home')) #å«åæ¾å°é¾æ¥
if user is not None:
auth.login(request, user)
return redirect(referer)
else:
return render(request, 'error.html', {'message': 'ç¨æ·åæå¯ç é误'})
- å¤çç¨æ·æäº¤çè¯è®º
def update_comment(request):
referer = request.META.get('HTTP_REFERER', reverse('home'))
# æ°æ®æ£æ¥
if not request.user.is_authenticated:
return render(request, 'error.html', {'message': '请å
ç»å½', 'redirect_to': referer})
text = request.POST.get('text', '').strip() # å¤ä¸ªç©ºæ ¼ä¹æ¯ç©ºå
容
if text == '':
return render(request, 'error.html', {'message': 'è¯è®ºå
容ä¸è½ä¸ºç©º', 'redirect_to': referer})
try:
content_type = request.POST.get('content_type', '')
object_id = int(request.POST.get('object_id', ''))
model_class = ContentType.objects.get(model=content_type).model_class()
model_obj = model_class.objects.get(pk=object_id)
except Exception as e:
return render(request, 'error.html', {'message': 'è¯è®ºå¯¹è±¡ä¸åå¨', 'redirect_to': referer})
# éè¿åä¿åæ°æ®
comment = Comment()
comment.user = user
comment.text = text
comment.content_object = model_obj
comment.save()
return redirect(referer) # æäº¤åéå®åå°å页é¢
- è¯è®ºå表æ¶é´éåºæ¾ç¤º, ææ°ç卿åé¢
- ä¿®æ¹å®ä¸éè¦æ°æ®è¿ç§»ï¼ç´æ¥çæ
class Comment(models.Model):
# ä¸é¢3è¡ç¨æ¥å
³èä»»æç±»å
content_type = models.ForeignKey(ContentType, on_delete=models.CASCADE)
object_id = models.PositiveIntegerField()
content_object = GenericForeignKey('content_type', 'object_id')
text = models.TextField()
comment_time = models.DateTimeField(auto_now_add=True)
user = models.ForeignKey(User, on_delete=models.CASCADE)
class Meta:
ordering = ['-comment_time'] # æ¶é´éåºï¼ææ°ç卿åé¢
- è·åè¯è®ºå表
def blog_detail(request, blog_pk):
blog = get_object_or_404(Blog, pk=blog_pk)
read_cookie_key = read_statistics_one_read(request, blog)
blog_content_type = ContentType.objects.get_for_model(blog)
comments = Comment.objects.filter(content_type=blog_content_type, object_id=blog.pk)
context = {}
context['comments'] = comments
context['previous_blog'] = Blog.objects.filter(created_time__gt=blog.created_time).last()
context['next_blog'] = Blog.objects.filter(created_time__lt=blog.created_time).first()
context['blog'] = blog
response = render(request, 'blog/blog_detail.html', context)
response.set_cookie(read_cookie_key, 'true') # é
读cookieæ è®°
return response
24.使ç¨Django Form表å
-
Django ç¨ Form ç±»æè¿° html 表åï¼ç®åæä½ï¼æ¹ä¾¿å¿«éå¼å
- æ¥ååå¤çç¨æ·æäº¤çæ°æ®
- å¯ä»¥æ£æ¥æäº¤çæ°æ®ï¼å°æ°æ®ç±»åè½¬æ¢æpythonçæ°æ®ç±»å
- å¯èªå¨çæhtml代ç
-
Django Form ç使ç¨
- å建 forms.py æä»¶
- åæ®µ å°±æ¯ html input æ ç¾
- æ¯ä¸ªå段类å齿ä¸ä¸ªéå½çé»è®¤Widgetç±»
-
å®å¶ç»å½è¡¨å
# forms.py
from django import forms
from django.contrib import auth
# å®å¶ç»å½è¡¨å
class LoginForm(forms.Form):
username = forms.CharField(label='ç¨æ·å', required=True) # é»è®¤ä¸ºTrue
password = forms.CharField(label='å¯ç ', widget=forms.PasswordInput)
# views.py
def login(request):
if request.method == 'POST':
login_form = LoginForm(request.POST)
if login_form.is_valid():
# éªè¯éè¿
username = login_form.cleaned_data['username']
password = login_form.cleaned_data['password']
user = auth.authenticate(request, username=username, password=password)
if user is not None:
auth.login(request, user)
return redirect(request.GET.get('from', reverse('home'))) # 没æå°±è·³è½¬é¦é¡µ
else:
login_form.add_error(None, 'ç¨æ·åæå¯ç é误') # æ·»å é误æç¤º
else:
# get å 载页é¢
login_form = LoginForm() # å®ä¾å表å
context = {}
context['login_form'] = login_form
return render(request, 'login.html', context)
# login.html
<form action="" method="POST">
{% csrf_token %}
{{ login_form }}
<input type="submit" value="ç»å½">
</form>
- å¦ä½è·åç¨æ·ç»å½åç页é¢ï¼æ¹ä¾¿ç»å½åè¿å
# ç»å½æ¶ç页é¢ï¼å¸¦ç彿¶çè·¯å¾
æªç»å½ï¼ç»å½åæ¹å¯è¯è®º
<a href="{% url 'login' %}?from={{ request.get_full_path }}">ç»å½</a>
# æ¿å°è·¯å¾ï¼å¦ææ²¡æå°±è·³è½¬é¦é¡µ
redirect(request.GET.get('from', reverse('home'))) # 没æå°±è·³è½¬é¦é¡µ
- ä¼åèªå®ä¹è¡¨åï¼æ·»å éªè¯æ°æ®æ¹æ³ï¼è®©è°ç¨æ¶çä»£ç æ¸ æ°æäº
class LoginForm(forms.Form):
username = forms.CharField(label='ç¨æ·å', required=True) # é»è®¤ä¸ºTrue
password = forms.CharField(label='å¯ç ', widget=forms.PasswordInput)
# éªè¯æ°æ®æ¹æ³
def clean(self):
username = self.cleaned_data['username']
password = self.cleaned_data['password']
user = auth.authenticate(username=username, password=password)
if user is None:
raise forms.ValidationError('ç¨æ·åæå¯ç é误')
elif:
self.cleaned_data['user'] = user
return self.cleaned_data
# ä¼ååçè°ç¨
def login(request):
if request.method == 'POST':
login_form = LoginForm(request.POST)
if login_form.is_valid():
user = login_form.cleaned_data['user']
auth.login(request, user)
return redirect(request.GET.get('from', reverse('home')))
else:
# get å 载页é¢
login_form = LoginForm() # å®ä¾å表å
context = {}
context['login_form'] = login_form
return render(request, 'login.html', context)
- Pythonå
建çfilter()彿°ç¨äºè¿æ»¤åºå, è¿æ»¤åºéè¦ç屿§ææ¹æ³
- filter()æ¥æ¶ä¸ä¸ªå½æ°åä¸ä¸ªåºåï¼æä¼ å ¥ç彿°ä¾æ¬¡ä½ç¨äºæ¯ä¸ªå ç´ ï¼ç¶åæ ¹æ®è¿å弿¯Trueåä¿ç
- filter()彿°è¿åçæ¯ä¸ä¸ªIterator
>>> from django import forms
>>> filter(lambda x: 'Input' in x, dir(forms))
<filter object at 0x10304ea58>
>>> list(filter(lambda x: 'Input' in x, dir(forms)))
['CheckboxInput', 'ClearableFileInput', 'DateInput', 'DateTimeInput', 'EmailInput', 'FileInput', 'HiddenInput', 'MultipleHiddenInput', 'NumberInput', 'PasswordInput', 'TextInput', 'TimeInput', 'URLInput']
>>>
>>> filter(lambda x: 'Field' in x, dir(forms))
<filter object at 0x10304e908>
>>> list(filter(lambda x: 'Field' in x, dir(forms)))
['BooleanField', 'BoundField', 'CharField', 'ChoiceField', 'ComboField', 'DateField', 'DateTimeField', 'DecimalField', 'DurationField', 'EmailField', 'Field', 'FileField', 'FilePathField', 'FloatField', 'GenericIPAddressField', 'ImageField', 'IntegerField', 'ModelChoiceField', 'ModelMultipleChoiceField', 'MultiValueField', 'MultipleChoiceField', 'NullBooleanField', 'RegexField', 'SlugField', 'SplitDateTimeField', 'TimeField', 'TypedChoiceField', 'TypedMultipleChoiceField', 'URLField', 'UUIDField']
- 使ç¨formsåbootstrapå®å¶ä¼åç»å½è¡¨åæ¾ç¤º
# å®å¶ç»å½è¡¨åæ¾ç¤º
class LoginForm(forms.Form):
username = forms.CharField(label='ç¨æ·å',
required=True, # é»è®¤ä¸ºTrue
widget=forms.TextInput(attrs={'class': 'form-control',
'placeholder':'请è¾å
¥ç¨æ·å'}))
# 设置渲æåçhtmlç屿§
password = forms.CharField(label='å¯ç ',
widget=forms.PasswordInput(attrs={'class': 'form-control', 'placeholder':'请è¾å
¥å¯ç '}))
<div class="containter">
<div class="row">
<div class="col-xs-4 col-xs-offset-4">
<div class="panel panel-default">
<div class="panel-heading">
<h3 class="panel-title">ç»å½</h3>
</div>
<div class="panel-body">
<form action="" method="POST">
{% csrf_token %}
{% comment %} {{ login_form }} å®å¶æ¾ç¤º {% endcomment %}
{% for field in login_form %}
<label for="field.id_for_label">{{ field.label }}</label>
{{ field }}
<p class="text-danger">
{{ field.errors.as_text }}
</p>
{% endfor %}
<span class="pull-left text-danger">{{ login_form.non_field_errors }}</span>
<input type="submit" value="ç»å½" class="btn btn-primary pull-right">
</form>
</div>
</div>
</div>
</div>
</div>
- å®å¶ç¨æ·æ³¨å表åï¼å¹¶éªè¯æ°æ®
class RegForm(forms.Form):
username = forms.CharField(label='ç¨æ·å',
required=True, # é»è®¤ä¸ºTrue
max_length=30,
min_length=4,
widget=forms.TextInput(attrs={'class': 'form-control',
'placeholder':'请è¾å
¥3-30ä½ç¨æ·å'}))
email = forms.EmailField(label='é®ç®±',
widget=forms.TextInput(attrs={'class': 'form-control',
'placeholder':'请è¾å
¥é®ç®±'}))
password = forms.CharField(label='å¯ç ',
min_length=6,
widget=forms.PasswordInput(attrs={'class': 'form-control', 'placeholder':'请è¾å
¥å¯ç '}))
password_again = forms.CharField(label='å¯ç ',
min_length=6,
widget=forms.PasswordInput(attrs={'class': 'form-control', 'placeholder':'åè¾å
¥ä¸æ¬¡å¯ç '}))
# éªè¯æ°æ®, æ¯å¦ææï¼æ¯å¦åå¨
def clean_username(self):
username = self.cleaned_data['username']
if User.objects.filter(username=username).exists():
raise forms.ValidationError('ç¨æ·åå·²åå¨')
return username
def clean_email(self):
email = self.cleaned_data['email']
if User.objects.filter(email=email).exists():
raise forms.ValidationError('é®ç®±å·²åå¨')
return email
def clean_password_again(self):
password = self.cleaned_data['password']
password_again = self.cleaned_data['password_again']
if password != password_again:
raise forms.ValidationError('两次è¾å
¥çå¯ç ä¸ä¸è´')
return password_again
- ä¼åå端 ç»å½ æ æ³¨å æé®
æªç»å½ï¼ç»å½åæ¹å¯è¯è®º
<a class="btn btn-primary" href="{% url 'login' %}?from={{ request.get_full_path }}">ç»å½</a>
<span>or</span>
<a class="btn btn-danger" href="{% url 'register' %}?from={{ request.get_full_path }}">注å</a>
- 注åç¨æ· å¤ç
def register(request):
if request.method == 'POST':
reg_form = RegForm(request.POST)
if reg_form.is_valid():
username = reg_form.cleaned_data['username']
password = reg_form.cleaned_data['password']
email = reg_form.cleaned_data['email']
# åå»ºç¨æ·
user = User.objects.create_user(username, email, password)
user.save()
# æè
'''
user = User()
user.username = username
user.email = email
user.set_password(password)
user.save()
'''
# ç»å½ç¨æ·
user = auth.authenticate(username=username, password=password)
auth.login(request, user)
# 跳转注åä¹åç页é¢
return redirect(request.GET.get('from', reverse('home')))
else:
reg_form = RegForm() # å®ä¾å表å
context = {}
context['reg_form'] = reg_form
return render(request, 'register.html', context)
25.表å坿æ¬ç¼è¾åajax弿¥æäº¤è¯è®º
-
django-ckeditor 坿æ¬è¡¨å
- æ¯ä¸ªå段类å齿ä¸ä¸ªéå½çé»è®¤Widgetç±»
- django-ckeditor æä¾ widget
from ckeditor.widget import CKEditorWidget
-
å°è¯è®ºè¡¨åç¬ç«åºæ¥ï¼æ¾å¨è¯è®ºåºç¨éï¼å®å¶è¯è®ºè¡¨åç±»ï¼æ·»å éªè¯è¡¨åé»è¾
# comment/forms.py
from django import forms
from django.contrib.contenttypes.models import ContentType
from django.db.models import ObjectDoesNotExist
class CommentForm(forms.Form):
content_type = forms.CharField(widget=forms.HiddenInput)
object_id = forms.IntegerField(widget=forms.HiddenInput)
text = forms.CharField(widget=forms.Textarea)
def __init__(self, *args, **kwargs):
if 'user' in kwargs:
self.user = kwargs.pop('user') # æ¥æ¶ç¨æ·ä¿¡æ¯, å¹¶åé¤ï¼ä¸ºäºä¸ä¸å¥ä¸åºé
super(CommentForm, self).__init__(*args, **kwargs)
# éªè¯æ°æ®
def clean(self):
# å¤æç¨æ·æ¯å¦ç»å½
if self.user.is_authenticated:
self.cleaned_data['user'] = self.user
else:
raise forms.ValidationError('ç¨æ·å°æªç»å½')
# è¯è®ºå¯¹è±¡éªè¯
content_type = self.cleaned_data['content_type']
object_id = self.cleaned_data['object_id']
try:
model_class = ContentType.objects.get(model=content_type).model_class()
model_obj = model_class.objects.get(pk=object_id)
self.cleaned_data['content_object'] = model_obj
except ObjectDoesNotExist:
raise forms.ValidationError('è¯è®ºå¯¹è±¡ä¸åå¨')
return self.cleaned_data
# æäº¤
<form action="{% url 'update_comment' %}" method="POST" style="overflow: hidden">
{% csrf_token %}
<label for="comment_text">{{ user.username }}ï¼æ¬¢è¿è¯è®ºï½</label>
{{ comment_form }}
<input type="submit" value="è¯è®º" class="btn btn-primary" style="float:right">
</form>
# å¤çé»è¾
def update_comment(request):
referer = request.META.get('HTTP_REFERER', reverse('home'))
comment_form = CommentForm(request.POST, user=request.user) # å®ä¾å, ä¼ éäºç¨æ·ä¿¡æ¯ï¼ç´æ¥æè¡¨åç±»éªè¯ç»å½
if comment_form.is_valid():
# éè¿åä¿åæ°æ®
comment = Comment()
comment.user = comment_form.cleaned_data['user']
comment.text = comment_form.cleaned_data['text']
comment.content_object = comment_form.cleaned_data['content_object']
comment.save()
return redirect(referer) # æäº¤åéå®åå°å页é¢
else:
return render(request, 'error.html', {'message': comment_form.errors, 'redirect_to': referer})
- æ·»å å¹¶å®å¶å¯ææ¬è¯è®ºè¡¨å
# forms.py
from ckeditor.widgets import CKEditorWidget
class CommentForm(forms.Form):
text = forms.CharField(widget=CKEditorWidget(config_name='comment_ckeditor'))
# settings.py æ·»å 设置å³å¯ï¼éè¿ comment_ckeditor
# é
ç½®ckeditorè¯è®ºè¡¨å
CKEDITOR_CONFIGS = {
'comment_ckeditor': {
'toolbar': 'custom',
'toolbar_custom': [
['Bold', 'Italic', 'Underline', 'Strike', 'Subscript', 'Superscript'],
['TextColor', 'BGColor', 'RemoveFormat'],
['NumberedList', 'BulletedList'],
['Link', 'Unlink'],
['Smiley', 'SpecialChar', 'Blockquote'],
],
'width': 'auto',
'height': '180',
'tabspace': 4,
'removePlugins': 'elementspath',
'resize_enable': False,
}
}
# å端å¼å
¥js
<script type="text/javascript" src="{% static "ckeditor/ckeditor-init.js" %}"></script>
<script type="text/javascript" src="{% static "ckeditor/ckeditor/ckeditor.js" %}"></script>
div.django-ckeditor-widget {
width: 100%;
}

-
ajax 弿¥æäº¤æ°æ®æ¹å¼ï¼jQuery - AJAX ç®ä»
- AJAX æ¯ä¸æå¡å¨äº¤æ¢æ°æ®çèºæ¯ï¼å®å¨ä¸éè½½å ¨é¨é¡µé¢çæ åµä¸ï¼å®ç°äºå¯¹é¨åç½é¡µçæ´æ°
- AJAX = 弿¥ JavaScript å XMLï¼Asynchronous JavaScript and XMLï¼
- å¨ä¸éè½½æ´ä¸ªç½é¡µçæ åµä¸ï¼AJAX éè¿åå°å è½½æ°æ®ï¼å¹¶å¨ç½é¡µä¸è¿è¡æ¾ç¤º
- ä½¿ç¨ AJAX çåºç¨ç¨åºæ¡ä¾ï¼è°·æå°å¾ãè ¾è®¯å¾®åãä¼é ·è§é¢ çç
- åºåå表åå¼ jQuery ajax - serialize() æ¹æ³
-
ajax请æ±
{# ajax 弿¥æäº¤, å ä¸ºç´æ¥æäº¤ä¼å·æ°é¡µé¢ #}
{% block script_extends %}
<script type="text/javascript">
$('#comment_form').submit(function(){
// 夿è¯è®ºå
容æ¯å¦ä¸ºç©º å
æ¬ç©ºçæ¢è¡
$("#comment_error").text('');
if(CKEDITOR.instances['id_text'].document.getBody().getText().trim() == ''){
$("#comment_error").text('è¯è®ºå
容为空');
return false;
}
// æ´æ°æ°æ®å°textareaéé¢
CKEDITOR.instances['id_text'].updateElement();
// 弿¥æäº¤
$.ajax({
url: "{% url 'update_comment' %}",
type: 'POST',
data: $(this).serialize(), // this å³ #comment_form
cache: false,
success: function(data){ // æäº¤æååè°ç¨çæ¹æ³
console.log(data);
// 妿æåï¼å°±æå
¥æ¾ç¤ºæ°æ®
$("#no_comment").remove();
if(data['status']=='SUCCESS'){
var comment_html = '<div>' + data['username'] +
' (' + data['comment_time'] + '): ' + data['text'] + '</div>';
$("#comment_list").prepend(comment_html);
// æ¸
空è¯è®ºåºå
容
CKEDITOR.instances['id_text'].setData('');
}else{
// æ¾ç¤ºé误信æ¯
$("#comment_error").text(data['message']);
}
},
error: function(xhr){ // æäº¤å¼å¸¸æ¶è°ç¨çæ¹æ³
console.log(xhr);
}
});
return false;
});
</script>
{% endblock script_extends %}
- å¤çajax请æ±
def update_comment(request):
# referer = request.META.get('HTTP_REFERER', reverse('home'))
comment_form = CommentForm(
request.POST, user=request.user) # å®ä¾å, ä¼ éäºç¨æ·ä¿¡æ¯ï¼ç´æ¥æè¡¨åç±»éªè¯ç»å½
data = {}
if comment_form.is_valid():
# éè¿åä¿åæ°æ®
comment = Comment()
comment.user = comment_form.cleaned_data['user']
comment.text = comment_form.cleaned_data['text']
comment.content_object = comment_form.cleaned_data['content_object']
comment.save()
# è¿åæ°æ®
data['status'] = 'SUCCESS'
data['username'] = comment.user.username
data['comment_time'] = comment.comment_time.strftime(
'%Y-%m-%d %H:%M:%S')
data['text'] = comment.text
else:
data['status'] = 'ERROR'
data['message'] = list(comment_form.errors.values())[0][0]
return JsonResponse(data)
- èªå®ä¹è¡¨åé误æç¤ºä¿¡æ¯
class CommentForm(forms.Form):
text = forms.CharField(
widget=CKEditorWidget(config_name='comment_ckeditor'),
error_messages={'required': 'è¯è®ºå
容为空'})
- æä¹æâææ è¯è®ºâçåæ ·å»æ(°â°)
- å¯ä»¥æâææ è¯è®ºâæ¹æ
<span id="no_comment">ææ è¯è®º</span> - ç¶åå¨ajaxæäº¤æåä¹åç§»é¤è¯¥èç¹ $("#no_comment").remove()
- å¯ä»¥æâææ è¯è®ºâæ¹æ
26.åå¤åè½è®¾è®¡åæ ç»æ
-
å®åè¯è®ºæ¨¡åï¼ä½¿ç¨æ ç»æçç¥è¯å®ç°åå¤åè½ã主è¦å æ¬æ ç»æçç¥è¯åå端页é¢ç代ç ã
-

-
å¦ä½è®¾è®¡åå¤åè½
- è¯è®ºå¯ä»¥è¢«åå¤
- åå¤ä¹å¯ä»¥è¢«åå¤
-
è¯è®ºæ¨¡å设计, root, parent, reply_to, 没æï¼ç¨ååæ´çç±»ï¼è¿ç« æç¹é¾çè§£
- è¯è®ºä¸ºæ ¹ rootï¼å¦æ parent is None é£å°±æ¯æ ¹
- reply_to åå¤è°
class Comment(models.Model):
...
text = models.TextField()
comment_time = models.DateTimeField(auto_now_add=True)
user = models.ForeignKey(User, related_name='comments', on_delete=models.CASCADE)
root = models.ForeignKey('self', related_name='root_comment', null=True, on_delete=models.CASCADE)
parent = models.ForeignKey('self', related_name='parent_comment', null=True, on_delete=models.CASCADE)
reply_to = models.ForeignKey(User, related_name='replies', null=True, on_delete=models.CASCADE)
- related_name 代表çåååè½è¦æä¹çè§£å¢ï¼
- ä¾å¦Commentæä¸ªuesrå¤é®èç³»å°Userï¼è¿ä¸ªæ¯æ£åå ³ç³»ãèUseræ¯è¢«èç³»ï¼è¦ä»Userå¾å°ç¸å ³Commentæ°æ®ï¼è¿ä¸ªæ¯ç¸å¯¹äºé£ä¸ªå¤é®å ³ç³»æ¥è¯´æ¯åè¿æ¥ï¼æä»¥å«ååå ³ç³»ãè¥è¦ä»Userè·åCommentæ°æ®ï¼æ¯é»è®¤éè¿ä¸ä¸ªcomment_set屿§ï¼æ¨¡ååå â_setâãè¦æ´æ¹è¿ä¸ªå±æ§åç¨related_name
# è¯è®ºè¡¨å
class CommentForm(forms.Form):
# åå¤çåªæ¡
reply_comment_id = forms.IntegerField(
widget=forms.HiddenInput(attrs={'id': 'reply_comment_id'}))
# éªè¯æäº¤çæ°æ®
def clean_reply_comment_id(self):
reply_comment_id = self.cleaned_data['reply_comment_id']
if reply_comment_id < 0:
raise forms.ValidationError('åå¤åºé')
elif reply_comment_id == 0:
self.cleaned_data['parent'] = None
elif Comment.objects.filter(pk=reply_comment_id).exists():
self.cleaned_data['parent'] = Comment.objects.get(
pk=reply_comment_id)
else:
raise forms.ValidationError('åå¤åºé')
return reply_comment_id
- è¯è®ºå表æ¾ç¤º
<div class="comment-area">
<h3 class="comment-area-title">è¯è®ºå表</h3>
<div id="comment_list" >
{% for comment in comments %}
<div id="root_{{ comment.pk }}" class="comment">
<span>{{ comment.user.username }}
<span>({{ comment.comment_time | date:"Y-m-d H:i:s" }}):</span>
<div id="comment_{{ comment.pk }}">
{{ comment.text | safe }}
</div>
<a href="javascript:reply({{ comment.pk }})">åå¤</a>
{% for reply in comment.root_comment.all %}
<div class="reply">
<span>{{ reply.user.username }}</span>
<span>({{ reply.comment_time | date:"Y-m-d H:i:s" }}):</span>
<span>åå¤</span>
<span>{{ reply.reply_to.username }}</span>
<div id="comment_{{ reply.pk }}">
{{ reply.text|safe }}
</div>
<a href="javascript:reply({{ reply.pk }})">åå¤</a>
</div>
{% endfor %}
</div>
{% empty %}
<span id='no_comment'>ææ è¯è®º</span>
{% endfor %}
</div>
</div>
- js 夿æäº¤çæ¯è¯è®ºè¿æ¯åå¤
// å¤ææ¯ è¯è®º è¿æ¯ åå¤ï¼ ä¸åçæå
¥ä½ç½®ç
// 没æå®#reply_comment_id å°±æ¯è¯è®ºï¼ å夿¯æå®å夿䏿¡ç
if($('#reply_comment_id').val() == '0'){
// æå
¥è¯è®º
var comment_html = '<div id="root_' + data['pk'] + '" class="comment"> \
<span>' + data['username'] + '</span> \
<span>(' + data['comment_time'] + '):</span>\
<div id="comment_' + data['pk'] + '">' + data['text'] + '</div> \
<a href="javascript:reply(' + data['pk'] + ');">åå¤</a></div>';
$('#comment_list').prepend(comment_html);
}else{
// æå
¥åå¤
var reply_html = '<div class="reply"><span>' + data['username'] + '</span> \
<span>(' + data['comment_time'] + '):</span> \
<span> åå¤ </span> \
<span>' + data['reply_to'] + ': </span> \
<div id="comment_' + data['pk'] + '">' + data['text'] + '</div> \
<a href="javascript:reply(' + data['pk'] + ');">åå¤</a></div>';
$('#root_' + data['root_pk']).append(reply_html);
}
- js ç¹å»åå¤åï¼å±å¹æ»å¨å°è¯è®ºè¡¨å, å¹¶è·å¾è¾å ¥ç¦ç¹
function reply(reply_comment_id){
// 设置å¼
$('#reply_comment_id').val(reply_comment_id);
// æ¾ç¤ºåå¤çåªæ¡
var html = $('#comment_' + reply_comment_id).html();
$('#reply_content').html(html);
$('#reply_content_container').show();
// ç¹å»åå¤åï¼å±å¹æ»å¨å°è¯è®ºè¡¨å, å¹¶è·å¾ç¦ç¹,
$('html').animate({scrollTop: $('#comment_form').offset().top - 60 }, 300, function(){
CKEDITOR.instances['id_text'].focus();
});
}
27.è·åè¯è®ºæ°åç»èå¤ç
-
å¦ä½è·åè¯è®ºæ°
- æ¹æ³ï¼filterçéå¨ç¨countæ¹æ³è®¡æ°
- é®é¢ï¼å¨å表å详æ 页æ¾ç¤ºï¼ä¼è®©ä»£ç åå¾å¾å¤æ
- 详æ 乿è¯è®ºï¼æ¯å¯ä»¥ç»è®¡ï¼å表页æ¾ç¤ºè¯è®ºæ°å°±æ¯è¾éº»ç¦
-
ç¨èªå®ä¹æ¨¡æ¿æ ç¾è·åè¯è®ºæ°
- å®ç°è¯è®ºåè½ç¬ç«ï¼éä½è¦åæ§ï¼ä»£ç ç¬ç«ï¼ä½¿ç¨ç®å
- å¨appå
å建
templatetagså - å建pyæä»¶, åæ¹æ³ï¼ç¨åä¼å½æ ç¾ä½¿ç¨, æ³¨åæ¹æ³åè¦éå¯åºç¨
- 卿¨¡çä¸
loadæ ç¾å 载该æä»¶ï¼{% load comment_tags %}æä»¶å廿py - 模çä¸è°ç¨
{% get_comment_count blog %}æ³¨ææ ç¾æ¯{% %}, 忰乿²¡æå¼å· - è¿æ ·å¯ä»¥å¨è¯¦æ ååè¡¨é¡µè½»æ¾æ¾ç¤ºè¯è®ºæ°ï¼2å¥è¯ï¼å¾ç®å
- Custom template tags and filters
# å建å
ï¼åæä»¶
# Django_Course/mysite/comment/templatetags/comment_tags.py
# vscode cmd +k p å¤å¶å½åæä»¶çè·¯å¾
from django import template
from django.contrib.contenttypes.models import ContentType
from ..models import Comment
register = template.Library()
@register.simple_tag
def get_comment_count(obj):
content_type = ContentType.objects.get_for_model(
obj) # æ ¹æ®å
·ä½å¯¹è±¡è·åcontenttype
return Comment.objects.filter(
content_type=content_type, object_id=obj.pk).count()
{% load comment_tags %}
è¯è®º({% get_comment_count blog %}
- å°viewsä¸çè¯è®ºè¡¨ååè¯è®ºå表åç¦»å°æ¨¡çæ ç¾ä¸ï¼ç²¾ç®ä»£ç
@register.simple_tag
def get_comment_form(obj):
content_type = ContentType.objects.get_for_model(obj)
form = CommentForm(initial={
'content_type': content_type,
'object_id': obj.pk,
'reply_comment_id': 0
})
return form
@register.simple_tag
def get_comment_list(obj):
content_type = ContentType.objects.get_for_model(obj)
comments = comments = Comment.objects.filter(
content_type=content_type, object_id=obj.pk, parent=None)
return comments.order_by('-comment_time')
# å¼ç¨
{% get_comment_form blog as comment_form %}
{% for field in comment_form %}
{% get_comment_list blog as comments %}
{% for comment in comments %}
- ä¿®å¤ajaxè·åçè¯è®ºæ¶é´æ¶åºé®é¢
//js æ¶é´æ³è½¬å½åæ¶é´ï¼å¹¶æ ¼å¼åæ¾ç¤º
function numFormat(num){
return ('00' + num).substr(-2);
}
function timeFormat(timestamp){
var datetime = new Date(timestamp * 1000);
var year = datetime.getFullYear();
var month = numFormat(datetime.getMonth()) + 1;
var day = numFormat(datetime.getDate());
var hour = numFormat(datetime.getHours());
var minute = numFormat(datetime.getMinutes());
var second = numFormat(datetime.getSeconds());
return year + '-' + month + '-' + day + ' ' + hour + ':' + minute + ':' + second
}
data['comment_time'] = comment.comment_time.timestamp()
- è°æ´åå¤è¡¨åçCSSæ ·å¼

div#reply_content_container {
border: 1px solid #d1d1d1;
border-bottom: none;
background-color: #f8f8f8;
overflow: hidden;
padding: 1em 1em 0.5em;
}
p#reply_title {
border-bottom: 1px dashed #ccc;
padding-bottom: 0.5em;
}
-
å¤é®çº§èå é¤CASCADEï¼ä¿è¯æ°æ®ç宿´æ§
user = models.ForeignKey(User, related_name='comments', on_delete=models.DO_NOTHING)User表æ¯ä¸»ï¼å½å é¤ç¨æ·åï¼DO_NOTHINGè¿ä¼ä¿çç¨æ·çè¯è®ºéçç¨æ·ï¼é ææ°æ®ä¸å®æ´- æ°æ®åºä¼æç¤ºï¼
FOREIGN KEY constraint failed - æ¢æ
on_delete=models.CASCADE, å é¤ç¨æ·åï¼å å«å¨è¯è®ºéçç¨æ·ä¹å é¤
-
ä¿®å¤ django-ckeditor æ¥é
No configuration named 'default' found in your CKEDITOR_CONFIGS- settings䏿·»å
'default': {},
28.å®ç°ç¹èµåè½, çä¼¼ç®åï¼å 容å¾å¤
-
ç¹èµåè½è®¾è®¡
- å客åè¯è®ºãåå¤é½å¯ä»¥ç¹èµ
- å¯ä»¥åæ¶ç¹èµ
- å¯çå°ç¹èµæ»æ°
- ç¨æ·ç»å½åæå¯ä»¥ç¹èµ (è§é¢éè¿æ ·è®¾è®¡çï¼å¦ä½æ¹è¿ä¸ç¨ç¨æ·ç»å½å¢ï¼)
-
å建ç¹èµ
likesapppython manage.py startapp likes- 注åapp
- æ°æ®åºè¿ç§»
- 设置请æ±ç æ»å urls
# Django_Course/mysite/likes/models.py
from django.db import models
from django.contrib.contenttypes.fields import GenericForeignKey
from django.contrib.contenttypes.models import ContentType
from django.contrib.auth.models import User
class LikeCount(models.Model):
content_type = models.ForeignKey(ContentType, on_delete=models.CASCADE)
object_id = models.PositiveIntegerField()
content_object = GenericForeignKey('content_type', 'object_id')
liked_num = models.IntegerField(default=0)
class LikeRecord(models.Model):
content_type = models.ForeignKey(ContentType, on_delete=models.CASCADE)
object_id = models.PositiveIntegerField()
content_object = GenericForeignKey('content_type', 'object_id')
user = models.ForeignKey(User, on_delete=models.CASCADE)
liked_time = models.DateTimeField(auto_now_add=True)
# æ» urls æ·»å
path('likes/', include('likes.urls')),
# app urls
path('like_change', views.like_change, name='like_change')
- ajax 弿¥æäº¤æ¹å ç¹èµ 请æ±
function likeChange(obj, content_type, object_id){
var is_like = (obj.getElementsByClassName('active').length == 0);
console.log(is_like)
// 弿¥æäº¤
$.ajax({
url: "{% url 'like_change' %}",
type: 'GET',
data: {
content_type: content_type,
object_id: object_id,
is_like: is_like,
},
cache: false,
success: function(data){
console.log(data);
if(data['status'] == 'SUCCESS'){
// æ´æ°ç¹èµç¶æ
var element = $(obj.getElementsByClassName('glyphicon'));
if(is_like){
element.addClass('active');
}else{
element.removeClass('active');
}
// æ´æ°ç¹èµæ°é
var liked_num = $(obj.getElementsByClassName('liked-num'));
liked_num.text(data['liked_num']);
}else{
alert(data['message']);
}
},
error: function(xhr){
console.log(xhr)
}
});
}
- css ç¹èµæ ·å¼
div.like {
color: #337ab7;
cursor: pointer;
display: inline-block;
padding: 0.5em 0.3em;
}
div.like .active{
color: red;
}
- views å¤çç¹èµè¯·æ±ï¼éªè¯åç§ç¶æ
def ErrorResponse(code, message):
data = {}
data['status'] = 'ERROR'
data['code'] = code
data['message'] = message
return JsonResponse(data)
def SuccessResponse(liked_num):
data = {}
data['status'] = 'SUCCESS'
data['liked_num'] = liked_num
return JsonResponse(data)
def like_change(request):
# è·å请æ±ä¼ éçæ°æ®
# è·åç¨æ·ï¼éªè¯ç¨æ·ç»å½
user = request.user
if not user.is_authenticated:
return ErrorResponse(400, 'you were not login')
content_type = request.GET.get('content_type')
object_id = int(request.GET.get('object_id'))
try:
content_type = ContentType.objects.get(model=content_type)
model_class = content_type.model_class()
model_obj = model_class.objects.get(pk=object_id)
except ObjectDoesNotExist:
return ErrorResponse(401, 'object not exist')
# å¤çæ°æ®
if request.GET.get('is_like') == 'true':
# è¦ç¹èµ
print('hi')
like_record, created = LikeRecord.objects.get_or_create(content_type=content_type, object_id=object_id, user=user)
if created:
# æªç¹èµè¿ï¼ç¹èµæ°å 1
like_count, created = LikeCount.objects.get_or_create(content_type=content_type, object_id=object_id)
like_count.liked_num += 1
like_count.save()
return SuccessResponse(like_count.liked_num)
else:
# å·²ç¹èµè¿ï¼ä¸è½éå¤ç¹èµ
return ErrorResponse(402, 'you were liked')
else:
# åæ¶ç¹èµ
if LikeRecord.objects.filter(content_type=content_type, object_id=object_id, user=user):
# æç¹èµï¼åæ¶ç¹èµ
like_record = LikeRecord.objects.get(content_type=content_type, object_id=object_id, user=user)
like_record.delete()
# ç¹èµæ»æ° -1
like_count, created = LikeCount.objects.get_or_create(content_type=content_type, object_id=object_id)
if not created:
like_count.liked_num -= 1
like_count.save()
return SuccessResponse(like_count.liked_num)
else:
return ErrorResponse(404, 'data error')
else:
# 没ç¹èµè¿ï¼ä¸è½åæ¶
return ErrorResponse(403, 'you were not liked')
- è®¾ç½®æ¨¡çæ ç¾, æ¹ä¾¿æ¨¡çå¼ç¨ï¼ä¸å¨views䏿´å ç¬ç«
# Django_Course/mysite/likes/templatetags/likes_tags.py
from django import template
from django.contrib.contenttypes.models import ContentType
from ..models import LikeCount, LikeRecord
register = template.Library()
@register.simple_tag
def get_like_count(obj):
content_type = ContentType.objects.get_for_model(obj)
like_count, created = LikeCount.objects.get_or_create(
content_type=content_type, object_id=obj.pk)
return like_count.liked_num
@register.simple_tag(takes_context=True) # ä½¿ç¨æ¨¡çéé¢çåé
def get_like_status(context, obj):
content_type = ContentType.objects.get_for_model(obj)
user = context['user']
if not user.is_authenticated:
return ''
if LikeRecord.objects.filter(
content_type=content_type, object_id=obj.pk, user=user).exists():
return 'active'
else:
return ''
@register.simple_tag
def get_content_type(obj):
content_type = ContentType.objects.get_for_model(obj)
return content_type.model
- 模çä¸å¼ç¨æ¨¡çæ ç¾
{% load likes_tags %}
// å客å表ä¸å¼ç¨
ç¹èµ({% get_like_count blog %})
// æ·»å ç¹èµåè½å°è¯è®ºå表
<div class="like" onclick="likeChange(this, '{% get_content_type comment %}', {{ comment.pk }})">
<span class="glyphicon glyphicon-thumbs-up {% get_like_status comment %}"></span>
<span class="liked-num">{% get_like_count comment %}</span>
</div>
// æ·»å ç¹èµåè½åå¤å表
<div class="like" onclick="likeChange(this, '{% get_content_type reply %}', {{ reply.pk }})">
<span class="glyphicon glyphicon-thumbs-up {% get_like_status reply %}"></span>
<span class="liked-num">{% get_like_count reply %}</span>
</div>
-
åå端å¼å建议
- åè½éæ±åæ -ãæ¨¡å设计 -ãåç«¯åæ¥å¼å -ãå端å®ç° -ãå®åå端代ç
-
æ¨¡çæ ç¾
- the Jinja2 template engine was inspired by the Django template language
- therefore their syntax is quite similar!
- 表达å¼
{% ... %} is used for statements. - åé
{{ ... }} is used for variables - 注é
{# ... #} is used for to comment
29.å®åç¹èµåè½
-
å®åç¹èµåè½ï¼è®©æ°å¢çè¯è®ºååå¤å¯ä»¥ç¹èµã
- è¿éæ¶åå°jsåç¬¦ä¸²æ¼æ¥çé®é¢ã
- ç¹èµæ¶ï¼æªç»å½çæ åµä¸å¼¹åºä¸ä¸ªæ¨¡ææ¡ç»å½
-
æ°å¢è¯è®ºååå¤ç¹èµ
- å 为æä»¬æ°å¢å çè¯è®ºåå夿²¡ææ·»å onclickäºä»¶
- è§£å³jsåç¬¦ä¸²æ¼æ¥çé®é¢
// å®ä¹åç¬¦ä¸²æ ¼å¼åæ¹æ³ï¼è§£å³åç¬¦ä¸²æ¼æ¥éº»ç¦é®é¢
// '{0}+{1}'.format('a', 'b') -> "a+b"
String.prototype.format = function(){
var str = this;
for (var i = 0; i < arguments.length; i++) {
var str = str.replace(new RegExp('\\{' + i + '\\}', 'g'), arguments[i])
};
return str;
}
// 弿¥æäº¤
$.ajax({
url: "{% url 'update_comment' %}",
type: 'POST',
data: $(this).serialize(), // this å³ #comment_form
cache: false,
success: function(data){ // æäº¤æååè°ç¨çæ¹æ³, dataæ¯å端è¿åç»åç«¯çæ°æ®
console.log(data);
// 妿æåï¼å°±æå
¥æ¾ç¤ºæ°
if(data['status']=='SUCCESS'){
// å¤ææ¯ è¯è®º è¿æ¯ åå¤ï¼ ä¸åçæå
¥ä½ç½®ç
if($('#reply_comment_id').val() == '0'){
// æå
¥è¯è®º
var comment_html = '<div id="root_{0}" class="comment">' +
'<span>({2}):</span>' +
'<div id="comment_{0}"> {3} </div>' +
'<div class="like" onclick="likeChange(this, \'{4}\', {0})">' +
'<span class="glyphicon glyphicon-thumbs-up "></span>' +
'<span class="liked-num"> 0 </span></div>' +
'<a href="javascript:reply({0})">åå¤</a></div>';
comment_html = comment_html.format(
data['pk'], data['username'], timeFormat(data['comment_time']), data['text'], data['content_type'])
$('#comment_list').prepend(comment_html);
...
-
æªç»å½æ¶ï¼å¼¹åºä¸ä¸ªæ¨¡ææ¡ç»å½
- æ¨¡ææ¡
- 以弹åºå¯¹è¯æ¡çå½¢å¼åºç°ï¼å ·ææå°åæå®ç¨çåè½éã
-
ç»å½æ¡ 代ç , å¼å ¥ä¹åç login form
<!-- Modal -->
<div class="modal fade" id="login_modal" tabindex="-1" role="dialog">
<div class="modal-dialog modal-sm" role="document">
<div class="modal-content">
<form id="login_modal_form" action="" method="POST">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">×</span></button>
<h4 class="modal-title" id="myModalLabel">ç»å½</h4>
</div>
<div class="modal-body">
{% csrf_token %}
{% for field in login_form %}
<label for="{{ field.id_for_label }}">{{ field.label }}</label>
{{ field }}
{% endfor %}
<span id="login_modal_tip" class="text-danger"></span>
</div>
<div class="modal-footer">
<button type="submit" class="btn btn-primary">ç»å½</button>
<button type="button" class="btn btn-default" data-dismiss="modal">å
³é</button>
</div>
</form>
</div>
</div>
</div>
-
æ·»å è·¯ç±urlï¼ç¨äºå¼¹åºç»å½æ¡æäº¤è¯·æ±
path('login_for_modal/', views.login_for_modal, name='login_for_modal'),
-
ajax æäº¤ç»å½ä¿¡æ¯
// 使£æ¥æªç»å½æ¶ æ¾ç¤ºç»å½æ¡
if(data['code'] == 400){
$('#login_modal').modal('show');
// æäº¤ç»å½è¯·æ±
$('#login_modal_form').submit(function(eventt){
event.preventDefault(); // 黿¢é¡µé¢æäº¤
$.ajax({
url: "{% url 'login_for_modal' %}",
type: 'POST',
data: $(this).serialize(),
cache: false,
success: function(data){
if(data['status'] == 'SUCCESS'){
window.location.reload(); // å·æ°é¡µé¢
}else{
$('#login_modal_tip').text('ç¨æ·åæå¯ç é误');
}
}
});
});
- å¤çç»å½è¯·æ±
def login_for_modal(request):
login_form = LoginForm(request.POST)
data = {}
if login_form.is_valid():
user = login_form.cleaned_data['user']
auth.login(request, user)
data['status'] = 'SUCCESS'
else:
data['status'] = 'ERROR'
return JsonResponse(data)
30.å¯¼èªæ æ·»å ç¨æ·æä½
-
ä¹åè¯è®ºåç¹èµçæ¶åï¼éè¦ç»å½åç»åºï¼æä½æç¹éº»ç¦ãæä»¥å¨å¯¼èªæ æ·»å ç¨æ·æä½ï¼å¹¶ä¸å°ç¸å ³ç¨æ·çå¤çæ¹æ³éä¸åæä¸ä¸ªdjangoåºç¨ï¼ä¸ºåé¢èªå®ä¹ç¨æ·æ¨¡ååå¤
-
æ¹ä¾¿ç»å½åéåº
- å¯¼èªæ å³ä¾§æ·»å âç»å½ï¼æ³¨åâï¼ç¨æ·ä¸ªäººä¿¡æ¯ï¼éåºåè½
- ä¸æå¯¼èªæ¡
- User model django.contrib.auth
// ç»å½ç¶ææ¾ç¤ºç¨æ·åï¼æªç»å½ç¶ææ¾ç¤ºç»å½å注å
<ul class="nav navbar-nav navbar-right">
{% if not user.is_authenticated %}
<li><a href="{% url 'login' %}?from={{ request.get_full_path }}">ç»å½</a></li>
<li><a href="{% url 'register' %}?from={{ request.get_full_path }}">注å</a></li>
{% else %}
<li class="dropdown">
<a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button">{{ user.username }}
<span class="caret"></span></a>
<ul class="dropdown-menu">
<li><a href="{% url 'user_info' %}">ä¸ªäººèµæ</a></li>
<li role="separator" class="divider"></li>
<li><a href="{% url 'logout' %}?from={{ request.get_full_path }}">éåº</a></li>
</ul>
</li>
{% endif %}
</ul>
// ç¨æ·ä¸å¿é¡µé¢
<div class="containter">
<div class="row">
<div class="col-xs-10 col-xs-offset-1">
{% if user.is_authenticated %}
<h2>{{ user.username }}</h2>
<ul>
<li>æµç§°ï¼ <a href="#">ä¿®æ¹æµç§°</a></li>
<li>é®ç®±ï¼
{% if user.email %} {{ user.email }}
{% else %} æªç»å® <a href="#">ç»å®é®ç®±</a>
{% endif %}</li>
<li>䏿¬¡ç»å½çæ¶é´: {{ user.last_login|date:"Y-m-d H:i:s" }}</li>
<li><a href="#">ä¿®æ¹å¯ç </a></li>
</ul>
{% else %}
<span>æªç»å½ï¼è·³è½¬å°é¦é¡µ....</span>
<script type="text/javascript">
window.location.href = '/';
</script>
{% endif %}
</div>
</div>
</div>
# 注åç¨æ·ä¸å¿url
path('user_info/', views.user_info, name='user_info'),
# å¤çéåºåç¨æ·ä¸å¿è¯·æ±
def logout(request):
auth.logout(request)
return redirect(request.GET.get('from', reverse('home')))
def user_info(request):
context = {}
return render(request, 'user_info.html', context)
-
è¿ç§»ï¼å°userç¬ç«æappï¼æ¾å°ä¸èµ·
- å建appå¯ä»¥ç¨å½ä»¤
python manage.py startapp appname - ä¹å¯ä»¥æå¨éè¦çæä»¶ï¼æ¨¡æå½ä»¤, åå°æä»¶å离åºï¼æ¾å°appéé¢
- å建appå¯ä»¥ç¨å½ä»¤
-
æå¨è¿ç§»useråºç¨æ¥éª¤
- è·¯ç±åç¦»ï¼æ»è·¯ç±æ·»å ç¨æ·
path('user/', include('user.urls')), - useråºç¨æ·»å
urls.py, ç»ä¸å¤çç¨æ·ç¸å ³ç url - useræ°å»ºæ¨¡çæä»¶å¤¹ï¼å°ç¨æ·ç¸å ³htmlæ¾å°éé¢çuserç®å½ï¼ç»ä¸ç®¡ç
- ä¿®æ¹viewsä¸å å
¥
userï¼ - å 为模çæä»¶ä¸ç¨å°çurl齿¯å«åï¼ææè¿ç§»ä¸å½±å
- æåå¨settings䏿³¨åapp
- è·¯ç±åç¦»ï¼æ»è·¯ç±æ·»å ç¨æ·
-
å°ç»å½è¡¨ååå¼¹åºçç»å½æ¡æ¾å°å ¬å ±æ¨¡çéï¼ç¬ç«åºæ¥ï¼æ¹ä¾¿è°ç¨
- userç®å½ä¸æ°å»º
context_processors.py - settings ä¸ç TEMPLATES æ·»å
- å°ä¹åviewsä¸å¼ç¨ç廿ï¼å¯ä»¥å¨æ¨¡çä¸ç´æ¥å¼ç¨äº
- å°ç»å½å¼¹æ¡åajaxèæ¬å离ç¬ç«åºæ¥ï¼æ¾å°å
Œ
±ç
base.htmlæä»¶ä¸ï¼éå¤å¯ç¨
- userç®å½ä¸æ°å»º
# Django_Course/mysite/user/context_processors.py
from .forms import LoginForm
def login_modal_form(request):
return {'login_modal_form': LoginForm()}
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [
os.path.join(BASE_DIR, 'templates'),
],
'APP_DIRS': True,
'OPTIONS': {
'context_processors': [
...
'django.template.context_processors.request',
'user.context_processors.login_modal_form',
],
},
},
]
31.èªå®ä¹ç¨æ·æ¨¡å
-
两ç§èªå®ä¹ç¨æ·æ¨¡åçæ¹å¼
- ç»§æ¿DjangoçUserç±»
- ä¼ç¹æ¯ èªå®ä¹å¼ºï¼æ²¡æä¸å¿ è¦çåæ®µ
- ç¼ºç¹æ¯ éè¦å¨é¡¹ç®å¼å§æ¶ä½¿ç¨ï¼é ç½®admin麻ç¦
- Customizing authentication in Django
- ç¨æ°çProfile模åæå±å ³èçUser
- ç»§æ¿DjangoçUserç±»
-
ç¨æ°çProfile模åæå±å ³èçUser
- å建models
- å建adminåå°
- è¿ç§»æ°æ®åºçæ
# Django_Course/mysite/user/models.py
from django.db import models
from django.contrib.auth.models import User
class Profile(models.Model):
#ä¸å¯¹ä¸å
³ç³»ï¼ä¸ä¸ªç¨æ·ä¸ä¸ªèµæï¼ éå¤ä¼æ¥éæ æ³æ·»å
user = models.OneToOneField(User, on_delete=models.CASCADE)
nickname = models.CharField(max_length=20)
def __str__(self):
return '<Profile: %s for %s>' % (self.nickname, self.user.username)
# Django_Course/mysite/user/admin.py
from django.contrib import admin
from .models import Profile
@admin.register(Profile)
class ProfileAdmin(admin.ModelAdmin):
list_display = ('user', 'nickname')
- å°profile模åä¿¡æ¯æ·»å å°adminåå°çç¨æ·ä¿¡æ¯é¡µé¢
- To add a profile modelâs fields to the user page in the admin, define an InlineModelAdmin (for this example, weâll use a StackedInline) in your appâs admin.py and add it to a UserAdmin class which is registered with the User class
- å¨ç¨æ·å表æ¾ç¤ºæµç§°
# admin.py
# Define an inline admin descriptor for Profile model
class ProfileInline(admin.StackedInline):
model = Profile
can_delete = False
# Define a new User admin
class UserAdmin(BaseUserAdmin):
inlines = (ProfileInline,)
list_display = ('username', 'nickname', 'email', 'is_staff', 'is_active', 'is_superuser')
# 为äºå¨ç¨æ·å表æ¾ç¤ºæµç§°ï¼éè¦å å
¥ä¸ä¸ªèªå®ä¹æ¹æ³ãä¸é¢å°±æ¯è°ç¨user.nicknameæ¾ç¤º
def nickname(self, obj):
return obj.profile.nickname
nickname.short_description = 'æµç§°' # 䏿æ¾ç¤º
# Re-register UserAdmin
admin.site.unregister(User)
admin.site.register(User, UserAdmin)
-
ç¨Profile模åæå±Useræ¹æ³çä¼ç¼ºç¹
- ä¼ç¹æ¯ä½¿ç¨æ¹ä¾¿ï¼ä¸ç¨å åºéæ¥ï¼ä¸å½±åæ´ä½æ¶æ
- ç¼ºç¹æ¯åå¨ä¸å¿ è¦çåæ®µï¼å¯¹æ¯ç»§æ¿çæ¹æ³ï¼æ¥è¯¢é度ä¼ç¨å¾®æ ¢ä¸ä¸ç¹
-
å å ¥è°æ´
åå°ç®¡ç龿¥
<ul class="dropdown-menu">
<li><a href="{% url 'user_info' %}">ä¸ªäººèµæ</a></li>
<li role="separator" class="divider"></li>
{% if user.is_staff or user.is_superuser %}
<li><a href="{% url 'admin:index' %}">åå°ç®¡ç</a></li> // adminæ¯å½å空é´
{% endif %}
<li><a href="{% url 'logout' %}?from={{ request.get_full_path }}">éåº</a></li>
</ul>
- ä¼å ç»å½å主页 页é¢é»è¾ï¼å¦ææ¯ç»å½ç¶æï¼å°±è°æ´å°é¦é¡µ
{% if not user.is_authenticated %}
... 注åæç»å½
{% else %}
<span>å·²ç»å½ï¼è·³è½¬å°é¦é¡µ....</span>
<script type="text/javascript">
window.location.href = '/';
</script> {% endif %}
{% endif %}
32.ä¿®æ¹ç¨æ·ä¿¡æ¯
-
ä¿®æ¹ç¨æ·ä¿¡æ¯ï¼å®ç°ä¿®æ¹æµç§°ãç»å®é®ç®±ï¼å¯åéé®ä»¶åè½ï¼
-
å®ç°ä¿®æ¹æµç§°
- åç«¯é¡µé¢æ·»å ä¿®æ¹æµç§° 龿¥
<a href="{% url 'change_nickname' %}">ä¿®æ¹æµç§°</a> - urls 䏿·»å 龿¥ï¼å对åºçå¤çæ¹æ³
path('change_nickname/', views.change_nickname, name='change_nickname'), - views 䏿·»å 渲æé¡µé¢åä¿®æ¹æµç§°å¤çæ¹æ³
- 渲æä¿®æ¹æµç§°è¡¨åï¼éè¦å®ä¹ä¸ä¸ª ä¿®æ¹æµç§° ç表åï¼
- æ·»å form.html ç¨æ¥ æ¾ç¤ºè¡¨ååæäº¤ä¿¡æ¯
- åç«¯é¡µé¢æ·»å ä¿®æ¹æµç§° 龿¥
<form action="" method="POST">
{% csrf_token %}
{% for field in form %}
{% if not field.is_hidden %}
<label for="field.id_for_label">{{ field.label }}</label>
{% endif %}
{{ field }}
<p class="text-danger"> {{ field.errors.as_text }} </p>
{% endfor %}
<span class="pull-left text-danger">{{ form.non_field_errors }}</span>
<div class="pull-right">
<input type="submit" value="{{ submit_text }}" class="btn btn-primary">
<button class="btn btn-default" onclick="{{ return_back_url }}">è¿å</button>
</div>
</form>
# form.py å®ä¹è¡¨ååéªè¯è¡¨åçæ¹æ³
class ChangeNicknameForm(forms.Form):
nickname_new = forms.CharField(
label='æ°çæµç§°',
max_length=20,
widget=forms.TextInput(attrs={
'class': 'form-control',
'placeholder': '请è¾å
¥æ°çæµç§°'
}))
# ä¸é¢2ä¸ªå½æ°ç¨äºå¤æç¨æ·æ¯å¦ç»å½
def __init__(self, *args, **kwargs):
if 'user' in kwargs:
self.user = kwargs.pop('user') # æ¥æ¶ç¨æ·ä¿¡æ¯, å¹¶åé¤ï¼ä¸ºäºä¸ä¸å¥ä¸åºé
super(ChangeNicknameForm, self).__init__(*args, **kwargs)
# éªè¯æ°æ®
def clean(self):
# å¤æç¨æ·æ¯å¦ç»å½
if self.user.is_authenticated:
self.cleaned_data['user'] = self.user
else:
raise forms.ValidationError('ç¨æ·å°æªç»å½')
return self.cleaned_data
def clean_nickname_new(self):
nickname_new = self.cleaned_data.get('nickname_new', '').strip()
if nickname_new == '':
raise forms.ValidationError('æ°çæµç§°ä¸è½ä¸ºç©º')
return nickname_new
# views.py å¤ç
def change_nickname(request):
redirect_to = request.GET.get('from', reverse('home'))
if request.method == 'POST':
form = ChangeNicknameForm(request.POST, user=request.user)
if form.is_valid():
nickname_new = form.cleaned_data['nickname_new']
profile, created = Profile.objects.get_or_create(user=request.user)
profile.nickname = nickname_new
profile.save()
return redirect(redirect_to)
else:
form = ChangeNicknameForm()
context = {}
context['page_title'] = 'ä¿®æ¹æµç§°'
context['form_title'] = 'ä¿®æ¹æµç§°'
context['submit_text'] = 'ä¿®æ¹'
context['form'] = form
context['return_back_url'] = redirect_to
return render(request, 'form.html', context)
- å¦ä½å¤ææ¾ç¤ºç¨æ·ååæµç§°
- ç»user类添å è·åæµç§°çç±»æ¹æ³ï¼è·åæµç§°ï¼æ¯å¦ææµç§°ï¼è·å¾æµç§°æç¨æ·å
# 使ç¨ç±»æ¹æ³ç卿ç»å®ï¼Userç±»ç»å®è·åæµç§°çæ¹æ³
def get_nickname(self):
if Profile.objects.filter(user=self).exists():
profile = Profile.objects.get(user=self)
return profile.nickname
else:
return ''
def get_nickname_or_username(self):
if Profile.objects.filter(user=self).exists():
profile = Profile.objects.get(user=self)
return profile.nickname
else:
return self.username
def has_nickname(self):
return Profile.objects.filter(user=self).exists()
User.get_nickname = get_nickname
User.has_nickname = has_nickname
User.get_nickname_or_username = get_nickname_or_username
// base.html
<a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button">
{% if user.has_nickname %}
{{ user.username }}({{ user.get_nickname }})
{% else %}
{{ user.username }}
{% endif %}
<span class="caret"></span></a>
// blog_detail.html è¯è®º
<label>{{ user.get_nickname_or_username }}ï¼æ¬¢è¿è¯è®ºï½</label>
// è¿æ ajax ä¸ï¼åé¢viewsè¿åçæ¹æ³éè¦ä¿®æ¹ï¼å¾å°æµç§°åç´æ¥è¿åæµç§°
data['status'] = 'SUCCESS'
data['username'] = comment.user.get_nickname_or_username()
if parent is not None:
data['reply_to'] = comment.reply_to.get_nickname_or_username()
-
å®ç°ç»å®é®ç®±åè½
- å æèç»å®é®ç®±éè¦åªäºå段ï¼é®ç®±å°ååéªè¯ç
- 设计ç»å®é®ç®±ç表å
- views ä¸å¼å ¥è¡¨åï¼æ·»å å¤çæ¹æ³
- æ·»å è·¯ç±
- åç«¯é¡µé¢æ·»å 龿¥
- Sending email 设置åä»¶é®ç®±
- QQ é®ç®± å¼å¯è®¾ç½® SMTP æå¡ã æ¹QQå¯ç åææç ä¼å®æ
- 表åéªè¯ä¿¡æ¯
- ajax åééªè¯ç
- views å¤ç ç»å®é®ç®±ååééªè¯ç
-
é®ç®±è®¾ç½®
# åéé®ä»¶è®¾ç½®
# https://docs.djangoproject.com/en/2.0/ref/settings/#email
# https://docs.djangoproject.com/en/2.0/topics/email/
EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend'
EMAIL_HOST = 'smtp.qq.com'
EMAIL_PORT = '25'
EMAIL_HOST_USER = '[email protected]'
EMAIL_HOST_PASSWORD = 's' # ææç
EMAIL_SUBJECT_PREFIX = '[ableçå客]'
EMAIL_USE_TLS = True # ä¸smtpæå¡å¨éä¿¡æ¶ï¼æ¯å¦å¯å¨TLS龿¥ å®å
¨é¾æ¥
- ç»å®é®ç®±ç表åï¼å³åç§è¡¨åéªè¯
class BindEmailForm(forms.Form):
email = forms.EmailField(
label='é®ç®±',
widget=forms.TextInput(attrs={
'class': 'form-control',
'placeholder': '请è¾å
¥æ£ç¡®çé®ç®±'
}))
verification_code = forms.CharField(
label='éªè¯ç ',
required=False, # 为äºå¨ä¸å¡«çæ¶åå¯ä»¥ç¹å»åéé®ä»¶
widget=forms.TextInput(attrs={
'class': 'form-control',
'placeholder': 'ç¹å»âåééªè¯ç âåéå°é®ç®±'
}))
# ä¸é¢2ä¸ªå½æ°ç¨äºå¤æç¨æ·æ¯å¦ç»å½
def __init__(self, *args, **kwargs):
if 'request' in kwargs:
self.request = kwargs.pop('request') # æ¥æ¶ä¼ å
¥çrquestä¿¡æ¯, å¹¶åé¤ï¼ä¸ºäºä¸ä¸å¥ä¸åºé
super(BindEmailForm, self).__init__(*args, **kwargs)
# éªè¯æ°æ®
def clean(self):
# å¤æç¨æ·æ¯å¦ç»å½
if self.request.user.is_authenticated:
self.cleaned_data['user'] = self.request.user
else:
raise forms.ValidationError('ç¨æ·å°æªç»å½')
# å¤æç¨æ·æ°ä¼å¦å·²ç»ç»å®é®ç®±
if self.request.user.email != '':
raise forms.ValidationError('ä½ å·²ç»ç»å®äºé®ç®±')
# 夿éªè¯ç
code = self.request.session.get('bind_email_code', '')
verification_code = self.cleaned_data.get('verification_code', '')
if not (code != '' and code == verification_code):
raise forms.ValidationError('éªè¯ç 䏿£ç¡®')
return self.cleaned_data
def clean_email(self):
email = self.cleaned_data['email']
if User.objects.filter(email=email).exists():
raise forms.ValidationError('该é®ç®±å·²ç»è¢«ç»å®')
return email
def clean_verification_code(self):
verification_code = self.cleaned_data.get('verification_code',
'').strip()
if verification_code == '':
raise forms.ValidationError('éªè¯ç ä¸è½ä¸ºç©º')
return verification_code
- views å¤ç ç»å®é®ç®±ååééªè¯ç
# è·¯ç±
path('bind_email/', views.bind_email, name='bind_email'),
path('send_verification_code/', views.send_verification_code, name='send_verification_code'),
def bind_email(request):
redirect_to = request.GET.get('from', reverse('home'))
if request.method == 'POST':
form = BindEmailForm(request.POST, request=request)
if form.is_valid():
email = form.cleaned_data['email']
request.user.email = email
request.user.save()
return redirect(redirect_to)
else:
form = BindEmailForm()
context = {}
context['page_title'] = 'ç»å®é®ç®±'
context['form_title'] = 'ç»å®é®ç®±'
context['submit_text'] = 'ç»å®'
context['form'] = form
context['return_back_url'] = redirect_to
return render(request, 'user/bind_email.html', context)
def send_verification_code(request):
email = request.GET.get('email', '')
data = {}
if email != '':
# çæéªè¯ç
code = ''.join(random.sample(string.digits, 6))
now = int(time.time()) # ç§æ°
send_code_time = request.session.get('send_code_time', 0)
if now - send_code_time < 60:
data['status'] = 'ERROR'
else:
# session åå¨ç¨æ·è¯·æ±ä¿¡æ¯ï¼é»è®¤æææä¸¤å¨
request.session['bind_email_code'] = code
request.session['send_code_time'] = now
# åéé®ç®±
send_mail(
'ç»å®é®ç®±',
'éªè¯ç : %s' % code,
'[email protected]',
[email],
fail_silently=False,
)
data['status'] = 'SUCCESS'
else:
data['status'] = 'ERROR'
return JsonResponse(data)
- ç»å®é®ç®±å端页é¢åajaxåééªè¯ç
{% extends "form.html" %}
{% block other_buttons %}
<button id="send_code" class="btn btn-primary">åééªè¯ç </button>
{% endblock other_buttons %}
{% block script_extends %}
<script type="text/javascript">
$('#send_code').click(function(){
var email = $('#id_email').val(); // æ¿å°ç¨æ·å¡«çé®ç®±ç å¼
if(email == ''){
$('#tip').text('* é®ç®±ä¸è½ä¸ºç©º')
return false;
}
// ajax 弿¥åééªè¯ç
$.ajax({
url: "{% url 'send_verification_code' %}",
type: 'GET',
data: {
'email': email
},
cache: false,
success: function(data){
if(data['status'] == 'ERROR'){
alert(data['status']);
}
}
});
// ææé®åç°
$(this).addClass('disabled');
$(this).attr('disabled', true);
var time = 60;
$(this).text(time + 's åéæ°åé');
var interval = setInterval(() => {
if(time <= 0){
clearInterval(interval);
$(this).removeClass('disabled');
$(this).attr('disabled', false);
$(this).text('åééªè¯ç ');
return false;
}
time --;
$(this).text(time + 's åéæ°åé');
}, 1000);
});
</script>
{% endblock script_extends %}
33.忥é®ç®±çä½ç¨
-
é®ç®±ä½ç¨
- åå°åå¾ç¨æ·
- ä¿è¯è´¦å·å®å ¨
- æ¨éæ¶æ¯éç¥
-
å¼å¯¼ç¨æ·å¡«é®ç®±ï¼å¯ä»¥ä»æ³¨åçæ¶åè¦æ±å¡«åé®ç®±
- åéé®ä»¶ï¼å¡«éªè¯ç
- åééªè¯é®ä»¶é¾æ¥
- ç´æ¥ä½¿ç¨é®ç®±æ³¨å
- ä¹å¯ä»¥ä¸è¦å»å¡«é®ç®±ï¼å»ºè®®ç»å®åä¸å¯è§£ç»
-
ä¿®æ¹ç»å½æ¹å¼ï¼ç¨æ·ååé®ç®±é½å¯ä»¥ç»å½
- ä¿®æ¹ç»å½è¡¨åçæ°æ®éªè¯æ¹å¼
# Django_Course/mysite/user/forms.py
class LoginForm(forms.Form):
...
def clean(self):
username_or_email = self.cleaned_data['username_or_email']
password = self.cleaned_data['password']
user = auth.authenticate(username=username_or_email, password=password)
if user is None:
if User.objects.filter(email=username_or_email).exists():
username = User.objects.get(email=username_or_email).username
user = auth.authenticate(username=username, password=password)
if user is not None:
self.cleaned_data['user'] = user
return self.cleaned_data
raise forms.ValidationError('ç¨æ·åæå¯ç é误')
else:
self.cleaned_data['user'] = user
return self.cleaned_data
-
ä¿®æ¹å¯ç
- ç»å½çæ åµä¸ï¼ç´æ¥éªè¯æ§å¯ç æ¥è®¾ç½®
- æªç»å½çæ åµä¸ï¼å¿è®°å¯ç ï¼åééªè¯ç å°é®ç®±
-
ç´æ¥éªè¯æ§å¯ç æ¥è®¾ç½®æ°å¯ç
- æ·»å ä¿®æ¹å¯ç 表å
- æ·»å viewså¤çé»è¾
- æ·»å url
-
å¿è®°å¯ç ï¼åéé®ä»¶éªè¯ï¼ä¿®æ¹å¯ç
-
fix bug æ³¨ææ¸ é¤sessionä¸çéªè¯ç
34.è¯è®ºåéé®ä»¶éç¥
- å©ç¨é®ä»¶æé«è®¿é®é
- è¿ä¸æ¥åæ¥é®ç®±ä½ç¨
- 䏿¦è¢«è¯è®ºï¼åå¤ï¼äºï¼åéé®ä»¶éç¥ï¼è®©ç¨æ·å次访é®ç½ç«
# æ·»å è·åé®ç®±åurlçæ¹æ³ Django_Course/mysite/blog/models.py
class Blog(models.Model, ReadNumExpandMethod): # ç»§æ¿ æ¹æ³
...
author = models.ForeignKey(User, on_delete=models.CASCADE)
def get_url(self):
return reverse('blog_detail', kwargs={'blog_pk': self.pk})
def get_email(self):
return self.author.email
# åéé®ä»¶éç¥
if comment.parent is None:
# è¯è®ºæçå客
# åéé®ç®±
subject = 'æäººè¯è®ºä½ çå客'
email = comment.content_object.get_email()
else:
# åå¤è¯è®º
subject = 'æäººåå¤ä½ çå客'
email = comment.reply_to.email
if email != '':
text = comment.text + '\n' + comment.content_object.get_url()
send_mail( subject, text, settings.EMAIL_HOST_USER, [email],
fail_silently=False,)
- 弿¥åéé®ä»¶
- å 为åéé®ä»¶éè¦ç¹æ¶é´ï¼è¦ç¨å¾®çä¸ä¸æç»§ç»è¿è¡ä¸é¢ç¨åºï¼æä»¥éè¦å¼æ¥åé
- ç®åæ¹æ¡ï¼å¤çº¿ç¨ï¼ç®åãå®ç°
- å¤ææ¹æ¡ï¼Celery
- å¯ä»¥é²æ¢ä»»å¡è¿å¤
- å¯å®æ¶æ§è¡ä¸äºä»»å¡
- å¼éæ´å¤§
# å¤çº¿ç¨åéé®ä»¶
# Django_Course/mysite/comment/models.py
class SendMail(threading.Thread):
def __init__(self, subject, text, email, fail_silently=False):
self.subject = subject
self.text = text
self.email = email
self.fail_silently = fail_silently
threading.Thread.__init__(self)
def run(self):
send_mail(
self.subject,
'',
settings.EMAIL_HOST_USER,
[self.email],
fail_silently=self.fail_silently,
html_message=self.text
)
...
if email != '':
context = {}
context['comment_text'] = self.text
context['url'] = self.content_object.get_url()
text = render_to_string('comment/send_mail.html', context)
send_comment_thread = SendMail(subject, text, email)
send_comment_thread.start()
- htmlé®ä»¶æ¨¡ç
- å¯ä»¥åéhtmlé®ä»¶ï¼
html_messageåæ®µ - å¨commmentåºç¨ä¸é¢æ°å»º
templates/comment/send_mail.html - å ä¸åºç¨åï¼æ¯ä¸ºäºæ¹ä¾¿åºç¨çè¿ç§»ï¼é²æ¢å²çª
- å 为
self.textæ¯è¡¨ååæ®µï¼ä¼å«æ<p>æ ç¾ï¼æä»¥æ¨¡çééè¦åsafeè¿æ»¤æ - {{comment_text|safe}}ï¼è¿æ ·ä¼ è¿å»ç没æhtmlæ ç¾äº
- html 让é®ä»¶æ´å¥½çï¼ä½ä¹å®¹æä¸ºå¤ä¸ºåå¾é®ä»¶
- å¯ä»¥åéhtmlé®ä»¶ï¼
// Django_Course/mysite/comment/templates/comment/send_mail.html
{{ comment_text | safe }}
<br>
<a href="{{ url }}">ç¹å»æ¥ç</a>
// æè
{% autoescape off %}
{{ comment_text | safe }}
<br>
<a href="{{ url }}">ç¹å»æ¥ç</a>
{% autoescape%}
- é¨ç½²å°äºèç½
- æå¡å¨
- åå
- æ°æ®åºï¼MySQL 弿º å è´¹ 好ç¨
- æ´æ°ä»£ç ï¼çæ¬æ§å¶ Git
35.é¨ç½²åå¤ï¼ä¸ï¼ï¼Git
-
Git æ¯ä¸æ¬¾å¼æºçåå¸å¼çæ¬æ§å¶ç³»ç»
- éçæ²ä»£ç åä¿®æ¹ä»£ç ï¼æä»¬ç代ç 伿´æ°å¾å¤çæ¬ï¼ä¸è¯è½å¤å¶å¥½å¤ä»½æä»¶
- å°±éè¦çæ¬æ§å¶ç³»ç»ï¼ç®¡ç代ç çæ¬
- åå¸å¼ å¯¹æ¯ éä¸å¼
- å¿«éæ§å¶æå¡å¨ä»£ç çæ¬
- æå©äºå¢éåä½
-
Git å½ä»¤
- æªè¿½è¸ªUntracked -> tracked å·¥ä½åº working dir -> æååº staging area -> æ¬å°ä»åºlocalrepo
- HEADæåççæ¬å°±æ¯å½åçæ¬
- Gitå
许æä»¬å¨çæ¬çåå²ä¹é´ç©¿æ¢ï¼ä½¿ç¨å½ä»¤
git reset commit_id - ç©¿æ¢åï¼ç¨
git logå¯ä»¥æ¥çæäº¤åå²ï¼ä»¥ä¾¿ç¡®å®è¦åéå°åªä¸ªçæ¬ - è¦éè¿æªæ¥ï¼ç¨
git reflogæ¥çå½ä»¤åå²ï¼ä»¥ä¾¿ç¡®å®è¦åå°æªæ¥çåªä¸ªçæ¬ git cleanå½±åuntrackedçæä»¶ï¼git resetå½±åtrackedçæä»¶git cleanå½ä»¤ç¨æ¥ä»ä½ çå·¥ä½ç®å½ä¸å é¤æææ²¡ætrackedè¿çæä»¶git resetåªå½±å被trackè¿çæä»¶git clean -næ¯ä¸æ¬¡cleançæ¼ä¹ , åè¯ä½ åªäºæä»¶ä¼è¢«å é¤, åªæ¯ä¸ä¸ªæégit clean -dfå é¤å½åç®å½ä¸æ²¡æè¢«trackè¿ç æä»¶åæä»¶å¤¹git clean -få é¤å½åç®å½ä¸æææ²¡ætrackè¿çæä»¶. ä»ä¸ä¼å é¤.gitignoreæä»¶é颿å®çæä»¶å¤¹åæä»¶, ä¸ç®¡è¿äºæä»¶ææ²¡æè¢«trackè¿git clean -f <path>å 餿å®è·¯å¾ä¸ç没æè¢«trackè¿çæä»¶git clean -xfå é¤å½åç®å½ä¸æææ²¡ætrackè¿çæä»¶ åæä»¶å¤¹ . ä¸ç®¡ä»æ¯å¦æ¯.gitignoreæä»¶é颿å®çæä»¶å¤¹åæä»¶git reset commit_idåªå½±åæååºï¼å°æåä¿®æ¹çæä»¶æ¾å°å°å·¥ä½åºã Resets the index but not the working tree (i.e., the changed files are preserved but not marked for commit) and reports what has not been updated.git reset --soft commit_idæ 害ï¼ä¸ä¸¢å¤±æ´æ¹ãéç½®çæ¬æåï¼ä¸å½±å å·¥ä½åºåæååº æä»¶æ´æ¹ Does not touch the index file or the working tree at allgit reset --hard commit_idå±é©ï¼ä¼ä¸¢å¤±æ´æ¹ãåééç½® å·¥ä½åº å æååºï¼ä¸¢å¤±trackedæä»¶çæ´æ¹! Resets the index and working tree. Any changes to tracked files in the working tree since commit are discarded.
36.é¨ç½²åå¤ï¼äºï¼ï¼MySQL
-
MySQL æ¯ä¸æ¬¾æ¡å¹³å°ç弿ºçå ³ç³»åæ°æ®åº
- 为æå¡å¨ç«¯è设计ï¼é«å¹¶å访é®
- SQlite è½»é级ï¼å¯åµå ¥ï¼ä¸è½é«å¹¶å访é®ï¼éç¨æ¡é¢åºç¨åææºåºç¨
-
wheel whl å ï¼æ¯ç¼è¯å¥½çå ï¼å¯ä»¥ç´æ¥å®è£ ï¼ä¸ä¼åºç¼è¯é误
-
SQlite è¿ç§» MySQLï¼ å å¯¼åºæ°æ®ï¼åæ´æ¹ä¸º MySQL æ°æ®åºè®¾ç½®, åå¯¼å ¥æ°æ®
- ä½¿ç¨ Django 导åºå¯¼å ¥æ°æ®çå½ä»¤å®æè¿ç§»
python manage.py dumpdata > data.jsonpython manage.py loaddata data.json
-
é»è®¤åç¬¦éæ¨è utf8mb4
myslq -u root -p
# ä¿®æ¹å¯ç
alter user 'root'@'localhost' identified by 'pwd123456'
# åå»ºæ°æ®åº
create database mysite_db default charset=utf8mb4 collate utf8mb4_general_ci;
show databases;
# åå»ºç¨æ·
create user 'able'@'localhost' identified by 'pwd123456';
# æ·»å æéï¼mysite_db 徿æè¡¨
grant all privileges on mysite_db.* to 'able'@'localhost';
# å·æ°æé
flush privileges;
myslq -u able -p
show databases;
Django æ°æ®åºè®¾ç½®
# Database
# https://docs.djangoproject.com/en/2.0/ref/settings/#databases
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.mysql',
'NAME': 'mysite_db',
'USER': 'able',
'PASSWORD': 'pwd123456',
'HOST': '127.0.0.1',
'PORT': '3306',
}
}
django.core.exceptions.ImproperlyConfigured: Error loading MySQLdb module.
Did you install mysqlclient?
pip install mysqlclient
ç¶å è¿ç§»æ°æ®åº
python manage.py migrate
python manage.py createcachetable
python manage.py runserver
æ¶åºé®é¢ï¼å è½½æ¶åºæè¿°è¡¨ myslq_tzinfo_to_sql
- å®è·µè¿ç§»å° docker mysql
- å¯å¨æ°æ®åºï¼åå»ºæ°æ®åºï¼åå»ºç¨æ·ï¼æ·»å æé
- å¯¼åºæ°æ®åºï¼ä¿®æ¹settingsè®¾ç½®æ°æ°æ®åºåæ°
- è¿ç§»æ°æ®åºï¼æç¤ºå®è£
pip install mysqlclient - 导å
¥æ°æ®ï¼
python manage.py runserver - æ æ³å¯å¨ï¼
python manage.py createcachetableå¯ä»¥äº - æåï¼æ°æ®é½æ£å¸¸ï¼æ²¡é®é¢
Starting a MySQL instance is simple: # å ä¸ç«¯å£ ç¨localhostå¯ä»¥è¿æ¥
docker run --name mysql-test -p 3306:3306 -e MYSQL_ROOT_PASSWORD=123456 -d mysql
docker stop mysql-test
docker restart mysql-test
docker rm -f mysql-test
docker exec -it mysql-test bash
docker exec -it mysql-test mysql -uroot -p123456
- åºç°é®é¢åè§£å³æ¹æ³
- æ æ³è¿æ¥æ°æ®åº
(2002, "Can't connect to local MySQL server through socket '/tmp/mysql.sock'(2)")
(1045, "Access denied for user 'able'@'172.17.0.1' (using password: YES)")
CREATE USER 'username'@'host' IDENTIFIED BY 'password';
说æï¼usernameï¼ä½ å°å建çç¨æ·å
hostï¼æå®è¯¥ç¨æ·å¨åªä¸ªä¸»æºä¸å¯ä»¥ç»éï¼å¦ææ¯æ¬å°ç¨æ·å¯ç¨localhostï¼å¦ææ³è®©è¯¥ç¨æ·å¯ä»¥ä»ä»»æè¿ç¨ä¸»æºç»éï¼å¯ä»¥ä½¿ç¨éé
符%
CREATE USER 'pig'@'%';
å é¤ç¨æ· DROP USER 'username'@'host';
# åå»ºç¨æ·
create user 'able'@'%' identified by 'pwd123456';
# æ·»å æéï¼mysite_db 徿æè¡¨
grant all privileges on mysite_db.* to 'able'@'%';
# å·æ°æé
flush privileges;
mysql -u able -p
show databases;
django.db.utils.ProgrammingError: (1146, "Table 'mysite_db.my_cache_table' doesn't exist")
python manage.py createcachetable
37.é¨ç½²åå¤ï¼ä¸ï¼ï¼æå¡å¨
- æå¡å¨ï¼æµéæ¶æ¯ï¼å卿°æ®
- æå¡å¨å°±æ¯ä¸ºæä»¬æä¾æå¡çè®¡ç®æº
- è®¿é®æä¸ªç½ç«å®é 䏿¯è®¿é®æä¸ªæå¡å¨ç»æä»¬æä¾çä¿¡æ¯
38.ç¨Apache+mod_wsgié¨ç½²
- web æå¡å¨æä¹æä¾æå¡

-
Linux 常è§çwebæå¡å¨è½¯ä»¶
- Apache 模åå¤ï¼åè½å¼ºå¤§
- Nginx(Engine-x) è½»éçº§ï¼æé«å¹¶åï¼é度快