スナックelve 本店

バツイチ派遣40代女性の日記です

エンジニア・プログラマにしか使えないSNSとやらを一介の事務派遣が覗いてみようじゃぁないか!2

追記

index.htmlの
{{tweet.text}}を
{{tweet.text | linebreaks | urlize}}
にしたほうが幸せになれそうです。
参考:【Django】model:テキストフィールド表示時に自動でp・br・a要素を付ける | OFFICE54
<終わり>
f:id:elve:20210723205107p:plain

本日の進捗

フォルダ構成

├─SNS
│  └─mysite
│      ├─mysite
│      │  └─__pycache__
│      └─polls
│          ├─migrations
│          │  └─__pycache__
│          ├─static
│          ├─templates
│          │  ├─polls
│          │  └─user
│          └─__pycache__

SNS\mysite\mysite\urls.py

from django.contrib import admin
from django.urls import include, path

urlpatterns = [
    path('polls/', include('polls.urls')),
    path('admin/', admin.site.urls),
]

SNS\mysite\mysite\settings.py

import os #大事
#中略
INSTALLED_APPS = [
    'polls.apps.PollsConfig',
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
]
#中略
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',
            ],
        },
    },
]
#中略
LANGUAGE_CODE = 'ja'
TIME_ZONE = 'Asia/Tokyo'
#中略
# https://kokiblog.com/2019/09/12/django_css/
# https://blog.fantom.co.jp/2021/01/23/name-os-is-not-defined/
STATICFILES_DIRS = [
    os.path.join(BASE_DIR, "static"),
]

SNS\mysite\polls\views.py

from django.shortcuts import render
import requests
from polls.models import USERS,TWEETS
from polls.forms import UserForm
import datetime
from django.views.generic import FormView 
import json

def get_username(my_user_id):
    try:
        user = USERS.objects.get(user_id = my_user_id)
        username=user.name
        userdescription=user.description
    except USERS.DoesNotExist:
        username = my_user_id
        userdescription=""
    return {'username':username,'userdescription':userdescription}
    
class UserFormView(FormView):
    template_name = 'user/user.html'
    form_class = UserForm
    success_url = 'http://localhost:8000/polls/'
    def form_valid(self, form):
        #https://hombre-nuevo.com/python/python0075/#h3_7
        sess = requests.session()
        url = "https://versatileapi.herokuapp.com/api/user/create_user"
        # ヘッダ
        headers = {'Authorization': 'HelloWorld'}
        # 送信データ
        prm = {"name": form.data.get("name"),"description":form.data.get("description")}
        print(prm)
        # JSON変換
        params = json.dumps(prm)
        # POST送信
        res = sess.put(url, data=params, headers=headers)
        
        return super().form_valid(form)
def get_object():
    url = "https://versatileapi.herokuapp.com/api/user/all"
    users = requests.get(url).json()
    USERS.objects.all().delete()
    for user in users:
        USERS.objects.create(
            id = user['id'],
            created_at = datetime.datetime.fromisoformat(user['_created_at']) ,
            updated_at = datetime.datetime.fromisoformat(user['_updated_at']) ,
            user_id = user['_user_id'],
            description = user['description'],
            name = user['name'])

    url = "https://versatileapi.herokuapp.com/api/text/all?$orderby=_created_at desc"#全部取得すると重いので・・・
    tweets = requests.get(url).json()
    TWEETS.objects.all().delete()
    for tweet in tweets:
        Uid = tweet['_user_id']
        my_user = get_username(Uid)
        if 'in_reply_to_user_id' in tweet:
            re_user = get_username(tweet['in_reply_to_user_id'])
        else:
            re_user={'username':"",'userdescription':""}


        TWEETS.objects.create(
            id = tweet['id'],
            created_at = datetime.datetime.fromisoformat(tweet['_created_at']) ,
            updated_at = datetime.datetime.fromisoformat(tweet['_updated_at']) ,
            user_id = Uid,
            in_reply_to_text_id = tweet['in_reply_to_text_id'] if 'in_reply_to_text_id' in tweet  else "",
            in_reply_to_user_id = tweet['in_reply_to_user_id'] if 'in_reply_to_user_id' in tweet  else "",
            in_reply_to_user_name=re_user['username'],
            text = tweet['text'],
            user_name = my_user['username'],
            user_description= my_user['userdescription'])
    output = {'tweets': TWEETS.objects.all()}
    return output

     
def index(request):
    if request.method=='GET':
        o = get_object()
        return render(request, 'polls/index.html',o)
    if request.method=='POST':
        #https://hombre-nuevo.com/python/python0075/#h3_7
        sess = requests.session()
        url = "https://versatileapi.herokuapp.com/api/text/"
        # ヘッダ
        headers = {'Authorization': 'HelloWorld'}
        # 送信データ
        prm = {"text": request.POST['text']}
        # JSON変換
        params = json.dumps(prm)
        # POST送信
        res = sess.post(url, data=params, headers=headers)
        
        o = get_object()
        return render(request, 'polls/index.html',o)

SNS\mysite\polls\models.py

from django.db import models

# Create your models here.

class USERS(models.Model):
    id = models.CharField(primary_key=True,max_length=40)
    created_at = models.DateTimeField()
    updated_at = models.DateTimeField()
    user_id = models.CharField(max_length=40)
    description = models.TextField(max_length=300)
    name = models.CharField(max_length=40)


class TWEETS(models.Model):
    id = models.CharField(primary_key=True,max_length=40)
    created_at = models.DateTimeField()
    updated_at = models.DateTimeField()
    user_id= models.CharField(max_length=40)
    in_reply_to_text_id= models.CharField(max_length=40)
    in_reply_to_user_id= models.CharField(max_length=40)
    in_reply_to_user_name=models.CharField(max_length=30,null=True)
    text= models.TextField(max_length=200)
    user_name = models.CharField(max_length=30,null=True)
    user_description =  models.TextField(max_length=300,null=True)

SNS\mysite\polls\forms.py

要ファイル作成

from django import forms
#https://note.com/mihami383/n/n29630c65abf6
#https://qiita.com/box16/items/23f78e1014f6dc8f849e

class UserForm(forms.Form):
   name=forms.CharField(label ="名前", max_length=30);
   description=forms.CharField(label ="自己紹介", widget=forms.Textarea, max_length=300);

SNS\mysite\polls\urls.py

from django.urls import path
from .views import index, UserFormView

urlpatterns = [
    path('', index, name='index'),
    path('user/', UserFormView.as_view(), name='user'),
]

SNS\mysite\polls\templates

要フォルダ作成
中にpollsとuserってフォルダも作る

SNS\mysite\polls\templates\polls\index.html
<!DOCTYPE html>
<!--https://kokiblog.com/2019/09/12/django_css/-->
<!--https://www.nishishi.com/javascript-tips/input-counter.html-->
{% load static %}
<html>
<head>
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <meta charset="UTF-8">
  <title>index.html</title>
  <link rel="stylesheet" href="{% static 'style1.css' %}">
  <script type="text/javascript">
    function ShowLength( str ) {
      document.getElementById("inputlength").innerHTML = str.length + "文字";
    }
  </script>
</head>
<body>
  <h1>例のSNS</h1>
    <div class="box27" id="link">
      <p><a href="./user/">ユーザー情報更新</a></p>
    </div>
    <form action="" method="post" class="box27">
    {% csrf_token %}
    <fieldset>
      <legend><h1>つぶやく</h1></legend>
      {% if error_message %}<p><strong>{{ error_message }}</strong></p>{% endif %}
      <label id="inputlength">280文字までよ</label><br>
      <textarea id="add-tweet" name="text" rows="5" cols="60" maxlength="280" onkeyup="ShowLength(value);"></textarea>
    </fieldset>
    <input type="submit" value="囁き 祈り 詠唱 念じよ!">
    </form>

{% for tweet in tweets %}

  <div class="box27" id="{{tweet.id}}">
    <div class="tooltip1">
      <p>{{tweet.user_name}}</p>
      <div class="description1">{{tweet.user_description}} </div>
    </div>
    {% if tweet.in_reply_to_text_id %}<p><a href="#{{tweet.in_reply_to_text_id}}">Re:{{tweet.in_reply_to_user_name}}</a></p>{% endif %}
    <p>{{tweet.text}}</p>
    <p class="add-time">{{tweet.created_at}}</p>
</div>
{% endfor %}
</body>
</html>
SNS\mysite\polls\templates\user\user.html
<!DOCTYPE html>
{% load static %}
<html>
<head>
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <meta charset="UTF-8">
  <title>user.html</title>
  <link rel="stylesheet" href="{% static 'style1.css' %}">
  <script type="text/javascript">
    function ShowLength1( str ) {
      document.getElementById("inputlength1").innerHTML = str.length + "文字";
    }    
    function ShowLength2( str ) {
      document.getElementById("inputlength2").innerHTML = str.length + "文字";
    }
  </script>
</head>
<body>
  <h1>例のSNS</h1>
    <div class="box27" id="link">
      <p><a href="../">つぶやく</a></p>
    </div>
      <form action="" method="post" class="box27">
      {% csrf_token %}
      <fieldset>
        <legend><h1>ユーザー登録</h1></legend>
        {% if error_message %}<p><strong>{{ error_message }}</strong></p>{% endif %}
        <label id="inputlength1">名前 30字まで</label><br>
        <input type="text" id="add-user" name="name" cols="60" maxlength="30" onkeyup="ShowLength1(value);">
        <label id="inputlength2">自己紹介 300字まで</label><br>
        <textarea id="add-user" name="description" rows="5" cols="60" maxlength="300" onkeyup="ShowLength2(value);"></textarea>
      </fieldset>
      <input type="submit" value="囁き 祈り 詠唱 念じよ!">
    </form>
</body>
</html>

SNS\mysite\polls\static

要フォルダ作成

SNS\mysite\polls\static\style1.css
/*https://kokiblog.com/2019/09/12/django_css/*/
/*https://saruwakakun.com/html-css/reference/box*/
body {
    background-color: #B2EBF2;
    font-family: sans-serif;
  }
h1{
  width: 80%;
  margin: 0 auto;
  padding: 0.5em 1em;
  max-width: 500px;   
} 
.box27 {
  width: 80%;
  position: relative;
  margin: 2em auto;
  padding: 0.5em 1em;
  border: solid 3px #62c1ce;
  max-width: 500px;
}
.box27 .box-title {
  position: absolute;
  display: inline-block;
  top: -27px;
  left: -3px;
  padding: 0 9px;
  height: 25px;
  line-height: 25px;
  font-size: 17px;
  background: #62c1ce;
  color: #ffffff;
  font-weight: bold;
  border-radius: 5px 5px 0 0;
}
.box27 p {
  margin: 0; 
  padding: 0;
}
.add-time {
  text-align : right;
}
/*https://www.jungleocean.com/programming/190308tooltip-css*/
.tooltip1{
  position: absolute;
  display: inline-block;
  top: -27px;
  left: -3px;
  padding: 0 9px;
  height: 25px;
  line-height: 25px;
  font-size: 17px;
  background: #62c1ce;
  color: #ffffff;
  font-weight: bold;
  border-radius: 5px 5px 0 0;
  
  cursor: pointer;
  display: inline-block;
}

.tooltip1 p{
  margin:0;
  padding:0;
}
.description1 {
  display: none;
  position: absolute;
  padding: 10px;
  font-size: 12px;
  line-height: 1.6em;
  color: #fff;
  border-radius: 5px;
  background: #000;
  width: 200px;
}
.description1:before {
  content: "";
  position: absolute;
  top: 0%;
  right: 95%;
  border: 15px solid transparent;
  border-top: 15px solid #000;
  margin-left: -15px;
  transform: rotateZ(90deg);
}
.tooltip1:hover .description1{
  display: inline-block;
  top: 0px;
  left: 80px;
}

実行手順

VisualStudioCodeのターミナルから下記コマンド実行

C:\Users\user\Documents\SNS\mysite> python manage.py makemigrations polls
C:\Users\user\Documents\SNS\mysite>  python manage.py migrate
C:\Users\user\Documents\SNS\mysite> python manage.py runserver

Watching for file changes with StatReloader
Performing system checks...

System check identified no issues (0 silenced).
July 23, 2021 - 21:20:12
Django version 3.2.5, using settings 'mysite.settings'
Starting development server at http://127.0.0.1:8000/
Quit the server with CTRL-BREAK.

みたいなメッセージが表示されたらローカルサーバー立ち上がってるのでブラウザで
http://localhost:8000/polls/
にアクセス。重い。
終了するときはターミナルでCtrl+cするとサーバーが終了します。


・・・うん、ごめん、何もわかってない・・・
まだリプライを送ることはできない。

例のSNSのリーダー

f:id:elve:20210723081116p:plain
例のSNS
snack.elve.club

Django使うよ。設定してね。

結果


ユーザー名にマウスカーソル当てるとユーザーの自己紹介が出るヨ!

mysite\polls\models.py

pollsが何なのかは知らない。サンプル通りにやったらできたフォルダなのだ・・・。

from django.db import models

# Create your models here.
class USERS(models.Model):
    id = models.CharField(primary_key=True,max_length=40)
    created_at = models.DateTimeField()
    updated_at = models.DateTimeField()
    user_id = models.CharField(max_length=40)
    description = models.CharField(max_length=300)
    name = models.CharField(max_length=40)


class TWEETS(models.Model):
    id = models.CharField(primary_key=True,max_length=40)
    created_at = models.DateTimeField()
    updated_at = models.DateTimeField()
    user_id= models.CharField(max_length=40)
    in_reply_to_text_id= models.CharField(max_length=40)
    in_reply_to_user_id= models.CharField(max_length=40)
    text= models.CharField(max_length=200)
    user_name = models.CharField(max_length=30,null=True)
    user_description =  models.CharField(max_length=300,null=True)

mysite\polls\views.py

from django.shortcuts import render
import requests
from polls.models import USERS,TWEETS
import datetime


def get_username(my_user_id):
    try:
        user = USERS.objects.get(user_id = my_user_id)
        username=user.name
        userdescription=user.description
    except USERS.DoesNotExist:
        username = my_user_id
        userdescription=""
    return {'username':username,'userdescription':userdescription}
    
def index(request):
    url = "https://versatileapi.herokuapp.com/api/user/all"
    users = requests.get(url).json()
    USERS.objects.all().delete()
    for user in users:
        USERS.objects.create(
            id = user['id'],
            created_at = datetime.datetime.fromisoformat(user['_created_at']) ,
            updated_at = datetime.datetime.fromisoformat(user['_updated_at']) ,
            user_id = user['_user_id'],
            description = user['description'],
            name = user['name'])
    url = "https://versatileapi.herokuapp.com/api/text/all?$orderby=_created_at desc&$limit=20"#全部取得すると重いので・・・

    tweets = requests.get(url).json()
    TWEETS.objects.all().delete()
    for tweet in tweets:
        Uid = tweet['_user_id']
        my_user = get_username(Uid)
        TWEETS.objects.create(
            id = tweet['id'],
            created_at = datetime.datetime.fromisoformat(tweet['_created_at']) ,
            updated_at = datetime.datetime.fromisoformat(tweet['_updated_at']) ,
            user_id = Uid,
            in_reply_to_text_id = tweet['in_reply_to_text_id'] if 'in_reply_to_text_id' in tweet  else "",
            in_reply_to_user_id = tweet['in_reply_to_user_id'] if 'in_reply_to_user_id' in tweet  else "",
            text = tweet['text'],
            user_name = my_user['username'],
            user_description= my_user['userdescription'])
    TWEETS.objects.order_by('created_at').reverse()
    output = {'tweets': TWEETS.objects.all()}
    return render(request, 'polls/index.html',output)

mysite\mysite\settings.pyに追記

# https://kokiblog.com/2019/09/12/django_css/
# https://blog.fantom.co.jp/2021/01/23/name-os-is-not-defined/
import os
STATICFILES_DIRS = [
    os.path.join(BASE_DIR, "static"),
]

mysite\polls\static\style1.css

/*https://kokiblog.com/2019/09/12/django_css/*/
/*https://saruwakakun.com/html-css/reference/box*/
body {
    background-color: #B2EBF2;
    font-family: sans-serif;
  }
h1{
  width: 80%;
  margin: 0 auto;
  padding: 0.5em 1em;
  max-width: 500px;   
} 
.box27 {
  width: 80%;
  position: relative;
  margin: 2em auto;
  padding: 0.5em 1em;
  border: solid 3px #62c1ce;
  max-width: 500px;
}
.box27 .box-title {
  position: absolute;
  display: inline-block;
  top: -27px;
  left: -3px;
  padding: 0 9px;
  height: 25px;
  line-height: 25px;
  font-size: 17px;
  background: #62c1ce;
  color: #ffffff;
  font-weight: bold;
  border-radius: 5px 5px 0 0;
}
.box27 p {
  margin: 0; 
  padding: 0;
}
.add-time {
  text-align : right;
}
/*https://www.jungleocean.com/programming/190308tooltip-css*/
.tooltip1{
  position: absolute;
  display: inline-block;
  top: -27px;
  left: -3px;
  padding: 0 9px;
  height: 25px;
  line-height: 25px;
  font-size: 17px;
  background: #62c1ce;
  color: #ffffff;
  font-weight: bold;
  border-radius: 5px 5px 0 0;
  
  cursor: pointer;
  display: inline-block;
}

.tooltip1 p{
  margin:0;
  padding:0;
}
.description1 {
  display: none;
  position: absolute;
  padding: 10px;
  font-size: 12px;
  line-height: 1.6em;
  color: #fff;
  border-radius: 5px;
  background: #000;
  width: 200px;
}
.description1:before {
  content: "";
  position: absolute;
  top: 0%;
  right: 95%;
  border: 15px solid transparent;
  border-top: 15px solid #000;
  margin-left: -15px;
  transform: rotateZ(90deg);
}
.tooltip1:hover .description1{
  display: inline-block;
  top: 0px;
  left: 80px;
}

mysite\polls\templates\polls\index.html

<!DOCTYPE html>
<!--https://kokiblog.com/2019/09/12/django_css/-->
{% load static %}
<html>
<head>
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <meta charset="UTF-8">
  <title>index.html</title>
  <link rel="stylesheet" href="{% static 'style1.css' %}">
</head>
<body>
  <h1>test</h1>


{% for tweet in tweets %}

  <div class="box27" id="{{tweet.user_id}}">
    <div class="tooltip1">
      <p>{{tweet.user_name}}</p>
      <div class="description1">{{tweet.user_description}} </div>
    </div>
    <p>{{tweet.text}}</p>
    <p class="add-time">{{tweet.created_at}}</p>
</div>
{% endfor %}
</body>
</html>

ニックネームを設定したよ

サイドバーのプロフィール表示がちょっと変わったのにお気づきでしょうか!?

f:id:elve:20210723074258p:plainf:id:elve:20210723074301p:plain

そうです! ニックネームを設定したのです(笑)
今まで人のブログのプロフィール欄の「id:~」をコピーすればIDコールができるので便利だと思っていたのですが、ふと見ると自分のところにない!! なぜ!? と考えた結果、ニックネーム設定となりました。
お気軽にIDコールしてください。一緒に混乱しましょう!!←

性欲に負けた

f:id:elve:20210723071608p:plain
同棲生活終了などと言っておりましたが、2日間で3回ハメたらなんか仲直りっぽい空気になった(爆)

休日の朝からすまん。すまんって。すまんこがばがば(久しぶりw)
私は週に2回位はセックスしたいわけよ。

いやまぁ、聞いてくれって。
7/8くらいからセックスしてなかったのよ。生理だったし。
その後、同居人とガンガン関係が悪くなって、破局を迎えたわけですよ。
最小限度の会話すらままならない嫌な空気で生活しておりました。

もうね、セックスしたいわけよ。誰でも良かったのよ。

でもこの後、駄目よ、襲うなんてポリコレ棒突っ込まれちゃうわ! と思ってオナニーして耐えたのよ。*1
よーし、パパ4連休でオトコ捕まえちゃうぞ~とか思ってたわけ。そう、ペアーズでね。←懲りないw

私は和室にベッドおいてそこで寝てて、カズは洋室に布団敷いて寝てるの。洋室にしかエアコン無いの。
んで悶々なりに耐えて寝ようと思ったその時に、和室と洋室の間の戸が開きました。
多分カズが私が暑いだろうからって開けてくれたのね・・・。

ん~もぅらめぇ~(昭和)←平成だろ?

おもむろに起き上がり、ビビってるカズの横に滑り込んだね。
あとはお察しよ!! ちょろいんだよ!! 俺は!!!(逆ギレ)

カズ「エルベ大好き」
私「私はカズさん嫌いだなぁ」
カズ「え、誰でもいいってこと?」
私「誰でもいいけど面倒なんだよ!! 同居してる元彼がいます、って状態で次探すのが!!! 早く出ていってくれよ!!!」
カズ「・・・はい」

はぁ~性欲以外何一つ解決してねぇ~(絶望)
お家の中の空気がピリピリしなくなったので良しとしますか(´;ω;`)

*1:結局突っ込んでるw

そんな私、一生知らなくてよかった

f:id:elve:20210723064625p:plain

いじめ炎上の小山田圭吾 絵に描いた「因果応報」 続報で〝傷口〟悪化の可能性(東スポWeb) - Yahoo!ニュース

因果応報(ニチャァ) ってなってる人だって、そうなりたかったわけじゃないからねぇ。みんなで幸せになりたかった人生だった

2021/07/18 10:38

因果応報(ニチャァ) ってなってる人だって、そうなりたかったわけじゃないからねぇ。みんなで幸せになりたかった人生だった - elve のブックマーク / はてなブックマーク

そんな大したことじゃないんだけど思い出したのでメモ。

昔、素敵なブロガーさん(女性、以下A)と知り合った。友達だと思っていた。
Aさんが海外に行ってもうすぐ帰ってくる、といえば帰国オフを企画しドタキャンされた。
Aさんが忘年会やりたい! って言ってきたので忘年会オフを企画しドタキャンされた。

Aさんが男性ブロガーとゴタゴタして、その人にリベンジポルノみたいなことされた記事が未だにInternet Archiveに記事が残っている。

Aさんがもし今なにか大きな表舞台に出る仕事を得て、そしてInternet Archiveの記事が原因でその仕事を放棄することになったら、と考えると「因果応報(ニチャァ)」ってなる自分がいるんだよね。

Aさんは今、裏舞台でケツ出してて、それはそれで「そんなAさん」見たくなかった自分がいるんだけどさ。
ムカつくくらいに成功*1してくれたらなぁ。
あぁ、ワタクシが踏みにじられたのはあの人のあの栄光のためだったのだね
きっと他にもたくさん踏みにじらないと成功できなかったのだね
と納得できたかもなぁ。ソレは幸せだったかもしれない。

つらいなぁ。
自分で幸せになるしかないだけの話だけどね。

*1:何をもって成功とするかは未定義なんだけどさw