質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
Django

DjangoはPythonで書かれた、オープンソースウェブアプリケーションのフレームワークです。複雑なデータベースを扱うウェブサイトを開発する際に必要な労力を減らす為にデザインされました。

JSON

JSON(JavaScript Object Notation)は軽量なデータ記述言語の1つである。構文はJavaScriptをベースとしていますが、JavaScriptに限定されたものではなく、様々なソフトウェアやプログラミング言語間におけるデータの受け渡しが行えるように設計されています。

Python

Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。

Q&A

解決済

2回答

1689閲覧

Python geojson形式でのpropertiesの数値を変更して緯度経度を変更させたい

okiron9619

総合スコア5

Django

DjangoはPythonで書かれた、オープンソースウェブアプリケーションのフレームワークです。複雑なデータベースを扱うウェブサイトを開発する際に必要な労力を減らす為にデザインされました。

JSON

JSON(JavaScript Object Notation)は軽量なデータ記述言語の1つである。構文はJavaScriptをベースとしていますが、JavaScriptに限定されたものではなく、様々なソフトウェアやプログラミング言語間におけるデータの受け渡しが行えるように設計されています。

Python

Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。

0グッド

1クリップ

投稿2020/09/11 12:56

編集2020/09/14 15:06

前提・実現したいこと

geojson形式のpropertiesのidに数値を加算し、緯度経度を反映する。

マップ上にリンクを表示しようとしています。
データベースには
link_id,start_node_id,end_node_id
1, 1, 2
2, 3, 4
3, 5, 6
……

node_id,latlng
1 | 0101000020E6100000DE1A27FC71F560409C84FFA2FE814140
2 | 0101000020E610000043C98E5F72F5604012AF29CF00824140
3 | 0101000020E610000036649C476EF560405E2C94D502824140
……
のように二つのテーブルがあります。

データベースの情報のみでは、全てのリンクがつながらず途切れ途切れになってしまいます。
そのため、途切れ途切れのリンクにともう一つリンクを用意(ソースコード部分)し、リンクをつなげようと考えています。

発生している問題・エラーメッセージ

一つ目の途切れ途切れのリンク {'link': {'link_id': 1, 'start_node_id': 1, 'end_node_id': 2}}, 'geometry': {'type': 'LineString', 'coordinates': [[135.670211581115, 35.0156496957335], [135.670164181115, 35.0155833957335]]}} 二つ目の途切れ途切れのリンク {'link': {'link_id': 1, 'start_node_id': 2, 'end_node_id': 3}}, 'geometry': {'type': 'LineString', 'coordinates': [[135.670211581115, 35.0156496957335], [135.670164181115, 35.0155833957335]]}} start_node_id,end_node_idに加算できているのですが、対応した緯度経度が反映されていない状況です。

該当のソースコード

修正前(投稿時)のソースコード

views.py class GetHalf1LinkListView(View): ##@method_decorator(login_required()) def get(self, request, *args, **kwargs): # オブジェクトの取得 link_list = Mareas_Links_Nodes.objects.all().order_by('link_id') # レスポンスの生成 features = [LinkNodeMapper1(link).as_dict() for link in link_list] print("hello") print(features) response = { 'features': features, } # レスポンス response_json = json.dumps(response) return HttpResponse(response_json, content_type='application/json') class GetHalf2LinkListView(View): ##@method_decorator(login_required()) def get(self, request, *args, **kwargs): # オブジェクトの取得 link_list = Mareas_Links_Nodes.objects.all().order_by('link_id') # レスポンスの生成 features = [LinkNodeMapper2(link).as_dict() for link in link_list] print(features) response = { 'features': features, } # レスポンス response_json = json.dumps(response) return HttpResponse(response_json, content_type='application/json') get_half1_link_list = GetHalf1LinkListView.as_view() get_half2_link_list = GetHalf2LinkListView.as_view() view_models.py class LinkNodeMapper1: """ノードマッパー""" def __init__(self, obj): self.obj = obj def as_dict(self): link = self.obj return { 'type': 'Feature', 'properties': { 'link': { 'link_id': link.link_id, 'start_node_id':link.end_node_id, 'end_node_id':link.start_node_id, }, }, 'geometry': { 'type': 'LineString', 'coordinates': [[link.start_node.latlng.x,link.start_node.latlng.y],[link.end_node.latlng.x,link.end_node.latlng.y]], }, } class LinkNodeMapper2: """ノードマッパー""" def __init__(self, obj): self.obj = obj def as_dict(self): link = self.obj return { 'type': 'Feature', 'properties': { 'link': { 'link_id': link2.link_id, 'start_node_id':link.end_node_id + 1, 'end_node_id':link.start_node_id + 1, }, }, 'geometry': { 'type': 'LineString', 'coordinates': [[link.end_node.latlng.x,link.end_node.latlng.y],[link.start_node.latlng.x,link.start_node.latlng.y]], }, }

toast_uz様に回答、説明を提示して頂いた後、修正したソースコード

views.py

1class LinkList(View): 2 ##@method_decorator(login_required()) 3 def get(self, request, *args, **kwargs): 4 # オブジェクトの取得 5 link_list = Mareas_Links_Nodes.objects.all().order_by('link_id') 6 # レスポンスの生成 7 # link_listから要素を2つずつ取り出す 8 features = [] 9 for link1, link2 in zip(link_list, link_list[1:]): 10 features.append(LinkNode().connectLinks(link1, link1)) 11 features.append(LinkNode().connectedLinks(link1, link2)) 12 #features.append(Mareas_Links_Nodes.objects.all().reverse()[0]) 13 print(features) 14 response = { 15 'features': features, 16 } 17 # レスポンス 18 response_json = json.dumps(response) 19 return HttpResponse(response_json, content_type='application/json')

views_models.py

1class LinkNode: 2 def connectLinks(self, link1, link2): 3 # 繋げられる方のリンク生成 4 return { 5 'type': 'Feature', 6 'properties': { 7 'link': { 8 'link_id': link1.link_id, 9 'start_node_id':link1.start_node_id, 10 'end_node_id':link1.end_node_id, 11 }, 12 }, 13 'geometry': { 14 'type': 'LineString', 15 'coordinates': [[link1.start_node.latlng.x,link1.start_node.latlng.y],[link2.end_node.latlng.x,link2.end_node.latlng.y]], 16 }, 17 } 18 def connectedLinks(self, link1, link2): 19 # 繋げる方のリンク生成 20 return { 21 'type': 'Feature', 22 'properties': { 23 'link': { 24 'link_id': link1.link_id, 25 'start_node_id':link1.start_node_id, 26 'end_node_id':link1.end_node_id, 27 }, 28 }, 29 'geometry': { 30 'type': 'LineString', 31 'coordinates': [[link1.end_node.latlng.x,link1.end_node.latlng.y],[link2.start_node.latlng.x,link2.start_node.latlng.y]], 32 }, 33 }

試したこと

link.start_node_id + 1 のように直接代入してみましたがエラーは出ず、緯度経度は反映されませんでした。

リサーチ不足かもしれないですが、自分の力では参考サイトを見つけることができませんでした。

補足情報(FW/ツールのバージョンなど)

初投稿のため、必要な情報が足りていないかもしれません。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

meg_

2020/09/11 13:08

> link.start_node_id + 1 のように直接代入してみましたがエラーは出ず、結果は反映されませんでした。 コードを提示してください。
okiron9619

2020/09/11 13:33

コードの提示方法について、間違っていましたら申し訳ありません。
meg_

2020/09/11 14:07

質問に掲載されているのはPythonコードの一部ですか?
okiron9619

2020/09/11 14:13

はい、Pythonコードの一部です。わかりにくくすみません。 データベースにある緯度経度を取得し、geojson形式で格納し、javascriptへ渡し、マップ上で描画するというものです。
toast-uz

2020/09/11 14:28

エラーメッセージ、二つ目の途切れ途切れのリンクとは、「一つ目の途切れ途切れのリンクから生成したつなげるためのリンク」のことでしょうか? 該当のソースコードとは、一つ目の途切れ途切れのリンクのgeojsonから、つなげるためのリンクを生成している部分でしょうか? それであれば、そもそも二つ目の途切れ途切れのリンク link2 を用意して、linkのend_nodeと、link2のstart_nodeで座標を書き換える、すなわち、 'coordinates': [[link.end_node.latlng.x,link.end_node.latlng.y],[link2.start_node.latlng.x,link2.start_node.latlng.y]], にすべきと思います。
okiron9619

2020/09/11 14:44

toast_uz様 返信ありがとうございます。 該当ソースコードの部分について変更しました。 おっしゃる通り、つなげるためのリンクです。 途切れ途切れのリンクについても記述いたしました。 この場合は、つなげるためのリンク(start_node_id,end_node_idに+1しているほう)を返信していただいているように座標を書き換えるという認識でよろしいでしょうか。
toast-uz

2020/09/11 23:04

はい。geometryの部分を書き換える必要があります。状況大体わかりましたので回答記載します。
guest

回答2

0

最初にlink_listにDBからのリンクが全てlinkの配列としてロードされ、全てつなげた結果をfeatures(これもlinkの配列)に入れる、という理解をしました。

そうすると、複雑なことはせずに、以下の実装でよいと思います。

viewspy

1link_list = Mareas_Links_Nodes.objects.all().order_by('link_id') 2 3features = [] 4for link1, link2 in zip(link_list, link_list[1:]): # link_listから要素を2つずつ取り出す 5 features.append(link1) 6 features.append(connected_link(link1, link2)) 7features.append(link_list[-1]) # link_listの最後の要素を追加する

connected_linkは2つのlinkから、つなぐlinkを生成する関数です。別に実装する必要があります。最初に述べたようにgeometry側も変更することを忘れないようにして、実装してみてください。

ロジックとしては
features.append(link1) が前に書いた fromDB
features.append(connected_link(link1, link2)) が前に書いたconnectLinks
に相当しています。

投稿2020/09/13 23:03

toast-uz

総合スコア3266

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

okiron9619

2020/09/14 15:45

返信遅くなりすみません。 新しい回答の提示ありがとうございます。 新しいソースコードをもとに、冗長性や設計ミスはあだあると思われますが、私なりにソースコードを修正いたしました。 idの部分に関して、propertiesのidの部分に関しては、修正コード記載後に修正いたしました。 最適化やオブジェクト指向という点でまだ完全に理解が及んでいないと思いますので、再度投稿していただいた内容を確認したいと思います。 修正後の問題点等を教えていただけましたら幸いです。
toast-uz

2020/09/14 22:17

新しいコードはクラスを使っておりません。LinkNodeクラスは忘れてください。views.pyに新しいコードをそのまま記述して、connected_link(link1, link2) を単なる関数として実装していただくイメージです。geometryの書き方は合っていると思います。
okiron9619

2020/09/15 07:47

承知しました。 最初から最後まで、丁寧且つ詳しい説明や分かりやすいソースコードの提示本当にありがとうございました。 まだまだ、基礎が足りていないということを実感でき、改めてPythonやオブジェクト指向を勉強していこうと思います。 ありがとうございました。
guest

0

ベストアンサー

キー: geometry 側を操作していないと思われます。こちらも操作すれば目的の動作になるでしょう。
ただし、コードやオブジェクト構成の見通しを改善すると、よりよくなると思います。

以下のような流れでコード作ってみてください。コードはイメージなので動作確認していません。必要に応じて手直しください。

(1)LinkNodeの汎用クラスを作る

class LinkNode: def __init__(self): self.content = {} def fromDB(self, index): # DBのindex番目のレコードを読み込んでself.contentの辞書を作る def connectLinks(self, link1, link2): # link1とlink2をつなぐリンクとしてself.contentを作る ★

(2)LinkNodeクラスの配列オブジェクトを初期化する

link_nodes = []

(3)データベースから最初のLinkNodeオブジェクトを1つ読み込む

link_nodes.append(LinkNode().fromDB(0))

(4)データベースが終わるまで(5)(6)(7)を繰り返す、ループ回数をiとする
(5)データベースから新たなLinkNodeオブジェクトを1つ読み込む

new_link = LinkNode().fromDB(i)

(6)配列の最後のリンクと、今取得したリンクをつなぐリンクを作る

connected_link = LinkNode().connectLinks(link_nodes[-1], new_link)

(7)つなぐリンク、取得したリンクを配列に加える

link_nodes.append(connected_link) link_nodes.append(new_link)

でもって、★が今回のご質問の肝ですが、冒頭に記述したとおり、link1とlink2から適切にgeometry側も含めて操作してあげると、目的の動作になると思います。

投稿2020/09/11 23:35

toast-uz

総合スコア3266

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

okiron9619

2020/09/12 05:17

ソースコードの提示ありがとうございます。 すみません、私の理解不足で申し訳ないのですが質問点がいくつかあります。 1.提示していただいたソースコードは、編集した後で申し訳ないのですが、view_models.pyに汎用クラスLinkNodeを記述し、link_idと緯度経度を含む配列?を(7)で生成しているというものでしょうか。 2.views.pyにおいて、汎用クラスLink_Nodeを呼び出すために、views.pyにも汎用クラスが必要になるのでしょうか。 本当に理解不足ですみません。
toast-uz

2020/09/12 05:27 編集

viewにあまりロジックは追加したくないですので、view_models.pyに汎用クラスLinkNodeを記述したほうがよいと思います。あるいは完全に新しいサポートモジュールとして、my_geojson.pyなどを新規に作ってもよいです。 views.pyにおいて、import views_model as vm などとなっていれば、vm.LinkNodeという形でクラスを参照できます。
toast-uz

2020/09/12 06:06

サンプルコードを拝見するに、もう少しオブジェクト指向の基礎を学習するとよいと思います。 クラスは「ひな型」でのすで、微妙に異なるクラス1・クラス2を作らず、同一のクラスから、「ひな型の実体」であるインスタンス1・インスタンス2を作ります。また、クラスもインスタンスも「モノ、名詞、主語」ですので、クラス名にGetとかMapperとかの「操作、動詞、述語」的な表現が含まれているのは、クラス設計が間違っている可能性が高いと思った方が良いです。操作はクラスのメソッドとして記述します。 私のサンプルコードですと、LinkNodeという単一のクラスから、インスタンスを生成していますし、クラスのメソッドとしてfromDBとかconnectLinksなどの操作を記述しています。参考にしてください。
okiron9619

2020/09/12 14:59

詳しい説明ありがとうございます。仰る通りオブジェクトに対する知識不足です。申し訳ありません。 view_models.pyに途切れ途切れのリンク、つなげるためのリンクを生成するクラスを作るのではなく、 二つのリンク生成を一つのクラスにする。 汎用クラスLinkNodeを生成し、メソッドconnectLinksに回答していただいたソースコード(2) ~(7)を記述する。 これに伴い、views.pyにて二つのクラスを一つにまとめる。 views.pyにてDBのオブジェクトを取得し、その後LinkNodeクラスを呼び出しリンク生成。 DBのデータの呼び出し回数が私のコードですと2回あり、それぞれ別々のクラスでリンクを生成しているものをDBの呼び出し回数を1回にし、リンク生成のクラスも一つにまとめる。 クラス名に「操作、動詞、述語」の表現が含まれるのは、設計ミスの可能性が高い。 理解が追い付いていない部分もあるかもしれませんが、上記のような理解であっていますでしょうか。
toast-uz

2020/09/12 23:00 編集

大体合っていますが、クラスは「リンク(LinkNode)」という名詞であり、「リンク生成」は動詞です。短く表現すると名詞的ですが、「リンクを生成する」という意味ですので。よって、リンク生成はクラスではなく、クラスの中のメソッドで表現します。具体的には、LinkNodeクラスの中の、メソッドであるfromDB(DBからリンクを生成する)とかconnectLinks(既存のリンク2つをつなげる新たなリンクを生成する)とかで表現します。
okiron9619

2020/09/13 05:50

確かに「リンク生成」は動詞にあたりますね、初歩的ですみません。 こちらのオブジェクト指向の基礎がまだわかっていないことによる質問ですが、 私のコードですと、views.pyにて取得したオブジェクトを順にview_mpdels.pyにて、obj→linkのように代入され、linkオブジェクトの情報をgeojson形式で戻すというものだという認識です。 toast_uz様に提示していただいたソースコードでは、オブジェクト取得し、LinkNodeクラスのconnectLinksメソッドを呼び出しリンクを生成する。(fromDBメソッドにはなにも記述しない、views.pyでのfor文は不要?) という認識であっていますでしょうか。
toast-uz

2020/09/13 06:20 編集

fromDBの実装もforも必要です。 私のコードのfromDBはDBから1レコードすつ直接読み出すことを想定しています。 提示いただいたコードを、「順に、obj→linkのように代入され」と解説していただいていますが、まさに、私のコードでのLinkNode(のインスタンス)がそのlinkと同様に位置付けられます。順に、obj→LinkNodeのインスタンスへ代入する部分がfromDBであり、順に最後までまわすのがforです。 私のコードで、fromDBを、fromDBojectと読み替えていただくと、わかりやすいかと思います。
okiron9619

2020/09/13 06:32

丁寧な説明ありがとうございます。 DBから取得したオブジェクト(インスタンス)と、生成したリンクオブジェクト(インスタンス)がLinkNodeクラスのそれぞれ別のインスタンスという考えですかね(間違っていたらまだ理解が足りていないです、順に理解できるよう努力します) fromDBには、少し雑ですが LinkNodeMapper1(link).as_dict() for link in link_list のfor文の部分が当たり、私のコードでは、fromDBの部分を除いてしまっている。 つなぐリンクを生成するにあたり、一度レコードをすべて読み込んでしまう(fromDBメソッドのように)方法が良いということですね。
toast-uz

2020/09/13 06:48

だいたい合っています。 DBから取得した全レコードをオブジェクトと呼ばれているようですが、私のコードのLinkNodeのインスタンスは1レコード分です。全レコードはインスタンスのリストであるlink_nodesです。なお、link_nodesには、DBから読み込んだリンク1つ1つの他に、つないで作ったリンク1つ1つも、リスト要素として平等に扱っています。単数形と複数形に注意してください。 for文を内包表現で1行で記載されていますが、このfor文と私のfor文は同じ位置付けです。私のfor文(4)では、その中で(5)(6)(7)の処理を行います。
okiron9619

2020/09/13 16:59

数時間提示していただいた説明とソースコードを試行してみたのですが、自分の力ではまだうまくいきません。 views.py link_list = Mareas_Links_Nodes.objects.all().order_by('link_id') # レスポンスの生成 features = [LinkNode().fromDB(link) for link in link_list] views_models.py class LinkNode: def __init__(self): self.content = {} print(type(self.content)) def fromDB(self, index): # DBのindex番目のレコードを読み込んでself.contentの辞書を作る self.content = index print(type(self.content)) def connectLinks(self, link1, link2): # link1とlink2をつなぐリンクとしてself.contentを作る ★ print("Hi") link_nodes = [] link_nodes.append(LinkNode().fromDB(0)) new_link = LinkNode().fromDB(i) connected_link = LinkNode().connectLinks(link_nodes[-1], new_link) link_nodes.append(connected_link) link_nodes.append(new_link) return link_nodes コメントの部分にソースコードの提示で質問すること自体間違いかもしれません。申し訳ありません。 取得した全レコードをどこにいれるべきなのか(indexに入っている) 辞書型への変換がうまくいっていない メソッドconnectLinksの呼び出し方、引数link1,link2が何にあたるのか このあたりが自分で分かっている上手くいっていない部分です。 質問に質問を重ねて、すみません。少しずつ丁寧な説明をしていただいているため理解はできているのですが、コードへの反映がうまくいきません。教えていただけましたら幸いです。
toast-uz

2020/09/13 22:52

長くなりましたのと、コードを見やすくしたいので、回答を新しく作ります。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問