[TOC]

(continue)

  • add the template folder path to /Twittme/settings.py: ```bash

TEMPLATES = [ { ‘BACKEND’: ‘django.template.backends.django.DjangoTemplates’,

    # 'DIRS': [],
    'DIRS': [os.path.join(BASE_DIR, "templates")],
    'APP_DIRS': True,
    'OPTIONS': {
        'context_processors': [
            'django.template.context_processors.debug',
            'django.template.context_processors.request',
            'django.contrib.auth.context_processors.auth',
            'django.contrib.messages.context_processors.messages',
        ],
    },
},

]

and we can refer our templates to requests.

- First, we prepare 2 folders, pages/ and tweets/ for templates/
- Then setup a home.html for the default page in pages/
```bash
(reactjs) [root@localhost Twittme]# tree
.
├── db.sqlite3
├── manage.py
├── templates
│   ├── pages
│   │   └── home.html
│   └── tweets
├── todo.md
├── tweets
│   ├── admin.py
│   ├── apps.py
│   ├── __init__.py
│   ├── migrations
│   │   ├── 0001_initial.py
│   │   └── __init__.py
│   ├── models.py
│   ├── tests.py
│   └── views.py
└── Twittme
    ├── __init__.py
    ├── settings.py
    ├── urls.py
    └── wsgi.py

6 directories, 16 files
<!--home.html-->
<h1>Hello World</h1>
  • now we cam simply refer the default path in /tweets/views.py to the template page before:

    # ...
    def home_view(request, *args, **kwargs):
      # return HttpResponse("<h1>Hello World</h1>")
      return render(request, "pages/home.html", context={}, status=200)
    # ...
    

    Bootstrap & Django Templates:

  • apply Starter template in https://getbootstrap.com/docs/4.5/getting-started/introduction/ to replace home.html before:

    <!doctype html>
    <html lang="en">
    <head>
      <!-- Required meta tags -->
      <meta charset="utf-8">
      <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
    
      <!-- Bootstrap CSS -->
      <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.5.0/css/bootstrap.min.css" integrity="sha384-9aIt2nRpC12Uk9gS9baDl411NQApFmC26EwAOH8WgZl5MYYxFfc+NcPb1dKGj7Sk" crossorigin="anonymous">
    
      <title>Hello, world!</title>
    </head>
    <body>
      <h1>Hello, world!</h1>
    
      <!-- Optional JavaScript -->
      <!-- jQuery first, then Popper.js, then Bootstrap JS -->
      <script src="https://code.jquery.com/jquery-3.5.1.slim.min.js" integrity="sha384-DfXdz2htPH0lsSSs5nCTpuj/zy4C+OGpamoFVy38MVBnE+IbbVYUew+OrCXaRkfj" crossorigin="anonymous"></script>
      <script src="https://cdn.jsdelivr.net/npm/popper.js@1.16.0/dist/umd/popper.min.js" integrity="sha384-Q6E9RHvbIyZFJoft+2mJbHaEWldlvI9IOYy5n3zV9zzTtmI3UksdQRVvoxMfooAo" crossorigin="anonymous"></script>
      <script src="https://stackpath.bootstrapcdn.com/bootstrap/4.5.0/js/bootstrap.min.js" integrity="sha384-OgVRvuATP1z7JjHLkuOU7Xw704+h835Lr+6QL9UvYjZE3Ipu6Tp75j7Bh/kR0JKI" crossorigin="anonymous"></script>
    </body>
    </html>
    

    to test, access the homepage again:
    image.png
    there’s title, and font is different, it means the new template is successfully applied.

  • create a base.html in templates/ to increase code reuse:

    <!doctype html>
    <html lang="en">
    <head>
      <!-- Required meta tags -->
      <meta charset="utf-8">
      <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
    
      <!-- Bootstrap CSS -->
      <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.5.0/css/bootstrap.min.css" integrity="sha384-9aIt2nRpC12Uk9gS9baDl411NQApFmC26EwAOH8WgZl5MYYxFfc+NcPb1dKGj7Sk" crossorigin="anonymous">
    
      <title>Twittme</title>
    </head>
    <body>
      {% block content %}
      {% endblock content %}
    
      <!-- Optional JavaScript -->
      <!-- jQuery first, then Popper.js, then Bootstrap JS -->
      <script src="https://code.jquery.com/jquery-3.5.1.slim.min.js" integrity="sha384-DfXdz2htPH0lsSSs5nCTpuj/zy4C+OGpamoFVy38MVBnE+IbbVYUew+OrCXaRkfj" crossorigin="anonymous"></script>
      <script src="https://cdn.jsdelivr.net/npm/popper.js@1.16.0/dist/umd/popper.min.js" integrity="sha384-Q6E9RHvbIyZFJoft+2mJbHaEWldlvI9IOYy5n3zV9zzTtmI3UksdQRVvoxMfooAo" crossorigin="anonymous"></script>
      <script src="https://stackpath.bootstrapcdn.com/bootstrap/4.5.0/js/bootstrap.min.js" integrity="sha384-OgVRvuATP1z7JjHLkuOU7Xw704+h835Lr+6QL9UvYjZE3Ipu6Tp75j7Bh/kR0JKI" crossorigin="anonymous"></script>
    </body>
    </html>
    

    and change home.html before to build HTML file based on base.html: ```html {% extends ‘base.html’ %}

{% block content %} Welcome to Twittme {% endblock content %}

to test, runserver and access localhost:8000 again:<br />![image.png](https://cdn.nlark.com/yuque/0/2020/png/1243266/1591328855821-fb51c47c-75b6-4560-ae3b-590b99a43506.png#align=left&display=inline&height=176&margin=%5Bobject%20Object%5D&name=image.png&originHeight=351&originWidth=489&size=14762&status=done&style=none&width=244.5)<br />so the base.html extension is successful.

- multiple blocks can be in the same pair, if we add another block in base.html:
```html
<!--base.html-->
<title>Twittme {% block head_title %} {% endblock head_title %} </title>
<!--...-->

then add a block with the same name in home.html:

<!--home.html-->
{% block head_title %}
This is amazing!
{% endblock head_title %}
<!--...-->

to test, runserver and access localhost:8000 to watch the title of the browser:
image.png
and we see ‘head_title’ is also extended.

Tweet List View:

now we need a view to show all tweets:

  • create tweet_list_view in /tweets/views.py
    # ...
    def tweet_list_view(request, *args, **kwargs):
      qs = Tweet.objects.all() # grad all objects in Tweet
      tweets_list = [{"id" : x.id, "content" : x.content} for x in qs]
      data = {
          "isUser" : False,
          "response" : tweets_list
      }
      return JsonResponse(data)
    # ...
    
    and add a pth in /Twittme/urls,py ```python from django.contrib import admin from django.urls import path, re_path

from tweets.views import home_view, tweet_detail_view, tweet_list_view # new

urlpatterns = [ path(‘admin/‘, admin.site.urls), path(‘’, home_view), path(‘tweets’, tweet_list_view), # new path(‘tweets/‘, tweet_detail_view), ]

to test, runserver and access localhost:8000/tweets<br />![image.png](https://cdn.nlark.com/yuque/0/2020/png/1243266/1591332326562-9aaff53c-a5c2-4ec0-9a4a-f5af4b33d971.png#align=left&display=inline&height=106&margin=%5Bobject%20Object%5D&name=image.png&originHeight=211&originWidth=490&size=15874&status=done&style=none&width=245)<br />and we see returned data with an attribute "response" -  a list of all tweets.

<a name="DrMqO"></a>
#### Dynamic Load Tweets via JavaScript

- and a <script> to home.html, let the page send a "GET" request to /tweets
```python
{% extends 'base.html' %}

{% block head_title %}
This is amazing!
{% endblock head_title %}

{% block content %}
Welcome to Twittme

<script>
    const xhr = new XMLHttpRequest()
    const method = 'GET'
    const url = '/tweets'
    const responseType = 'json'

    xhr.responseType = responseType
    xhr.open(method, url)
    xhr.onload = function() {
      console.log(xhr.response)
    }
    xhr.send()
</script>
{% endblock content %}

to test, access localhost:8000
image.png
In the console, we saw response (the list of tweets)

  • if we want to only get content, we specify it.
  • modify xhr.onload in home.html:
    <script>  //...
    xhr.onload = function() {
      const serverResponse = xhr.response
      var listedItems = serverResponse.response
      console.log(listedItems)
    }
    //...
    </script>
    
    runserver and access:
    image.png
    and now we have HTML content that only includes tweets

Replace HTML Content with JavaScript:

  • still in home.html: ```html {% block content %} Welcome to Twittme
Replace me

{% endblock content %}

if we ignore script, the next line displayed after "Welcome to Twittme" is "Replace me", but we changed innerHTML, so actually:<br />![image.png](https://cdn.nlark.com/yuque/0/2020/png/1243266/1591347232350-c7323c5d-17c5-4045-b1b6-cfbdc6250b35.png#align=left&display=inline&height=192&margin=%5Bobject%20Object%5D&name=image.png&originHeight=305&originWidth=489&size=15755&status=done&style=none&width=308)<br />it's "Loading..."<br />so after this test, we know how to replace lines if necessary.<br /> 

- another test case, still in home.html:
```html
{% block content %}
Welcome to Twittme

<div id='tweets'>
  Replace me
</div>

<script>
  const tweetsElement = document.getElementById("tweets") //get an HTML element

  tweetsElement.innerHTML = 'Loading...' //set new HTML in that element

  var el1 = "<h1>Hi there 1</h1>"
  var el2 = "<h1>Hi there 2</h1>"
  var el3 = "<h1>Hi there 3</h1>"
  tweetsElement.innerHTML = el1 + el2 + el3
    //...
</script>
{% endblock content %}

and we see:
image.png
it means we can do innerHTML replacement by adding either, but should take care of format.

Tweets to HTML via JavaScript:

we need to iterate(loop) all tweets in the list.

  • still in home.html: ```html {% block content %} Welcome to Twittme
Replace me

{% endblock content %}


- to show that the loop is successful add a new object to the list:
```bash
(reactjs) [root@localhost Twittme]# ./manage.py shell
Python 3.6.5 (default, Sep 10 2018, 09:39:42) 
[GCC 4.8.5 20150623 (Red Hat 4.8.5-28)] on linux
Type "help", "copyright", "credits" or "license" for more information.
(InteractiveConsole)
>>> from tweets.models import Tweet
>>> obj = Tweet.objects.create(content='Hello there #2')
>>> exit()

runserver:
image.png
and we can see i and listedItems[i] are shown in the log.

  • pend listedItems variables and change the innerHTML of the content: ```html {% block content %} Welcome to Twittme
Replace me

{% endblock content %} ``` to test, runserver:
image.png