最新の投稿

django-otp 二要素認証
カテゴリー:django 作成日:2025年1月26日21:58

google Authenticator(スマホアプリ)とdjango認証

すでに構築済みに二要素認証を追加する簡単な方法

(venv)$ pip install django-otp qrcode

setting.py に追加

INSTALLED_APPS = (

    ...

    'django_otp',
    'django_otp.plugins.otp_totp',
    'django_otp.plugins.otp_static',

    ...


)

MIDDLEWARE = (
    ...
    'django_otp.middleware.OTPMiddleware',
    ...
)

migrateの実行

(venv)$ python manage.py migrate

superuserを作っていなければ作る

(venv)$ python manage.py createsuperuser

user:
email:
password:
確認用password:
を入力

この跡 adminを実行する

(venv)$ python manage.py runserver

localhost:8000/adminを実行



localhost:8000/adminを実行し
左図のようにTOTP Devices +追加で
User:枠に ユーザ名を入れ右の検索ボタンを押す
ブラウザーが開くので登録したadminユーザを選択して日付、時刻など入力後保存する。




次にqrcodeを表示させる


赤枠のqrcodeをクリック




qrcodeが表示される

google Authenticator(スマホアプリ)に追加する


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 django.views.generic.base import TemplateView
from django_otp.admin import OTPAdminSite # 追加

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

]

# admin でdjango-otp
admin.site.__class__ = OTPAdminSite # 追加

この設定後adminでのログイン画面

OTP Token枠が表示される
ここにはスマホのgoogle Authenticatorの6文字を入力する。



ここではincludeした blog.urls.pyにloginを追加

from django.urls import path
from . import views
#from django.contrib.auth import views as auth_views
from django.contrib.auth.views import LoginView
from django_otp.forms import OTPAuthenticationForm


app_name = 'blog'

urlpatterns = [
    path('', views.PostList.as_view(), name='post_index'),
    path('login/', LoginView.as_view(authentication_form=OTPAuthenticationForm,template_name='login.html'), name='login'),
 ]

最後にtemplates/ligin.htmlを作成
{% load tailwind_filters %}は pip install django-tailwindを使ってるため

{% extends "base.html" %}
{% load tailwind_filters %}

{% block title %}ログイン | {{ block.super }}{% endblock %}

{% block content  %}


<form action="." method="POST" class="max-w-sm mx-auto text-sm font-medium">
    {% csrf_token %}
    <div class="form-row"> {{ form.username.errors }}{{ form.username.label_tag }}{{ form.username }} </div>
    <div class="form-row"> {{ form.password.errors }}{{ form.password.label_tag }}{{ form.password }} </div>
    {% if form.get_user %}
    <div class="form-row"> {{ form.otp_device.errors }}{{ form.otp_device.label_tag }}{{ form.otp_device }} </div>
    {% endif %}
    <div class="form-row"> {{ form.otp_token.errors }}{{ form.otp_token.label_tag }}{{ form.otp_token }} </div>
    <div class="submit-row">
        <input type="submit" value="ログイン" class="bg-blue-500 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded"/>

    </div>
</form>
{% endblock content  %}

これによりlogin画面も OTP Tokenが追加表示される。

login画面も OTP Tokenが追加表示される。



LVM挑戦
カテゴリー:BIOS等 作成日:2024年11月28日23:05

ProxmoxでLVM作成+結合の練習を行う

後日に参照しても分かるようになるべく楽して(コマンド少なく)やりたい。

xubuntu24.04 LTS isoのLiveモードを起動してインスールを行う


全容を簡単に説明する

xubuntu24.04.iso をdvd又はuseにつくる
最初1台のssdにLVM機能を使ってインストール
インストールを終了後2台目を追加
xubuntu24.04 cdかusbで再度起動し
gpartedを使って追加した2台目のssdをlvm2 pvにてフォーマット
PV(Phisical Volume)
VG(Volume Group)
LV(Logical Volume)
上記コマンドで結合して2台で ( / )領域を共有する

それでも容量がたりない場合同様の要領で追加可能

インストール 1


 日本語の選択をして
 次をクリック



インストール 2


 日本語キーボードの選択
 枠の中でキーの試し打ちをして
 よければ 次をクリック


インストール 3


 対話式インストールを選択して次をクリック


インストール 4


 Minimalを選ぶと基本的なものをインストール
 最初はDesktopを選択する方が良いと思う(後から削除する事も可能)
 ここではディスク容量が少ないのでMinimalを選択した。
 次をクリック


インストール 5


 ディスクを削除して Xubuntu をインストールにチェックをいれ
 高度な機能...をクリック


インストール 6


 LVMを使用 にチェックする




インストールを完了して2台目のssdを追加しインストールに使ったcdかusbで再起動後 gparted を開く


 インストールを終了したら
 240gbのssdを取り付けて
 再起動してもう一度 Xubuntu24.04 LTS のISOをLIVEモード起動して
 メニュー ー> システム ー> gpartedを選択して確認する


240g ssdの設定 1


 /dev/sdbを選択し
 メニュー ー> Device ー> Create Partition Table 選択


240g ssdの設定 2


 BiosでUEFI boisに設定しているので gptを選択
 もしlegacy biosなら msdosを選択する


240g ssdの設定 3


 gptを選択した。


240g ssdの設定 4


 メニュー Partition ー> NewでPartitionを作る


240g ssdの設定 5


 すべての Partitionを ext4 に割り当てる


240g ssdの設定 6


 その後作成した New Partition #1を選択し 
 メニューの Partition ー> Format to ー>lvm2 pvを選択する


240g ssdの設定 7


 lvm2 pvになっている事を確認


240g ssdの設定 8

 メニューの Apply アイコンで設定を反映する。



240g ssdの設定 9


 左端が少し切れてしまったがインストール後に
 240Gssd を追加しLiVE usbでGpartedで設定したばかりの
 rootになって コマンド lsblkを叩いたところです。 
 sda 64G
  sda3 lvmになっているのがわかる
 sdb 240G


240g ssdの設定 10


 ここでは sdb1も設定されている


240g ssdの設定 11


 pvscan
 /dev/sda3 VG ubuntu-vg lvm2
 /dev/sdb1       lvm2
 Total: で容量が まだ 62.00 Gで結合がされていないのがわかる


240g ssdの設定 12


 pvscan で VGの名前が ubuntu-vg だと解り
 vgextend ubuntu-vg /dev/sdb1 ubuntu-vgに結びつけている。


240g ssdの設定 13


 vgdisplay -v
 LV Name  ubuntu-lv
 VG Name ubuntu-vg
 など確かめる


240g ssdの設定 14


 lvextend -l +100%FREE /dev/ubuntu-vg/ubuntu-lvで ubuntu-lvに結びつけている。


240g ssdの設定 15


 resize2fs /dev/ubuntu-vg/ubuntu-lvでフォーマットするつもりだったが
 Please 'e2fsck -f /dev/ubuntu-vg/ubuntu-lv' firstと怒られたので
 e2fsck -f /dev/ubuntu-vg/ubuntu-lv 実行後
 resize2fs /dev/ubuntu-vg/ubuntu-lv とした。

 df -h
 ubuntu-lv 301.99gと表示されているが
 いつもの df -hの表示とは少し違うような?


240g ssdの設定 16


 再起動してインストールした xubuntu24.04から df -hを実行
 いつもの見慣れた df -h 
 /dev/mapper/ubuntu-vg/ubuntu-lv 297G となり成功したようだ。



mbrとgpt
カテゴリー:BIOS等 作成日:2024年11月28日21:25

古すぎるPC

私のつかっているPCはあまりに古い
dell T350, T550, T750, (全部で9台ある)
BIOSの設定にUEFI等見当たらないので2TBまでしかシステムを起動不可能という事はなんとなく
知ってはいたのだが
windows 7 -> windows10 もうそろそろサポート終了かな
windows11はuefiでないとアップデートできなくなると誰が言ったか知らないが気になる。
そもそも最近はもっぱら xubuntuを使っていたので、、、
どうしようか
もちろん古いPCは速度も遅いなので HDD->SSDへ変更するとだいぶましになった
アマゾンで少し又少しと買った結果 240Gb(3個),480から500Gb(4個),1TB(5個),2TB(2個)
最近 xubuntu24.04 LTS に変更ついでに240Gb( / )+500Gb( /home )構成でインストール完了した。


これはもったいない

/dev/sda1 198Gも使われていない

何とか198Gを/homeで使う方法はないか

調べた結果 LVMで何とかなるらしいので又挑戦してみよう



django-blog-2
カテゴリー:django 作成日:2024年6月13日12:29

djangoでBlog その2

今回(djangoでBlog その1の続き)はdjango-breezeを使って

djnago + inertia.js + react + tailwind.css + viteをubuntu22.04LTSに簡単に構築する方法

完成するとこんな感じです

django-breezeを使えるようにする

django-breeze-githubサイト

mkdir djb-react && cd djb-react
pyenv local 3.8.10

nodenv local 18.16.1

python -m venv venv
source venv/bin/activate

pipを最新版にする
(venv) pip install --upgrade pip
(venv) pip install django-breeze

(venv) django-breeze startproject conf . //「.」を忘れないように

(venv) django-breeze startapp app


react 又は vue3が選択可能のようです

今回はreactを選択

(venv) django-breeze create-app react 
vueを選択する場合は
(venv) django-breeze create-app vue3
とします

conf/settings.pyに以下設定

INSTALLED_APPS = [
  #..............
  'django_breeze',
  'app'
  #..............
]

LANGUAGE_CODE = 'ja'

TIME_ZONE = 'Asia/Tokyo'

USE_I18N = True

USE_TZ = True

# axios 設定追加 今回はaxiosは使わないが一応設定しとく

CSRF_HEADER_NAME = 'HTTP_X_XSRF_TOKEN'
CSRF_COOKIE_NAME = 'XSRF-TOKEN'


npm install も忘れずに行ってください

ここまででほぼ設定まで完了しています


src/main.jsx ここにはdjangoとreactをinetertia.jsを使って連結する内容が書かれています。

src/index.cssにはtailwind cssが書かれています。

@tailwind base;
@tailwind components;
@tailwind utilities;



ただreactでimportする時src以下を@/で置き換える為 vite.config.jsに以下を追加

resolve: {
    resolve: {
      extensions: [".js", ".jsx", ".json"],
    },
  // ここから
    alias: {
      '@': resolve(__dirname, './src')
    },
 // ここまで追加
},


/src/Layout/MyLayoutを
import MyLayout from '@/Layout/MyLayout';
とできます。
階層が深くなった時にも '../../MyLayout'いや'../../../MyLayout'だったかな?
と悩まずにすみます。

後tailwindは多機能な感じで良いのですが少し楽をしたいのでflowbite flowbite-reactを入れます

npm install flowbite flowbite-react

tailwind.config.jsをflowbite対応に書き換えます

/** @type {import('tailwindcss').Config} */
export default {
  content: [
    "./src/index.html",
    "./src/**/*.{js,ts,jsx,tsx}",
    'node_modules/flowbite-react/**/*.{js,jsx,ts,tsx}',
    'node_modules/flowbite/**/*.{js,jsx,ts,tsx}',
  ],
  theme: {
    extend: {},
  },
  plugins: [
    /** forms, **/
    require('flowbite/plugin'),
  ],
};

それとreactでiconを使いたいので lucide-react 日付を日本語で表示したいので momentをインストール

npm install moment lucide-react

djangoには marshmallowをインストール
databaseをjsonへ変換したりvalidation機能もあります

(venv)pip install marshmallow



1.データを作ります app/models.py

from django.db import models
from django.core import validators
from django.utils.timezone import now

class Item(models.Model):

    SEX_CHOICES = (
        (1, '男性'),
        (2, '女性'),
    )

    name = models.CharField(
        verbose_name='名前',
        max_length=200,
    )
    age = models.IntegerField(
        verbose_name='年齢',
        validators=[validators.MinValueValidator(1)],
        blank=True
    )
    sex = models.IntegerField(
        verbose_name='性別',
        choices=SEX_CHOICES,
        default=1
    )
    memo = models.TextField(
        verbose_name='備考',
        max_length=300,
        blank=True
    )
    created_at = models.DateTimeField(
        verbose_name='登録日',
        default=now
    )

    # 管理サイト上の表示設定
    def __str__(self):
        return self.name

    class Meta:
        verbose_name = 'アイテム'
        verbose_name_plural = 'アイテム'

ここで気をつける事は

from django.utils.timezone import now

created_at = models.DateTimeField(
       verbose_name='登録日',
        default=now
)



登録日は now関数を使う事です auto_now_add=Trueauto_now=True にすると後で日付を書き換える事ができないからです。

2. djangoに登録します adminのユーザとパスワードも作成します

(venv)python manage.py makemigrations
(Venv)python manage.py migrate

## admin User, Passwordを作る
(venv)python manage.py createsuperuser エンターキーを叩くとUser,Email,passwordを聞いてきます。
例:
User :demo
Email: demo@email.com
Password: password!!11AA
Password確認: password!!11AA
Passwordは先頭がアルファベットで大文字小文字を各1個以上数値も含ませ8文字以上との制約があります。 

3.conf/urls.pyを修正します

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

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

4.app/urls.pyを作成して編集します

from django.urls import path

from . import views

app_name = 'app'

urlpatterns = [
    path("", views.index, name="index"),
    path("create/", views.create, name="create"),
    path("store/", views.store, name="store"),
    path("edit/<int:id>", views.edit, name="edit"),
    path("update/<int:id>", views.update, name="update"),
    path("delete/<int:id>", views.delete, name="delete"),
    path("show/<int:id>", views.show, name="show"),
]

5.続いて app/views.pyを編集していきます

from django.shortcuts import redirect
from inertia import render, share
from .models import Item
from .serializers import ItemSchema  # <-serializers.pyこのあと作ります
from marshmallow import ValidationError

def index(request):
  obj = Item.objects.order_by('-created_at')
  # auth_bool = request.user.is_superuser
  return render(request, 'Items/Index', props={
    'items': obj,
  })

def create(request):
  return render(request, 'Items/Create', {})

def show(request, id):
    obj = Item.objects.get(id=id)
    return render(request, 'Items/Show', props={'item': obj})

def store(request):
  if request.method == 'POST':
    try:
      schema = ItemSchema()
      data = schema.loads(request.body)
      obj = Item.objects.create(**data)
    except ValidationError as err:
      share(request, error="Exists errors on form")
      share(request, error=err.messages)
    else:
      share(request, success=f"Item {obj.name} created")
      return redirect("app:index")

def edit(request, id):
  obj = Item.objects.get(id=id)
  return render(request, 'Items/Edit', props={'item': obj})

def update(request, id):
  obj = Item.objects.get(id=id)
  schema = ItemSchema()
  param = schema.loads(request.body)
  obj.name = param["name"]
  obj.age = param["age"]
  obj.sex = param["sex"]
  obj.memo = param["memo"]
  obj.save()
  #obj.objects.filter(id=id).update(**data)
  share(request, success=f"Item {obj.name} update")
  return redirect("app:index")

def delete(request, id):
  obj = Item.objects.get(id=id)
  obj.delete()
  share(request, success="Item Deleted")
  return redirect("app:index")

6. app/serializers.pyを作成し編集します

from marshmallow import Schema, fields, validate

class ItemSchema(Schema):
    id = fields.Int()
    name = fields.Str(validate=validate.Length(min=1))
    age = fields.Int()
    sex = fields.Int()
    memo = fields.Str()
    created_at = fields.DateTime()



7. src/pagesにItemsフォルダーをつくりItems/Index.jsxを作ります

mkdir -p src/pages/Items
touch src/pages/Items/Index.jsx
touch src/pages/Items/Create.jsx
touch src/pages/Items/Edit.jsx
touch src/pages/Items/Show.jsx



8. /src/pages/Items/Index.jsxを編集します

import { useState, useEffect } from 'react';
import { router, Link } from '@inertiajs/react';
import MyLayout from '@/Layout/MyLayout';
import moment from 'moment';


export default function Index({items}){

    const [prePage] = useState(6)

    const [totalPage] = useState(items.length)

    const [currentPage, setCurrentPage] = useState(1)

    const nextPage = () => {
        if (currentPage !== Math.ceil(items.length / prePage)) {
            setCurrentPage(currentPage+1)
        }
    }

    const prevPage = () => {
        if(currentPage !== 1){
            setCurrentPage(currentPage-1)
        }
    }

    const gotoPage = (page) => {
        setCurrentPage(page)
    }

    const [lcount] = useState(Math.ceil(totalPage / prePage))

    const pageNumbers = [];
    for (let i=1; i<Math.ceil(totalPage/prePage)+1; i++){
        pageNumbers.push(i);
    }

    function deletePost( id ) {
        if (confirm(`No.${id}を削除してよろしいですか`)) {
            router.delete(`/delete/${id}`);
        }
    }

    function dateFormat(data) {
        return  moment(data).format('YYYY年MM月DD日 HH:mm')
    }

    function get_sex_display(sex) { return (sex === 1) ? '男性' : '女性' }

    return (
        <>
        <MyLayout>
            <div className="flex flex-wrap columns-2 md:columns-3 lg:columns-4">
            { items.slice((currentPage -1) * prePage, currentPage * prePage).map( (item) => (
            <div key={item.id}   className="mt-4 max-w-sm rounded border-gray-400 overflow-hidden shadow-xl">
                <div className="p-4 w-72">
                <h2 className="mb-2 text-2xl font-bold tracking-tight text-gray-900 dark:text-white">
                    <p>{item.name}</p>
                </h2>
                <p  className="font-normal text-gray-700 dark:text-gray-400">
                        年齢 {item.age} 歳
                </p>
                <p className="font-normal text-gray-700 dark:text-gray-400">
                    性別 { get_sex_display(item.sex) }
                </p>
                <p className="font-normal text-gray-700 dark:text-gray-400">
                    備考 { item.memo }
                </p>
                <p className="font-normal text-gray-700 dark:text-gray-400">
                    登録日 {dateFormat(item.created_at)}
                </p>
                <div className="px-6 pt-4 pb-2">
                    <Link href={`/show/${item.id}`} className="inline-block bg-gray-200 rounded-full px-3 py-1 text-sm font-semibold text-gray-700 mr-2 mb-2">
                            確認
                    </Link>
                    <Link href={`/edit/${item.id}`} className="inline-block bg-gray-200 rounded-full px-3 py-1 text-sm font-semibold text-gray-700 mr-2 mb-2">
                            編集
                    </Link>
                    <button onClick={() => deletePost(item.id)} className="inline-block bg-gray-200 rounded-full px-3 py-1 text-sm font-semibold text-red-700 mr-2 mb-2">
                            削除
                    </button>
               </div>
            </div>
            </div>
            ))}
            </div>
            <br />
            <nav aria-label="Page navigation example">
            <ul className="flex items-center  -space-x-px h-8 text-sm">
                <li className="flex">
                  { currentPage > 1 ? (
                     <button onClick={prevPage} className="flex items-center justify-center px-3 h-8 ms-0 leading-tight text-gray-500 bg-white border border-e-0 border-gray-300 rounded-s-lg hover:bg-gray-100 hover:text-gray-700 dark:bg-gray-800 dark:border-gray-700 dark:text-gray-400 dark:hover:bg-gray-700 dark:hover:text-white">
                      <span className="sr-only">Previous</span>
                      <svg className="w-2.5 h-2.5 rtl:rotate-180" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 6 10">
                       <path stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 1 1 5l4 4"/>
                     </svg>
                     </button>
                       ) : (<p></p>)
                    }
                </li>
                <li className="flex">
                        {pageNumbers.map((number) => (
                            <button onClick={() => gotoPage(number)}
                            className={
                                currentPage === number
                                ? "z-10 flex items-center justify-center px-3 h-8 leading-tight text-blue-600 border border-blue-300 bg-blue-50 hover:bg-blue-100 hover:text-blue-700 dark:border-gray-700 dark:bg-gray-700 dark:text-white"
                                : "flex items-center justify-center px-3 h-8 leading-tight text-gray-500 bg-white border border-gray-300 hover:bg-gray-100 hover:text-gray-700 dark:bg-gray-800 dark:border-gray-700 dark:text-gray-400 dark:hover:bg-gray-700 dark:hover:text-white"
                            }
                        >{number}</button>
                        ))}
                </li>
                <li className="flex">
                    { currentPage < lcount ? (
                    <button onClick={nextPage} className="flex items-center justify-center px-3 h-8 leading-tight text-gray-500 bg-white border border-gray-300 rounded-e-lg hover:bg-gray-100 hover:text-gray-700 dark:bg-gray-800 dark:border-gray-700 dark:text-gray-400 dark:hover:bg-gray-700 dark:hover:text-white">
                        <span className="sr-only">Next</span>
                        <svg className="w-2.5 h-2.5 rtl:rotate-180" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 6 10">
                        <path stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="m1 9 4-4-4-4"/>
                        </svg>
                    </button>
                        ) : (<p></p>)
                    }
                </li>
            </ul>
            </nav>
        </MyLayout>
        </>
    )
}

9. src/Layout/MyLayout.jsx作成編集

import React from "react";
import { Navigation, Header } from './index';


export default function MyLayout({children}) {
    return  (
        <>
        <div className="flex flex-col h-screen bg-gray-100">
            <Header />
            <div className="flex flex-grow bg-gray-100">
              <div className="w-2/12">
                <Navigation />
              </div>
              <div className="w-10/12 m-2 bg-gray-100 overflow-y-auto">
               {children}
              </div>
            </div>
        </div>
        </>
    )
}

10. src/Layout/Header.jsx, src/Layout/Navigation.jsx src/Layout/index.jsx作成
src/Layout/Header.jsx

import { Link } from '@inertiajs/react';
import {headerMenus} from '../icons';

export const Header = () => {
    return (
        <div className="h-12 bg-gray-100 text-yellow-900 flex items-center mx-4 pl-3 px-4">
        <ul className="mx4">
            {headerMenus.map((menu, index) => (
                <li className="mb-1 group" key={index}>
                    <Link href={menu.link} className="flex font-semibold items-center py-1 px-4 text-gray-900 hover:bg-red-500 hover:text-gray-100 rounded-md group-[.active]:bg-gray-800 group-[.active]:text-white group-[.selected]:bg-gray-950 group-[.selected]:text-gray-100">
                        <menu.icon  className="mr-1 size-[24px] text-indigo-500"></menu.icon>{menu.label}
                    </Link>
                </li>
            ))}
        </ul>
        </div>
    );
}

src/Layout/Navigation.jsx

import { Link } from '@inertiajs/react';
import { naviMenus } from '../icons';

export const Navigation = () =>{
    return (
        <nav className="bg-gray-100 mx-auto p-4 text-black-600 flex flex-col items-center">
        <ul className="mx4">
            {naviMenus.map((menu, index) => (
                <li className="mb-1 group" key={index}>
                    <Link href={menu.link} className="flex font-semibold items-center py-1 px-4 text-gray-900 hover:bg-gray-950 hover:text-gray-100 rounded-md group-[.active]:bg-gray-800 group-[.active]:text-white group-[.selected]:bg-gray-950 group-[.selected]:text-gray-100">
                        <menu.icon  className="mr-1 size-[24px] text-green-300"></menu.icon>{menu.label}
                    </Link>
                </li>
            ))}
        </ul>
        </nav>
    );
};

src/Layout/index.jsx

export * from './Header';
export * from './Navigation';
export * from './MyLayout';

11. Icon関係のファイルを作成します

mkdir src/icons
touch src/icons/hraderMenus.jsx
touch src/icons/navMenus.jsx
touch src/icons/index.jsx

src/icons/headerMenus.jsx

import {Home} from 'lucide-react';

export const headerMenus = [
    {
        link: '/',
        label: 'ホーム',
        icon: Home,
    },
];

src/icons/naviMenus.jsx

import {Home, Plus} from 'lucide-react';

export const naviMenus = [
    {
        link: '/',
        label: 'ホーム',
        icon: Home,
    },
    {
        link: '/create',
        label: '新規',
        icon: Plus,
    },
]

src/icons/index.jsx

export * from './headerMenus';
export * from './naviMenus';

12. app/admin.py編集します

from django.contrib import admin

# Register your models here.
from .models import Item


@admin.register(Item)
class ItemAdmin(admin.ModelAdmin):

    class Meta:
        verbose_name = 'ユーザ'
        verbose_name_plural = 'ユーザ'

vscode ターミナルで npm run dev
もう一つターミナルを開いて python manage.py runserver
127.0.0.1:8000/adminで10個位サンプルを入れてください。


django-blog-1
カテゴリー:django 作成日:2024年5月24日15:55

djangoでblog その1

djangoでblogを作る方法
条件
マークダウンを使いたい
tailwindcssを使いたい
vueかreactを使いたい
なるべく簡単に作りたい  


まず開発環境

1.ubuntu 22.04LTS or 24.04LTS //proxmox ve 8内で作業する為省略
2.pyenv pythonのバージョンを管理
3.nodenv nodejsのバージョンを管理


pyenv インストール

sudo apt update
sudo apt install build-essential libffi-dev libssl-dev zlib1g-dev liblzma-dev libbz2-dev \
  libreadline-dev libsqlite3-dev libopencv-dev tk-dev git

gitでpyenv clone

git clone https://github.com/pyenv/pyenv.git ~/.pyenv

echo '' >> ~/.bashrc
echo 'export PYENV_ROOT="$HOME/.pyenv"' >> ~/.bashrc
echo 'export PATH="$PYENV_ROOT/bin:$PATH"' >> ~/.bashrc
echo 'eval "$(pyenv init --path)"' >> ~/.bashrc
source ~/.bashrc

pyenv でインスール可能なバージョン

pyenv install --list

pyenv で 3.10.8をインストール

pyenv install 3.10.8
pyenv install 3.7.0

pyenv で現在インストールされているリスト

pyenv versions

pyenv の使うバージョンを全体で指定

pyenv global 3.10.8

pyenv フォルダ別にバージョン指定

cd /home/folder
pyenv local 3.7.0

nodenv インストール

pyenvの使い方によく似ています
git clone https://github.com/nodenv/nodenv.git ~/.nodenv

echo 'export PATH="$HOME/.nodenv/bin:$PATH"' >> ~/.bashrc
echo 'eval "$(nodenv init -)"' >> ~/.bashrc

nodejsバージョン一覧を取得用 node-build インストール

git clone https://github.com/nodenv/node-build.git $(nodenv root)/plugins/node-build

source ~/.bashrc

nodenvでインストールできる一覧

nodenv install --list

nodenv でインストール

nodenv install 18.16.1
nodenv install 16.14.0

nodenv で現在インストールされているリスト

nodenv versions

nodenv の使うバージョンを全体で指定

nodenv global 18.16.1

nodenv フォルダ別にバージョン指定

cd /home/folder
nodenv local 16.14.0
pyenv local 又は nodenv localを指定すると フォルダーに .python-version .node-versionが記録される

.python-versionの中身
3.10.8

.node-versionの中身
16.14.0