Code Monkey home page Code Monkey logo

django's Introduction

Django

Framework sử dụng mô hình MTV (Model-Template-View) nhưng cơ bản của nó là từ mô hình MVC (model-view-controller)

Lưu ý: Django trong project này là Django 3

Cài đặt

Trên Windows

  • Cài Python 3.7
  • pip install django
  • Tạo project đầu tiên: django-admin startproject mywebsite .
  • python manage.py startapp home

  • Khai báo ứng dụng home cho project tại file settings.py:

    INSTALLED_APPS = [
      'django.contrib.admin',
      'django.contrib.auth',
      'django.contrib.contenttypes',
      'django.contrib.sessions',
      'django.contrib.messages',
      'django.contrib.staticfiles',
      'home'
    ]
  • Cập nhật project: python manage.py migrate

  • Viết chương trình ứng dụng home đầu tiên:

    • Trong file views.py:
    from django.shortcuts import render
    from django.http import HttpResponse
    
    def index(response):
        response = HttpResponse()
        response.writelines("<h1>Xin chào</h1>")
        response.write("<h2>Đây là app home</h2>")
        return response
    • Trong file urls.py:
      from django.urls import path
      from . import views
    
      urlpatterns = [
        path('', views.index)
      ]
    • Trong file tests.py:
    from django.test import TestCase, SimpleTestCase
    class SimpleTest(SimpleTestCase)
      def test_home_status(self)
        response = self.client.get('/home')
        self.assertEqual(response.status_code, 200)
    • Trong file mywebsite/urls.py
    from django.contrib import admin
    from django.urls import path, include
    
    urlpatterns = [
      path('admin/', admin.site.urls),
      path('home/', include('home.urls'))
    ]

    Mục đích tạo template trong Django là để tái sử dụng giao diện nhiều lần trong project và ứng dụng

    Ví dụ:

    Trong thư mục home tạo:

    • templates/pages/base.html: Ý ở đây là template nền tảng

      <!DOCTYPE html>
      <html>
          <head>
              <meta charset="UTF-8">
              <meta name="viewport" content="width=device-width, initial-scale=1.0">
              <meta http-equiv="X-UA-Compatible" content="ie=edge">
              <title>{% block title%} {% endblock %}</title>
          </head>
          <body>
          Content:
      
          {% block content %}
          {% endblock %}
          </body>
      </html>
  • templates/pages/home.html: Ở đây, home.html được kế thừa từ template base.html:

      {% extends "pages/base.html" %}
    
      {% block title %}Home{% endblock %}
    
      {% block content %} 
          <h1>Xin chào</h1>
          <h2>Đây là app home</h2>
      {% endblock %}
  • File views.py viết:

    from django.shortcuts import render
    from django.http import HttpResponse
    
    def index(request):
      return render(request, 'pages/home.html')
  • Chạy project: python manage.py runserver

Tạo Blog

  • Tạo app mới: python manage.py startapp blog

  • Cập nhật file settings.py tại dòng lệnh INSTALLED_APPS:

     	INSTALLED_APPS = [
     	'django.contrib.admin',
     	'django.contrib.auth',
     	'django.contrib.contenttypes',
     	'django.contrib.sessions',
     	'django.contrib.messages',
     	'django.contrib.staticfiles',
     	'home', 
     	'blog',
     ]
  • Cập nhật lại project: python manage.py migrate

  • Trong file models.py của app blog tạo model database:

     from Django.db import models
     class Post(models.Model):
     	title 	= models.CharField(max_length=100)
     	content = models.TextField()
     	date    = models.DateTimeField(auto_now_add=True)
  • Cập nhật ứng dụng blog sau khi tạo xong model: python manage.py makemigrations blog

  • Cập nhật lại project sau khi cập nhật xong ứng dụng: python manage.py migrate

  • Xem và kiểm tra cơ sở dữ liệu sau khi cập nhật xong project. Ở đây dùng SQLite DB

Lưu trữ file metadata trong thư mục static trên môi trường product

Sử dụng static file

{% load static %}
...
<link rel="stylesheet" href="{% static 'css/bootstrap.min.css' %}">

Nếu chạy sản phẩm demo trên máy local thì chỉ cần chạy dòng lệnh sau đây là có thể gọi static thoải mái: python manage.py runserver --insecure

Trên môi trường product như: Heroku, AWS, Openshift, PaaS,... nếu chỉ đơn thuần gọi cú pháp sử dụng các file static thì chương trình sẽ không tìm thấy các file hình ảnh, video, css, js,... Vì vậy, để giải quyết vấn đề đó thì có một giải pháp là cài thêm gói whitenoise và cấu hình file settings.py

pip install whitenoise

Cấu hình trong file settings.py thì có thể tham khảo như sau:

MIDDLEWARE = [
    'whitenoise.middleware.WhiteNoiseMiddleware',
    ...
]

STATICFILES_STORAGE = 'whitenoise.storage.CompressedStaticFilesStorage'
STATIC_URL = '/static/'
STATIC_ROOT = os.path.join(BASE_DIR, 'home/static')
STATICFILES_DIRS = (
    os.path.join(BASE_DIR, 'static'),
)

Tương tác với Cơ sở dữ liệu trong Django

  • Chạy dòng lệnh sau để tương tác với CSDL: python manage.py shell

  • Gọi đối tượng model đã tạo trong app ra tương tác với DB:

    >>> from blog.models import Post
    >>> p = Post()
    >>> p.title = "Bài viết đầu tiên"
    >>> p.content = "AI trong thế kỷ 21"
    >>> p.save()
    >>> Post.objects.all()
    >>> p =Post.objects.get(id=1)
    >>> p.title
    >>> p.content 
    >>> p.date
    >>> p = Post(title = "AI Python", content = "Lập trình Python với Tensorflow")
    >>> p.save()
    >>> Post.objects.all()

    Mục đích: Quản lý user, group, hệ thống bài viết cho blog

    • Tạo user, pass đăng nhập hệ thống admin của blog: python manage.py createsuperuser

    • Chạy project: python manage.py runserver

    • Truy cập trang admin: http://localhost:8000/admin và đăng nhập hệ thống

    • Tạo chức năng quản trị bài viết:

      Trong file admin.py của ứng dụng blog đã tạo trước viết mã:

      from django.contrib import admin
      from .models import Post
      
      class PostAdmin(admin.ModelAdmin):
        list_display  = ['title', 'date']
        list_filter   = ['date']
        search_fields = ['title']
      admin.site.register(Post, PostAdmin)
      • title, date là những thuộc tính trong model Post đã tạo trên
    • Kết quả:

      Django Administrator

      Django Administrator

    • Tạo model DB cho bài viết:
    from django.db import models
    class Post(models.Model):
        title   = models.CharField(max_length=100)
        content = models.TextField()
        date    = models.DateTimeField(auto_now_add=True)
        def __str__(self):
            return self.title
    • Trong file blog/views.py viết hai hàm hiển thị danh sách bài viết list và chi tiết bài viết post:
    from django.shortcuts import render
    from .models import Post
    
    def list(request):
        data = {'Posts': Post.objects.all().order_by("-date")}
        return render(request, 'blog/blog.html', data)
    
    def post(request, id):
        post = Post.objects.get(id=id)
        return render(request, 'blog/post.html', {'post' : post})
    • Tạo template bài viết: Tạo thư mục templates/blog chứa hai file template html: blog.html, post.html

      Hai template này sẽ hiển thị dữ liệu render từ view

      • blog.html
      {% extends 'pages/base.html' %}
      {% block title %}Blog Display{% endblock %}
      {% block content %}
        {% for post in Posts %}
              <h5>{{post.date|date:"d/m/Y"}} - <a href="/blog/{{post.id}}">{{post.title}}</a></h5>
        {% endfor %}
      {% endblock %}
      • post.html
      {% extends "pages/base.html" %}
      {% block title %}{{post.title}}{% endblock %}
      {% block content %}
        <h3><a href="blog/{{post.id}}">{{post.title}}</a></h3>
        <h6>on {{post.date}}</h6>
        {{post.content|safe|linebreaks}}
      {% endblock %}
    • Cấu hình URL trong urls.py của ứng dụng blog

    from django.urls import path
    from . import views
    
    urlpatterns = [
        path('', views.list),
        path('<int:id>/', views.post)
    ]
    • Cấu hình URL trong urls.py của project
    from django.contrib import admin
    from django.urls import path, include
    
    urlpatterns = [
        path('admin/', admin.site.urls),
        path('', include('home.urls')),
        path('blog/', include('blog.urls'))
    ]
    • Viết Test case kiểm thử hai chức năng trên của blog:
    from django.test import TestCase
    from .models import Post
    
    class BlogTest(TestCase):
        def setUp(self):
            Post.objects.create(
                title="My Title",
                content="This is a just test"
            )
        def test_string_representation(self):
            post = Post(title="My entry title")
            self.assertEqual(str(post), post.title)
        def test_post_list_view(self):
            response = self.client.get("/blog/")
            self.assertEqual(response.status_code, 200)
            self.assertContains(response, 'My Title')
            self.assertTemplateUsed(response, 'blog/blog.html')
        def test_post_detail_view(self):
            response = self.client.get("/blog/1/")
            self.assertEqual(response.status_code, 200)
            self.assertContains(response, 'My Title')
            self.assertTemplateUsed(response, 'blog/post.html')
    • Kết quả:

    Hardcode URL trong Django

    Hardcoce là bất cứ những gì được gán cố định đối với những có thể sẽ thay đổi trong quá trình phát triển của phần mềm với mục đích nào đó.

    VD: Đường dẫn URL: http://localhost:8000/blog/1, http://localhost:8000/java/spring-mvc/1, http://localhost:8000/categories/network/1,...

    • Loại bỏ hardcode trong lập trình web Django:

      • Thêm thuộc tính name trong mảng urlpatterns trong file urls.py của ứng dụng blog
      from django.urls import path
      from . import views
      
      urlpatterns = [
          path('', views.list, name="blog"),
          path('<int:id>/', views.post, name = "post")
      ]
      • Gọi đường dẫn với cú pháp tương đương.

      VD: <a href="{% url 'blog' %}">Bài viết</a>

Ở đây, tại ứng dụng home thì thực hiện một số công việc:

  • Tạo template home/templates/error.html:
{% extends "pages/base.html" %}

{% block title %}Error{% endblock %}

{% block content %} 
    <h4>Your requested page, Not Found.</h4>
{% endblock %}
  • Tạo hàm render template home/templates/error.html trong thư mục home/views.py:
def error404(request, exception):
    return render(request, "pages/error.html")
def error500(request):
    return render(request, "pages/error.html")
  • Tại file urls.py của project thì chỉnh sửa cấu hình:
from django.contrib import admin
from django.urls import path, include
from django.conf.urls import handler400, handler500

urlpatterns = [
    path('admin/', admin.site.urls),
    path('', include('home.urls')),
    path('blog/', include('blog.urls'))
]
handler400 = 'home.views.error404'
handler500 = 'home.views.error500'
  • Chỉnh sửa cấu hình trong file settings.py của project:
DEBUG = False
ALLOWED_HOSTS = ["*"]

Lưu ý: Khi đổi DEBUG = False thì các file static của admin sẽ không hoạt động. Vì vậy hãy cố gắng tìm cách giải quyết. Nhưng có thể tham khảo project 404.

  • Trong ứng dụng blog tạo thêm thuộc tính image cho model:
from django.db import models

class Post(models.Model):
    title   = models.CharField(max_length=100)
    content = models.TextField()
    date    = models.DateTimeField(auto_now_add=True)
    image   = models.ImageField(null=True)
    def __str__(self):
        return self.title

Chạy dòng lệnh cập nhật model:

  • python manage.py makemigrations

  • python manage.py migrate

  • Cấu hình đường dẫn upload hình ảnh trong file settings.py của project:

MEDIA_URL = '/media/'
MEDIA_ROOT = os.path.join(BASE_DIR, 'media')
  • Trong file urls.py của project, thêm dòng code để cấu hình đường dẫn nơi lưu trữ:
from django.views.static import serve

if settings.DEBUG:
  urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
else:
    urlpatterns += [
        url(r'^media/(?P<path>.*)$', serve,{'document_root': settings.MEDIA_ROOT})
  ]
  • Upload hình ảnh trong backend admin:

  • Liệt kê bài viết:

    Trong blog.html:

      {% if post.image %}
          <img src="{{post.image.url}}" width="500px" height="300px"> 
      {% endif %} 

    Trong post.html:

      {% if post.image %}
          <img src="{{post.image.url}}" width="500px" height="300px"> 
      {% endif %} 
    • Chức năng đăng ký:

      • Tạo file form.py trong ứng dụng home:
      from django import forms
      from django.contrib.auth.models import User
      from django.core.exceptions import ObjectDoesNotExist
      import re
      
      class RegistrationForm(forms.Form):
          username  = forms.CharField(label='Tài khoản', max_length=30)
          email     = forms.EmailField(label='Email')
          password1 = forms.CharField(label='Mật khẩu', widget=forms.PasswordInput())
          password2 = forms.CharField(label='Nhập lại mật khẩu', widget=forms.PasswordInput())
          def clean_password2(self):
              if 'password1' in self.cleaned_data:
                  password1 = self.cleaned_data['password1']
                  password2 = self.cleaned_data['password2']
                  if password1 == password2 and password1:
                      return password2
                  raise forms.ValidationError("Mật khẩu không hợp lệ")
          def clean_username(self):
              username = self.cleaned_data['username']
              if not re.search(r'^\w+$', username):
                  raise forms.ValidationError("Tên tài khoản có kí tự đặt biệt")
              try:
                  User.objects.get(username=username)
              except ObjectDoesNotExist:
                  return username
              raise forms.ValidationError("Tên tài khoản đã tồn tại")
          def save(self):
              User.objects.create_user(username=self.cleaned_data['username'], 
                                                  email=self.cleaned_data['email'], 
                                                      password=self.cleaned_data['password1'])
      • Tạo template cho chức năng đăng ký trong ứng dụng home theo đúng cú pháp: register.html
      • Tạo template cho chức năng đăng nhập trong ứng dụng home theo đúng cú pháp: login.html
      • Tạo chức năng xử lý view trong home/views.py:
      def register(request):
        form = RegistrationForm()
        if request.method == 'POST':
            form = RegistrationForm(request.POST)
            if form.is_valid():
                form.save()
                return HttpResponseRedirect('/')
        return render(request, 'pages/register.html', {'form':form})
      path('login/', auth_views.LoginView.as_view(template_name='pages/login.html'), name='login'),
      path('logout/', auth_views.LogoutView.as_view(next_page='/'), name='logout')

Nếu viết các hàm xử lý view là hơi phức tạp thì Django có thư viện generic view, là một tập các class thư viện xử lý view hỗ trợ xử lý view nhanh hơn.

Dưới đây là liệt kê các class trong thư viện generic view

>>> import django.views.generic
>>> dir(django.views.generic)

['ArchiveIndexView', 'CreateView', 'DateDetailView', 'DayArchiveView', 
   'DeleteView', 'DetailView', 'FormView', 'GenericViewError', 'ListView', 
   'MonthArchiveView', 'RedirectView', 'TemplateView', 'TodayArchiveView', 
   'UpdateView', 'View', 'WeekArchiveView', 'YearArchiveView', '__builtins__', 
   '__doc__', '__file__', '__name__', '__package__', '__path__', 'base', 'dates', 
   'detail', 'edit', 'list']

Trong file urls.py thì cấu hình và viết lệnh:

from django.urls import path
from django.views.generic import ListView, DetailView
from . import views
from .models import Post

urlpatterns = [
    path('', ListView.as_view(
        queryset            = Post.objects.all().order_by("-date"),
        template_name       = 'blog/blog.html',
        context_object_name = 'Posts',
        paginate_by         = 2,
    ), name="blog"),
    path('<int:pk>/', DetailView.as_view(
        model = Post,
        template_name = 'blog/post.html'
    ), name = "post")
]
urlpatterns = [
    ...
    path('<int:pk>/', views.post, name="post")
]
class Comment(models.Model):
    post = models.ForeignKey(Post, on_delete=models.CASCADE, related_name='comments')
    author = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
    content = models.TextField()
    data = models.DateTimeField(auto_now_add=True)
+ Cập nhật lại DB: `python manage.py makemigrations` và `python manage.py migrate`
from django import forms
from .models import Comment
class CommentForm(forms.ModelForm):
    def __init__(self, *args, **kwargs):
        self.author = kwargs.pop('author', None)
        self.post   = kwargs.pop('post', None)
        super().__init__(*args, **kwargs)
    def save(self, commit=True):
        comment        = super().save(commit=False)
        comment.author = self.author
        comment.post   = self.post
        comment.save()
    class Meta:
        model  = Comment
        fields = ['content'] 
from django.shortcuts import render, get_object_or_404
from .models import Post, Comment
from .forms import CommentForm
from django.http import HttpResponseRedirect
def post(request, pk):
    post = get_object_or_404(Post, pk=pk)
    form = CommentForm()
    if request.method == 'POST':
        form = CommentForm(request.POST, author=request.user, post=post)
        if form.is_valid():
            form.save()
    return render(request, "blog/post.html", {'post':post, 'form':form})
from django.contrib import admin
from .models import Post, Comment

class CommentInline(admin.StackedInline):
    model = Comment
class PostAdmin(admin.ModelAdmin):
    list_display  = ['title', 'date']
    list_filter   = ['date']
    search_fields = ['title']
    inlines       = [CommentInline] 
admin.site.register(Post, PostAdmin)
  • Kết quả:

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.