ホーム 記事一覧 ブック DH週間トピックス 検索 このサイトについて
RSS English
Apache Solrのフィールドがどのようにインデックスされているか確認する方法

Apache Solrのフィールドがどのようにインデックスされているか確認する方法

Apache Solrのフィールドがどのようにインデックスされているか確認する方法のメモです。 Schema APIを使う SolrのSchema APIを使って、特定のフィールドがどのように定義されているかを確認できます。下記は特定のフィールドに対するリクエストの例です。 http://localhost:8983/solr/{core_name}/schema/fields/{field_name} このURLにブラウザからアクセスしたり、curlコマンドなどを使ってGETリクエストを送ると、特定のフィールドに関する情報がJSON形式で返されます。その中にはそのフィールドがどのようにインデックスされているかに関する情報も含まれます。 Solr管理UIを使う Solrが提供している管理UIからもフィールドがどのようにインデックスされているかを確認できます。 Solrの管理UI (http://localhost:8983/solr) をブラウザで開きます。 左側のメニューから「Core Selector」を選択し、該当のコアを選びます。 コアを選択したら、メニューから「Schema Browser」を選択します。 「Schema Browser」ページでフィールド名を選択すれば、そのフィールドがどのようにインデックスされているかに関する詳細情報が表示されます。 この2つの方法で、Solrに格納されているフィールドがどのようにインデックスされているかを確認できます。どちらの方法も、フィールドがどのような型で定義されているか、どのようなオプションが設定されているかなど、フィールドの定義に関する詳細な情報を提供します。

Omeka Classic IIIF Toolkitにデータを一括登録する

Omeka Classic IIIF Toolkitにデータを一括登録する

概要 Omeka Classic IIIF Toolkitにデータを一括登録する方法を説明します。Omeka Classic IIIF Toolkitのセットアップについては、以下を参考にしてください。 また、以下の記事の内容を発展させ、excelデータを入力データとして、より簡便に使用できるようにしたものです。 excelファイルの準備 以下のようなexcelファイルを準備します。 https://github.com/nakamura196/000_tools/blob/main/data/sample.xlsx 「collection」「item」「annotation」の3つのシートを用意します。 collection manifest_uri https://d1fasenpql7fi9.cloudfront.net/v1/manifest/3437686.json item title canvas_uri width height image_url manifest_uri 校異源氏物語. 巻一 [4] https://www.dl.ndl.go.jp/api/iiif/3437686/canvas/4 6890 4706 https://www.dl.ndl.go.jp/api/iiif/3437686/R0000004/full/full/0/default.jpg https://d1fasenpql7fi9.cloudfront.net/v1/manifest/3437686.json 校異源氏物語. 巻一 [4] https://www.dl.ndl.go.jp/api/iiif/3437686/canvas/5 6890 4706 https://www.dl.ndl.go.jp/api/iiif/3437686/R0000005/full/full/0/default.jpg https://d1fasenpql7fi9.cloudfront.net/v1/manifest/3437686.json annotation chars x y w h canvas_uri tag 3125 4898 4008 241 79 https://www.dl.ndl.go.jp/api/iiif/3437686/canvas/4 序 2910 868 147 140 https://www.dl.ndl.go.jp/api/iiif/3437686/canvas/4 913.36 たH 2228 226 586 156 https://www.dl.ndl.go.jp/api/iiif/3437686/canvas/4 或は撮影して、 897 3517 83 434 https://www.dl.ndl.go.jp/api/iiif/3437686/canvas/4 一 810 3528 30 17 https://www.dl.ndl.go.jp/api/iiif/3437686/canvas/4 序 6018 1055 65 65 https://www.dl.ndl.go.jp/api/iiif/3437686/canvas/5 二 6025 3535 49 39 https://www.dl.ndl.go.jp/api/iiif/3437686/canvas/5 殆んどあらゆる現存貴重資料に及び、 5889 707 86 1090 https://www.dl.ndl.go.jp/api/iiif/3437686/canvas/5 一字をも忽にしない細緻な〓究は、 5889 1837 86 1012 https://www.dl.ndl.go.jp/api/iiif/3437686/canvas/5 フイルム等 5501 3614 76 323 https://www.dl.ndl.go.jp/api/iiif/3437686/canvas/5 大島雅太郞氏· 916 3491 89 436 https://www.dl.ndl.go.jp/api/iiif/3437686/canvas/5 序 807 1048 65 61 https://www.dl.ndl.go.jp/api/iiif/3437686/canvas/5 三 815 3517 61 57 https://www.dl.ndl.go.jp/api/iiif/3437686/canvas/5 python 以下のライブラリをインストールします。 ...

Mirador3プラグイン開発: ウインドウをコピーする

Mirador3プラグイン開発: ウインドウをコピーする

概要 Mirador3のプラグインとして、ウインドウをコピーするプラグインを作成しました。 なお本機能は以下のプラグインですでに提供されているものです。 https://github.com/ProjectMirador/mirador-plugin-demos そのため、本プラグインはプラグインの開発手順を学ぶために作成しています。そのような観点で、本プラグインが参考になりましたら幸いです。 画面例は以下です。 ソースコードは以下です。 https://github.com/nakamura196/mirador-copy-window-plugin デモサイトは以下です。 https://nakamura196.github.io/mirador-copy-window-plugin/ 開発メモ 本プラグインの開発にあたり、まず以下のリポジトリをcloneし、変更を加えていきました。 https://github.com/ProjectMirador/mirador-dl-plugin src/index.js まず以下のファイルについて、miradorDownloadをMiradorCopyWindowに書き換えました。 https://github.com/nakamura196/mirador-copy-window-plugin/blob/main/src/index.js src/MiradorCopyWindow.js 以下のファイルが主に編集するファイルです。 https://github.com/nakamura196/mirador-copy-window-plugin/blob/main/src/MiradorCopyWindow.js 本ファイルは、まず以下のファイルの内容をコピーしました。 https://github.com/ProjectMirador/mirador-plugin-demos/blob/master/src/plugins/copy-window.js まず末尾の以下の記述から説明します。 export default { target: 'WindowTopMenu', mode: 'add', component: CopyWindowComponent, mapDispatchToProps: mapDispatchToProps, mapStateToProps: mapStateToProps, } targetとmode targetはコンポーネントを設置する場所を指定します。またmodeはコンポーネントの追加方法を指定します。modeについては、addやwrapという選択肢があるようでした。 以下、targetの値の例です。 WindowTopMenu 各ウインドウ上部のメニューの部分です。 WorkspaceControlPanelButtons ワークスペースのパネル部分です。 AnnotationSettings アノテーションの設定画面です。 最後のAnnotationSettingsおよびmodeにwrapが指定されているプラグインとして、以下のMiradorのアノテーション付与モジュールがありました。 https://github.com/ProjectMirador/mirador-annotations/blob/master/src/plugins/miradorAnnotationPlugin.js mapDispatchToPropsとmapStateToProps これがはじめ理解しづらかった(そしてまだ適切に説明できるほど理解できていない)のですが、propsに渡すdispathとstateを定めた変数を指定します。 dispatchについては、以下の変数を与えてます。 const mapDispatchToProps = (dispatch, { windowId }) => ({ copyWindow: () => dispatch(copyWindowAction(windowId)), }); copyWindowActionの具体的な内容は以下です。既存のwindowを取得して(1)、不要な変数を削除した上でwindowをコピーして(2)、それをaddWindow(3)しています。 const copyWindowAction = (windowId) => (dispatch, getState) => { const window = getState().windows[windowId]; // 1 const cleanedWindow = omit(window, [ 'id', 'companionWindowIds', 'thumbnailNavigationId', ]); // 2 dispatch(mirador.actions.addWindow(cleanedWindow)); // 3 }; stateについては、以下の変数を与えています。以下の例は少し特殊で、stateをすべてpropsに渡す設定となっています。他のプラグインでは、必要な値のみをstateから抽出して、propsに渡しているようでした。 const mapStateToProps = (state) => ({ state: state, }); 実際、本プラグインでは、mapStateToPropsでpropsに渡された値は使用されていないため、この記述はなくてもよいはずです。そのため、以下でもmapStateToPropsの記述は省略しています。 https://github.com/nakamura196/mirador-copy-window-plugin/blob/main/src/MiradorCopyWindow.js component 最後にcomponentです。以下のように、コンポーネントで表示する内容を記述しています。 ...

wikibase.cloudでQuickStatementsを試す

wikibase.cloudでQuickStatementsを試す

概要 wikibase.cloudでQuickStatementsを試してみましたので、その備忘録です。 以下の記事を参考にさせていただきました。 https://qiita.com/higa4/items/10affb47215def42d8e0 追加 上記の記事の通り、csvファイルをインポートしています。 ところが、以下のようなエラーが発生しました。 原因は、独自に立てたwikibaseインスタンスに、必要なプロパティが未登録だったことが原因でした。 Property [[Property:P1814|P1814]] not found WikibaseSyncなどを使って、事前に(特にwikidataと同じIDの)プロパティを登録しておく必要があることがわかりました。 そのため、ラベルに関する情報のみを登録する以下のようなデータを登録してみました。 qid,Lja,Len,Dja,Den,qal1545 ,タイトル,title,""""説明,desc,1 結果、以下のようにデータの新規登録ができました。 更新 次のコマンドで、上記で登録したQ59の更新を試みました。 qid,Lja,Len,Dja,Den,qal1545 Q59,変更後のタイトル,updated title,""""変更後の説明,updated desc,1 結果、以下のように、いずれの値も更新することができました。 まとめ ほんの一例ですが、QuickStatementsを試してみました。APIでの登録例を以下の記事で紹介していますが、CSVによる登録はユーザフレンドリーな機能だと感じました。 他の方の参考になりましたら幸いです。

WikibaseSyncを試す

WikibaseSyncを試す

概要 以下のWikibaseSyncを試す機会がありましたので、その備忘録です。 https://github.com/the-qa-company/WikibaseSync 以下の論文で、上記のツールを知りました。 https://doi.org/10.11517/jsaisigtwo.2022.SWO-056_04 インストール ソースコードや関連ライブラリをインストールします。 !get clone https://github.com/the-qa-company/WikibaseSync cd WikibaseSync !pip install -r requirements.txt Bot Accountの作成 事前に用意したWikibaseにアクセスし、「Special pages」から、「Bot passwords」をクリックします。 以下の画面で、「Bot name」を入力します。 次の画面で、以下の3つにチェックを入れます。 Give him the follwing rights: “High-volume editing”, “Edit existing pages” and “Create, edit, and move pages” 結果、以下のようなメッセージが表示され、パスワードを取得することができます。 The bot password for bot name "WikidataUpdater" of user "Nakamura" was created. The new password to log in with Nakamura@WikidataUpdater is xxxxxxxxxxxxxx. Please record this for future reference. (For old bots which require the login name to be the same as the eventual username, you can also use Nakamura as username and WikidataUpdater@xxxxxxxxxxxxxx as password.) Return to Special:BotPasswords. そして、以下の説明にしたがって、インストールしたソースコードの設定ファイルに、上記のBotに関する情報を入力します。 ...

wikibaseのapiをつかってみる

wikibaseのapiをつかってみる

概要 wikibaseのapiをpythonクライアントから使用する機会がありましたので、その備忘録です。 以下のライプラリを使用しました。 https://wikibase-api.readthedocs.io/en/latest/index.html インストール 以下でインストールします。 !pip install wikibase-api Read 今回は、以下のwikibaseインスタンスに対して処理を行います。 https://nakamura196.wikibase.cloud/ from wikibase_api import Wikibase api_url = "https://nakamura196.wikibase.cloud/w/api.php" wb = Wikibase(api_url=api_url) r = wb.entity.get("Q1") print(r) 上記により、Q1に関する情報を取得することができました。 Create 認証情報の取得 アイテムの作成などを行う際には、以下のどちらかの方法で認証を行う必要がありました。 Authentication using OAuth Authentication with a user account 後者はBot passwordsを作成する方法で、以下の記事でも作成方法を紹介しています。 今回は前者の方法を試します。 「Special pages」の「OAuth consumer registration」を選択します。 「Request a token for a new OAuth 1.0a consumer.」と「Request a token for a new OAuth 2.0 client.」の2つの作成方法がありますが、前者を選択します。 項目を埋めていきます。 今回はテストのため、すべての項目にチェックを入れました。 結果、以下のようなページが表示され、認証情報を取得できます。 実行 .envファイルを作成します。 consumer_key=xxx consumer_secret=yyy access_token=zzz access_secret=aaa load_dotenvを使って認証情報をロードして、設定します。 ...

Dataverseを試す

Dataverseを試す

概要 Dataverseを試す機会がありましたので、その備忘録です。以下のデモ環境を使用します。 https://demo.dataverse.org/ アカウント作成 Sign Upからアカウントを作成します。 Dataverseの作成 Dataverseを作成してみます。 以下のようなDataverseを作成しました。 https://demo.dataverse.org/dataverse/nakamura196 Datasetの作成 Add Dataから、データセットを作成します。 以下が登録画面です。 以下が登録結果の画面です。 URLは以下になっており、自動的に付与されるDOIをシステム内の識別子として利用しているようでした。 https://demo.dataverse.org/dataset.xhtml?persistentId=doi:10.70122/FK2/HBXQPZ Whole Tale Access Datasetボタンのオプションに、Whole Taleというものがありました。 アカウントを作成して、Compute EnvironmentをJupyter Notebookに設定してみます。 Acknowledge allボタンを押します。 結果、以下のようなJupyter Notebookの環境が作成されました。 Pythonを使って、ダウンロードした画像を表示してみます。 上記のように、データセットやソースコードに対する動作確認や検証もシームレスに実行できるようでした。 Widgets 以下の「Thumbnails + Widgets」を押してみます。 以下の「Widgets」タブを表示してみます。 上記のコードを埋め込んでみると、以下に示すように、データセットに関する情報を埋め込み表示することができました。 https://codepen.io/satoru196/pen/NWEMvEV?editors=1000 API Pythonのライブラリを使ってみます。 https://pydataverse.readthedocs.io/en/latest/ ライブラリをインストールします。 !pip install pyDataverse データのダウンロード 以下のページを参考にしました。 https://pydataverse.readthedocs.io/en/latest/user/basic-usage.html#download-and-save-a-dataset-to-disk from pyDataverse.api import NativeApi, DataAccessApi from pyDataverse.models import Dataverse base_url = 'https://demo.dataverse.org' api = NativeApi(base_url) data_api = DataAccessApi(base_url) DOI = "doi:10.70122/FK2/HBXQPZ" dataset = api.get_dataset(DOI) files_list = dataset.json()['data']['latestVersion']['files'] for file in files_list: filename = file["dataFile"]["filename"] file_id = file["dataFile"]["id"] print("File name {}, id {}".format(filename, file_id)) response = data_api.get_datafile(file_id) with open(filename, "wb") as f: f.write(response.content) データセットの作成(demo.dataverse.orgでは権限がありませんでした。) demo.dataverse.orgでは権限がありませんでしたが、実施した内容をメモします。 ...

wikibase.cloudを使ってみる

wikibase.cloudを使ってみる

概要 wikibase.cloudを使ってみる機会がありましたので、その備忘録です。 ドキュメント 以下にマニュアルがありました。 https://www.mediawiki.org/wiki/Wikibase/Wikibase.cloud インスタンスの作成 はじめに独自ドメインを設定してみましたが、うまくいきませんでした。以下、記録だけ残します。以後、独自ドメインを諦めて、nakamura196.wikibase.cloudを使用しています。 失敗 独自のドメインを割り当てられるようでしたので、wikibase.aws.ldas.jpを入力しました。 Route 53で以下のような設定を行いました。 テーマの変更 以下のSet Skinで見た目を変更することができました。 Vector Modern Timeless データを作成してみる デフォルトで作成されるユーザでログインすると、以下の画面に遷移しました。 Satoru Itemを作成してみました。 以下のように作成されました。 プロパティ プロパティnameを作成してみます。 アイテムへのStatementsの追加 作成したプロパティ(P1)を使って、アイテム(Q1)にStatementsを追加してみます。 Query Service クエリサービスも問題なく動作しました。 タイムラインを用いた可視化例です。 #defaultView:Timeline select * where { ?s wikibase:timestamp ?o . } 棒グラフの表示例です。 #defaultView:BarChart select ?name (count(?name) as ?count) where { ?s <https://nakamura196.wikibase.cloud/prop/direct/P1> ?name . } group by ?name ...

onClose propを使用する

onClose propを使用する

MUIのDialogコンポーネントにおいてonBackdropClickを使用したところ、以下の警告が発生しました。 Warning: Failed prop type: The prop `onBackdropClick` of `ForwardRef(Dialog)` is deprecated. Use the onClose prop with the `reason` argument to handle the `backdropClick` events. 警告メッセージは、Dialogコンポーネントの非推奨のprop onBackdropClickに関するものです。これは、このpropがあなたのコードのどこかで使用されているが、もはやサポートされていないか、使用が推奨されていないことを意味します。警告は代わりにonClose propを使用するように提案しています。 これを解決する方法は以下の通りです: 以前は、コードに以下のようなものがあったかもしれません: <Dialog open={isOpen} onBackdropClick={handleBackdropClick} > { /* ダイアログの内容 */ } </Dialog> 警告に従って、これをonClose propを使用するように更新する必要があります: <Dialog open={isOpen} onClose={(event, reason) => { if (reason === 'backdropClick') { handleBackdropClick(); } }} > { /* ダイアログの内容 */ } </Dialog> 上記のコードでは、onClose propは関数を取り、eventとreasonという2つの引数を受け取ります。reasonは’backdropClick’、’escapeKeyDown’、またはundefinedになる可能性があります。reasonが’backdropClick’かどうかをチェックすることで、ユーザーがダイアログボックスの外側をクリックしたときに関数handleBackdropClick()を実行できます。 以上のようにコードを更新すると、警告は表示されなくなりました。 ...

Mirador 3でビューポートが設定した制約を満たすようにズームを行う

Mirador 3でビューポートが設定した制約を満たすようにズームを行う

概要 Mirador 3で特定の領域にズームにするには、以下に記載があるような方法で行います。 https://github.com/ProjectMirador/mirador/wiki/M3---Mirador-3-Frequently-Asked-Questions#q-how-do-i-change-the-view-of-an-image-to-zoom-to-a-certain-area 具体的には以下です。 // Box to zoom to const boxToZoom = { x: 1420, y: 1831, width: 800, height: 1195 }; const zoomCenter = { x: boxToZoom.x + boxToZoom.width / 2, y: boxToZoom.y + boxToZoom.height / 2 }; var action = Mirador.actions.updateViewport(windowId, { x: zoomCenter.x, y: zoomCenter.y, zoom: 1 / boxToZoom.width }); miradorInstance.store.dispatch(action); 内部的にはOpenSeadragonのpanToとzoomToが使用されているようでした。 この時の課題として、zoomToは以下の記事にあるように、constraintsを無視して拡大するようでした。 https://github.com/openseadragon/openseadragon/issues/881 これに対して、以下の記事で示したように、viewer.viewport.applyConstraints();の処理を追加することで、constraintsを守った拡大ができるようになりました。 以下、強引ではありますが、npmでインストールしたMiradorに対して、上記の設定を行う方法を紹介します。 Miradorの編集 以下でMiradorをインストールします。 npm install mirador node_modules以下にmiradorフォルダが作成されます。 その中にある以下のファイルに対して、viewport.applyConstraints();を追加する例を示します。 ... { key: "componentDidUpdate", value: function componentDidUpdate(prevProps, prevState) { var _this$props2 = this.props, viewerConfig = _this$props2.viewerConfig, canvasWorld = _this$props2.canvasWorld; var viewer = this.state.viewer; this.apiRef.current = viewer; if (prevState.viewer === undefined) { if (viewerConfig) { viewer.viewport.panTo(viewerConfig, true); viewer.viewport.zoomTo(viewerConfig.zoom, viewerConfig, true); viewerConfig.degrees !== undefined && viewer.viewport.setRotation(viewerConfig.degrees); viewerConfig.flip !== undefined && viewer.viewport.setFlip(viewerConfig.flip); } this.addAllImageSources(!viewerConfig); return; } if (!this.infoResponsesMatch(prevProps.infoResponses) || !this.nonTiledImagedMatch(prevProps.nonTiledImages)) { viewer.close(); var canvasesChanged = !isEqual(canvasWorld.canvasIds, prevProps.canvasWorld.canvasIds); this.addAllImageSources(canvasesChanged || !viewerConfig); } else if (!isEqual(canvasWorld.layers, prevProps.canvasWorld.layers)) { this.refreshTileProperties(); } else if (viewerConfig && !this.osdUpdating) { var viewport = viewer.viewport; if (viewerConfig.x !== viewport.centerSpringX.target.value || viewerConfig.y !== viewport.centerSpringY.target.value) { viewport.panTo(viewerConfig, false); } if (viewerConfig.zoom !== viewport.zoomSpring.target.value) { viewport.zoomTo(viewerConfig.zoom, viewerConfig, false); viewport.applyConstraints(); // ここを追加 } if (viewerConfig.rotation !== viewport.getRotation()) { viewport.setRotation(viewerConfig.rotation); } if (viewerConfig.flip !== viewport.getFlip()) { viewport.setFlip(viewerConfig.flip); } } } ... 上記の設定により、Mirador.actions.updateViewportでズームした際に、constraintsを守った拡大ができるようになりました。 ...

Monaco EditorでLaTeXをハイライトする

Monaco EditorでLaTeXをハイライトする

概要 Monaco EditorでLaTeXをハイライトする機会がありましたので、備忘録です。 Ace Editorを対象にした以下の記事の続編です。 参考になりましたら幸いです。 画面例 デモサイト https://nakamura196.github.io/ace_latex/monaco/ リポジトリ https://github.com/nakamura196/ace_latex/ ソースコード <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>Monaco Editor Demo</title> <link href="https://cdn.jsdelivr.net/npm/monaco-editor@0.40.0/min/vs/editor/editor.main.min.css" rel="stylesheet" /> </head> <body> <h2>Monaco Editor LaTeX</h2> <div id="container" style="width: 100%; height: 600px; border: 1px solid lightgray" ></div> <script src="https://cdn.jsdelivr.net/npm/monaco-editor@0.40.0/min/vs/loader.min.js"></script> <script> require.config({ paths: { vs: "https://cdn.jsdelivr.net/npm/monaco-editor@0.40.0/min/vs", }, }); require(["vs/editor/editor.main"], function () { // Register a new language monaco.languages.register({ id: "latex" }); // Register a tokens provider for the language monaco.languages.setMonarchTokensProvider("latex", { tokenizer: { root: [ [/(\\[a-zA-Z]+)/, "command"], // LaTeX commands [/(\\[\w\u3000-\u9FFF]+)/, "note"], // LaTeX commands [/(\{)/, "brace"], [/(\})/, "brace"], [/(\[)/, "bracket"], [/(\])/, "bracket"], [/(document|dvips)/, "keyword"], // LaTeX keywords [/(%.*)/, "comment"], // Comments ], }, }); // Define a new theme that contains only rules that match this language monaco.editor.defineTheme("myTheme", { base: "vs", inherit: true, rules: [ { token: "command", foreground: "#F44336" }, // LaTeX commands in red { token: "note", foreground: "#2196F3" }, // Notes in blue { token: "brace", foreground: "FF00FF" }, // Braces in magenta { token: "bracket", foreground: "00FFFF" }, // Brackets in cyan { token: "keyword", foreground: "#4CAF50" }, // Keywords in green { token: "comment", foreground: "#9E9E9E" }, // Comments in gray ], colors: {}, }); monaco.editor.create(document.getElementById("container"), { value: getCode(), language: "latex", theme: "myTheme", wordWrap: true, }); }); function getCode() { return `\\documentclass{tbook} \\usepackage{hiragino,cid} \\usepackage[dvips]{graphics} \\usepackage{font} % \\見開き \\begin{document} テキスト \\書名{(サンプル)}テキスト 長いテキスト長いテキスト長いテキスト長いテキスト長いテキスト長いテキスト長いテキスト長いテキスト長いテキスト長いテキスト長いテキスト長いテキスト長いテキスト長いテキスト長いテキスト\\右注{(あああ)}長いテキスト長いテキスト \\右注{(サンプル)}テキスト \\end{document}`; } </script> </body> </html> カスタム言語の設定方法については、以下のページが参考になりました。 ...

Ace.jsでTeXをハイライトする

Ace.jsでTeXをハイライトする

概要 Ace.jsでTeXをハイライトする機会がありましたので、備忘録です。 以下の記事を参考にしました。 https://banatech.net/blog/view/11 参考になりましたら幸いです。 画面例 デモサイト https://nakamura196.github.io/ace_latex/ リポジトリ https://github.com/nakamura196/ace_latex ソースコード <html lang="en"> <head> <title>ACE in Action</title> </head> <body> <div id="editor" style="width: 100%; height: 400px; border: 1px solid gray;"></div> <script src="https://cdnjs.cloudflare.com/ajax/libs/ace/1.23.2/ace.js" integrity="sha512-oVyp48/610D5Jo577cvp2vX+Fc0kYaI6s2tZRqBRzjZh7+y/vOEHTzUefbXk/B8P0B76bOK3tL1zeF/QcXlyiA==" crossorigin="anonymous" referrerpolicy="no-referrer" ></script> <script> const text = `\\usepackage{hiragino,ryumin,cid} \\usepackage[dvips]{graphics} \\usepackage{multicol} \\begin{document} テキスト \\右注{(サンプル)}テキスト \\end{document}`; const editor = ace.edit("editor"); // editor.setTheme("ace/theme/monokai"); editor.setFontSize(14); editor.getSession().setMode("ace/mode/latex"); editor.getSession().setUseWrapMode(true); editor.getSession().setTabSize(4); editor.$blockScrolling = Infinity; editor.setOptions({ enableBasicAutocompletion: true, enableSnippets: true, }); editor.setValue(text, 1); </script> </body> </html>

Github Actionsを使ってGithubからEC2までのDjangoのCICD環境構築(2023版)

Github Actionsを使ってGithubからEC2までのDjangoのCICD環境構築(2023版)

概要 Github Actionsを使ってGithubからEC2までのDjangoのCICD環境を構築する機会があり、その備忘録です。 以下の記事を参考にさせていただきました。 https://qiita.com/fffukken/items/27b0bfa712940914d3f6 上記の記事に対して、Github Actionsの設定を一部更新しました。 Github Actionsの設定 name: Test and Deploy on: push: branches: [ develop, main ] pull_request: branches: [ develop ] jobs: build: runs-on: ubuntu-latest strategy: max-parallel: 4 matrix: python-version: [3.9, "3.10"] steps: - uses: actions/checkout@v3 - name: Set up Python ${{ matrix.python-version }} uses: actions/setup-python@v4 with: python-version: ${{ matrix.python-version }} - name: Install Dependencies run: | python -m pip install --upgrade pip pip install -r requirements.txt - name: Run Tests run: | python manage.py makemigrations python manage.py migrate python manage.py test - name: deploy run: | echo "$SECRET_KEY" > secret_key chmod 600 secret_key ssh -oStrictHostKeyChecking=no ${EC2_USER}@${EC2_HOST} -i secret_key "source <仮想環境名>/bin/activate \ && cd ~/<プロジェクト名>\ && git pull origin main \ && python manage.py makemigrations \ && python manage.py migrate \ && deactivate \ && sudo systemctl restart gunicorn" env: SECRET_KEY: ${{ secrets.SECRET_KEY }} EC2_USER: ${{ secrets.EC2_USER }} EC2_HOST: ${{ secrets.EC2_HOST }} 変更した点として、actions/checkoutとactions/setup-pythonのバージョンを変更しました。また、pip installの部分を変更し、pip install -r requirements.txtにしました。 ...

django-simple-history: Djangoでモデルの編集履歴を記録する

django-simple-history: Djangoでモデルの編集履歴を記録する

概要 Djangoで編集履歴を残す方法を調べたので、その備忘録です。 以下のメッセージのように、デフォルトでは、管理画面を通じた編集履歴は記録されるが、それ以外の画面を通じた編集履歴は残らないようでした。 This object doesn’t have a change history. It probably wasn’t added via this admin site. django-simple-history そこで、以下のパッケージを使ってみます。 https://django-simple-history.readthedocs.io/en/latest/ 以下のクイックスタートのページを参考にすることで、問題なく利用できました。 https://django-simple-history.readthedocs.io/en/latest/quick_start.html 参考 以下のように、編集履歴に関するテーブルが追加され、編集履歴が記録されるようになりました。 また管理画面から、以下のような編集履歴を確認できるようになりました。管理画面以外の画面からの変更履歴を確認できました。 まとめ Djangoで編集履歴を残す際に参考になりましたら幸いです。

Django Rest Framework (DRF)で部分一致フィルタを実装する

Django Rest Framework (DRF)で部分一致フィルタを実装する

Django Rest Framework (DRF)で部分一致フィルタを実装するためには、Djangoフィルターバックエンドを使うのが一般的です。これは、django_filters モジュールを使用します。 このモジュールをまだインストールしていない場合は、以下のコマンドでインストールできます: pip install django-filter 以下は、部分一致検索を実現するための一般的な手順です: フィルタセットを定義します。以下はmodels.pyに存在するMyModelというモデルでnameフィールドを部分一致検索するためのフィルタセットです: import django_filters class MyModelFilter(django_filters.FilterSet): name = django_filters.CharFilter(lookup_expr='icontains') class Meta: model = MyModel fields = ['name',] ここで、lookup_expr=‘icontains’は、大文字小文字を区別せずに部分一致を行うための設定です。 次に、作成したフィルタセットをViewSetに適用します: from rest_framework import viewsets from django_filters.rest_framework import DjangoFilterBackend class MyModelViewSet(viewsets.ModelViewSet): queryset = MyModel.objects.all() serializer_class = MyModelSerializer filter_backends = [DjangoFilterBackend] filterset_class = MyModelFilter これで、クライアントからのリクエストにnameパラメータが含まれている場合、その値に部分一致するMyModelのインスタンスがレスポンスとして返されます。 ただし、これらのコードは例示のためのものであり、実際の使用ではモデルやフィールド名を適切に置き換える必要があります。また、セキュリティやパフォーマンスの観点から、適切なフィルタリングとバリデーションを行うことが重要です。

bagit-pythonを試す

bagit-pythonを試す

bagitは以下のように説明されています。 bagit is a Python library and command line utility for working with BagIt style packages. 本ライブラリを試すGoogle Colabのノートブックを作成しました。 https://colab.research.google.com/github/nakamura196/ndl_ocr/blob/main/bagit_python.ipynb bagitの利用にあたり、参考になりましたら幸いです。

DjangoのModelFormを使用してアップロードしたファイルのパスを取得する

DjangoのModelFormを使用してアップロードしたファイルのパスを取得する

DjangoのModelFormを使用してアップロードしたファイルのパスを取得する機会がありましたのでメモします。 以下のモデルを想定します。 class Document(models.Model): file = models.FileField(upload_to='documents/') 上記に対して、以下のようなviewsで、パスにアクセスすることができました。 from django.shortcuts import render, redirect from .forms import DocumentForm def upload_file(request): if request.method == 'POST': form = DocumentForm(request.POST, request.FILES) if form.is_valid(): document = form.save() file_url = document.file.url # Correct field name used here full_path = document.file.path # Correct field name used here return redirect('some-view') else: form = DocumentForm() return render(request, 'upload.html', {'form': form}) 基本的なことかと思いますが、参考になりましたら幸いです。

DjangoとAWS OpenSearchを接続する

DjangoとAWS OpenSearchを接続する

概要 DjangoとAWS OpenSearchを接続する方法に関するメモです。以下の記事が参考になりました。 https://testdriven.io/blog/django-drf-elasticsearch/ ただし、上記の記事はElasticsearchを対象にした設定のため、OpenSearchに応じた変更が必要です。 変更点 以下のElasticsearch Setupの部分から、OpenSearchに応じた変更が必要でした。 https://testdriven.io/blog/django-drf-elasticsearch/#elasticsearch-setup 具体的には、以下の2つのライブラリが必要でした。 (env)$ pip install opensearch-py (env)$ pip install django-opensearch-dsl その後は、django_elasticsearch_dslとなっている箇所をdjango-opensearch-dslに、elasticsearch_dslをopensearchpyに書き換えることで、記事の通りに進めることができました。 例えば、以下のような形です。 # blog/documents.py from django.contrib.auth.models import User from django_opensearch_dsl import Document, fields # opensearchに変更 from django_opensearch_dsl.registries import registry # opensearchに変更 from blog.models import Category, Article @registry.register_document class UserDocument(Document): class Index: name = 'users' settings = { 'number_of_shards': 1, 'number_of_replicas': 0, } class Django: model = User fields = [ 'id', 'first_name', 'last_name', 'username', ] @registry.register_document class CategoryDocument(Document): id = fields.IntegerField() class Index: name = 'categories' settings = { 'number_of_shards': 1, 'number_of_replicas': 0, } class Django: model = Category fields = [ 'name', 'description', ] @registry.register_document class ArticleDocument(Document): author = fields.ObjectField(properties={ 'id': fields.IntegerField(), 'first_name': fields.TextField(), 'last_name': fields.TextField(), 'username': fields.TextField(), }) categories = fields.ObjectField(properties={ 'id': fields.IntegerField(), 'name': fields.TextField(), 'description': fields.TextField(), }) type = fields.TextField(attr='type_to_string') class Index: name = 'articles' settings = { 'number_of_shards': 1, 'number_of_replicas': 0, } class Django: model = Article fields = [ 'title', 'content', 'created_datetime', 'updated_datetime', ] Populate Elasticsearch Elasticsearchを対象にした上記の記事では、以下のコマンドが紹介されています。 ...

Django REST framework で一括登録する

Django REST framework で一括登録する

概要 Django REST framework で一括登録を行う方法を調べたので、その備忘録です。 以下の記事の通りに進めることで、一括登録用のエンドポイントを作成することができました。 https://qiita.com/Utena-lotus/items/c7bde7f663cfc4aabff1 Postman Postmanで以下のようなリクエストを送りました。 結果、以下のように、一括登録を行うことができました。 まとめ 参考になりましたら幸いです。

djangoでJWTを使う(djangorestframework-simplejwt)

djangoでJWTを使う(djangorestframework-simplejwt)

概要 djangoでJWTを使おうと思い、djangorestframework-jwtを使ってみました。 https://github.com/jpadilla/django-rest-framework-jwt 以下のサイトなどを参考にすすめてみました。 https://dev-yakuza.posstree.com/django/jwt/ ただし、‘rest_framework_jwt.authentication.JSONWebTokenAuthentication’を記述したところで、以下のエラーが発生しました。 ImportError: cannot import name 'smart_text' from 'django.utils.encoding' 調べたところ、以下の記事が見つかりました。 https://stackoverflow.com/questions/72102911/could-not-import-rest-framework-jwt-authentication-jsonwebtokenauthentication かわりにdjangorestframework-simplejwtを使え、とのことでした。 https://github.com/jazzband/djangorestframework-simplejwt 以下、こちらの使い方についてメモを残します。 djangorestframework-simplejwt 以下のページを参考にすることで、動作確認を行うことができました。 https://django-rest-framework-simplejwt.readthedocs.io/en/latest/getting_started.html Postman usernameとpasswordを使って、以下にpostします。 http://localhost:8000/api/token/ 結果、refreshとaccessが得られます。 このaccessのほうの値を使用して、HeaderにAuthorizationを設定して送ります。Bearer [jwt]の形式で送ることで、apiを利用できました。 まとめ djangoでJWTを使う際の参考になりましたら幸いです。