#python #django
#python #django
Вопрос:
Я изучаю Django, чтобы создать интерфейс для моего проекта python, где мне нужно создать форму учетных данных для установления соединения с инструментом базы данных, например, PostgreSQL, который я создал. Теперь я хочу, чтобы в раскрывающемся списке были перечислены все базы данных, доступные в моем PostgreSQL, а затем в другом раскрывающемся списке перечислены все схемы, присутствующие в выбранной базе данных в первом раскрывающемся списке, а затем в другом раскрывающемся списке для таблиц, присутствующих в выбранной схеме, используя второй раскрывающийся список.
Я проверил много видео для этого, но все они показаны с моделями. Но я хочу, чтобы эти выпадающие значения были из внешней базы данных, а не из моделей.
Я попытался создать файл python для создания формы внутри моего приложения Django, в котором я использую формы.Выберите поле для перечисления значений базы данных. Но не удается получить выбранное значение для выпадающего списка. Чтобы я мог запрашивать схемы
Ответ №1:
Для примера я создал проект t_project
и приложение t_app
.
Я использовал psycopg2
библиотеку для изучения базы данных с помощью необработанного курсора (без оболочки Django).
Я вручную установил field.choices со значениями, которые я получил от psycopg.
# /t_project/settings.py
INSTALLED_APPS = [
# ...
't_app.apps.TAppConfig',
]
# /t_project/urls.py
from django.urls import path
from t_app import views as t_app_views
urlpatterns = [
path('', t_app_views.TestView.as_view(), name='test'),
path('<str:database>/', t_app_views.TestView.as_view(), name='test'),
path('<str:database>/<str:schema>/', t_app_views.TestView.as_view(), name='test'),
]
# /t_app/templates/t_app/test.html
<form method="post">
{% csrf_token %}
{{ form.as_p }}
<input type="submit" value="Submit"/>
</form>
# /t_app/views.py
import psycopg2
from django import forms
from django.http import HttpResponseRedirect
from django.urls import reverse
from django.views import generic
class DBForm(forms.Form):
database = forms.ChoiceField()
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.fields['database'].choices = self._get_databases()
def _get_databases(self):
conn_string = "host='localhost' dbname='postgres' user='postgres' password='postgres_pass'"
with psycopg2.connect(conn_string) as conn:
cursor = conn.cursor()
cursor.execute('SELECT datname FROM pg_database WHERE datistemplate = FALSE')
return [(d, d) for d, in cursor.fetchall()]
class SchemaForm(DBForm):
schema = forms.ChoiceField()
def __init__(self, database, *args, **kwargs):
super().__init__(*args, **kwargs)
self.fields['database'].initial = database
self.fields['schema'].choices = self._get_schemas(database)
def _get_schemas(self, database):
# TODO Do NOT forget to escape "database" here to prevent injections
conn_string = f"host='localhost' dbname='{database}' user='postgres' password='postgres_pass'"
with psycopg2.connect(conn_string) as conn:
cursor = conn.cursor()
cursor.execute('SELECT schema_name FROM information_schema.schemata')
return [(s, s) for s, in cursor.fetchall()]
class TableForm(SchemaForm):
table = forms.ChoiceField()
def __init__(self, database, schema, *args, **kwargs):
super().__init__(database, *args, **kwargs)
self.fields['schema'].initial = schema
self.fields['table'].choices = self._get_tables(database, schema)
def _get_tables(self, database, schema):
# TODO Do NOT forget to escape "database" here to prevent injections
conn_string = f"host='localhost' dbname='{database}' user='postgres' password='postgres_pass'"
with psycopg2.connect(conn_string) as conn:
cursor = conn.cursor()
cursor.execute('SELECT tablename FROM pg_catalog.pg_tables WHERE schemaname = %s', (schema,))
return [(t, t) for t, in cursor.fetchall()]
class TestView(generic.FormView):
template_name = 't_app/test.html'
def get_form(self, form_class=None):
kwargs = self.get_form_kwargs()
database = self.kwargs.get('database')
schema = self.kwargs.get('schema')
if schema:
return TableForm(database=database, schema=schema, **kwargs)
if database:
return SchemaForm(database=database, **kwargs)
return DBForm(**kwargs)
def form_valid(self, form):
database = form.cleaned_data.get('database')
schema = form.cleaned_data.get('schema')
table = form.cleaned_data.get('table')
if table:
print('Exit is here')
if schema:
return HttpResponseRedirect(reverse('test', kwargs={'schema': schema, 'database': database}))
if database:
return HttpResponseRedirect(reverse('test', kwargs={'database': database}))
return HttpResponseRedirect(reverse('test'))
Комментарии:
1. Спасибо @mistiru за обмен. Он работает до схемы. при выборе схемы я получаю сообщение об ошибке «требуется поле». Я попытался распечатать схему внутри класса testView и показывает мне «Нет».
2. @JaswantSingh Хорошо, это было из-за атрибута «disabled» (который я поместил в свой пост после тестирования), который не позволяет форме отправлять значение. Я отредактировал свой пост, и теперь он работает 😉
3. Спасибо, @mistiru за помощь. Сейчас он работает. Но у меня есть еще один вопрос, можем ли мы сделать это без кнопки отправки?
4. Да, мы можем делать все, что вы хотите ^^ Без кнопки отправки, вы можете прикрепить к полю прослушиватель «onchange» (с помощью javascript, на всякий случай ;)), и этот прослушиватель отправит форму, или вы можете сделать это с помощью ajax, или действительно, все, что вы хотите ^^ Я просто привел минимальный пример (вот почему я использовал наследование)
Ответ №2:
Вы можете сделать это:
- возвращает все базы данных
import psycopg2
conn = psycopg2.connect(
database="test",
user="root",
password="root",
host="127.0.0.1",
port="5432"
)
cursor = conn.cursor()
# first: get all databases
cursor.execute(
"""
SELECT datname
FROM pg_database
WHERE datistemplate = false;
"""
)
rows = cursor.fetchall()
dbs = [row[0] for row in rows]
cursor.close()
conn.close()
Интерфейс отображает выпадающий список, затем запрашивает все схемы с выбранной базой данных.
- возвращает все схемы
import psycopg2
conn = psycopg2.connect(
database="test",
user="root",
password="root",
host="127.0.0.1",
port="5432"
)
cursor = conn.cursor()
# second: get all schemas
# DB is the database selected in the previous step
cursor.execute(
"""
SELECT schema_name
FROM information_schema.schemata
WHERE catalog_name = 'DB';
"""
)
rows = cursor.fetchall()
schemes = [row[0] for row in rows]
cursor.close()
conn.close()
То же, что и предыдущий, затем используйте выбранную схему и базу данных для запроса всех таблиц
- возвращает все таблицы
import psycopg2
conn = psycopg2.connect(
database="test",
user="root",
password="root",
host="127.0.0.1",
port="5432"
)
cursor = conn.cursor()
# third: get all tables
# SCHEMA is the schema selected in the previous step
cursor.execute(
"""
SELECT table_name
FROM information_schema.tables
WHERE table_schema = 'SCHEMA'
AND table_catalog = 'DB';
"""
)
rows = cursor.fetchall()
tables = [row[0] for row in rows]
cursor.close()
conn.close()
Вы можете встроить приведенный выше код в свой код django, чтобы сделать следующее.
Комментарии:
1. Я уже написал код на Python, чтобы получить все это. Я не могу встроить его в интерфейс django