最新の投稿
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が追加表示される。
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 となり成功したようだ。
古すぎる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でBlog その1の続き)はdjango-breezeを使って
djnago + inertia.js + react + tailwind.css + viteをubuntu22.04LTSに簡単に構築する方法
完成するとこんな感じです
django-breezeを使えるようにする
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=True やauto_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で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