Обновленная информация внизу поста.
Мне нужно немного помочь с PyQt5 и его архитектурой представления модели для баз данных.
Я пытаюсь повторносделать проект базы данных я сделал. (https://github.com/DivineHermit/Media-Database-v1/) обновление его для использования моделей (https://github.com/DivineHermit/Media-Database-v2/).
В настоящее время у меня есть три QSqlTableModel по одному для каждой таблицы в базе данных:
1) model_media - это QSqlTableModel из 'таблица media в моей базе данных и в настоящее время имеет 616 записей и используется QListView в главном окне и QDataWidgetMapper для отображения подробной информации о выбранной записи.
2) model_genres другая QSqlTableModel для «жанров»таблица.
3) model_types окончательная QSqlTableModel для таблицы 'media_types'.
Однако после настройки второй и третьей моделей (отображения их данных в дочерних окнах) исходная модель остановиласьзагрузка записей при прокрутке вниз по списку, и я не могу понять, почему, прежде чем он загрузит несколько записей, а затем загрузит еще несколько, когда вы прокрутите до конца QListView.
Пояснение (Надеюсь): Исходная модель model_media используется для отображения списка заголовков мультимедиа в QListView (в настоящее времяимеет 616 записей) он будет отображать первые сто или около того записей в QListView и при прокрутке вниз будет загружаться больше, как и ожидалось. Поэтому я перешел к реализации следующих двух моделей и аналогичным образом отобразил их данные в своих собственных окнах, что сработало нормально, однако в этот момент основной QListView больше не загружал записи при прокрутке вниз по списку, он отображает только первую сотню или около тогозаписи.
Оригинальный проект (PyQt5 & Sqlite3): https://github.com/DivineHermit/Media-Database-v1/
Новая версия (только PyQt5): https://github.com/DivineHermit/Media-Database-v2/
Обновление: тестовые сценарии.
В настоящее время я считаю, что способ, которым я реализовал свой класс / GUI, влияет на основную модель и будет сводить проект к основам и пытаться провести некоторое тестирование, чтобы найти истинную проблему.
Я включаю тестовые сценарии, приведенные ниже, в надежде, что они будут полезны другим.
Следуя совету eyllanesc, я написал минимальный пример моделей, которые я использую, и провел его по базе данных, пытаясь воспроизвестиошибка, однако, этот тестовый скрипт на самом деле работал:
from PyQt5 import QtCore
from PyQt5 import QtSql
from PyQt5 import QtWidgets
class DBQueries(QtWidgets.QMainWindow):
def __init__(self, db="Media-Database.db", parent=None):
super(DBQueries, self).__init__(parent)
self.db = QtSql.QSqlDatabase.addDatabase("QSQLITE")
self.db.setDatabaseName(db)
if not self.db.open():
print("Error connecting to database:\n{}".format(self.db.lastError().text()))
# ===== Media Model =====
self.model_media = QtSql.QSqlTableModel(self)
self.model_media.setTable("media")
self.model_media.sort(1, QtCore.Qt.AscendingOrder)
self.model_media.select()
# ===== Genres Model =====
self.model_genres = QtSql.QSqlTableModel(self)
self.model_genres.setTable("genres")
self.model_genres.setSort(1, QtCore.Qt.AscendingOrder)
self.model_genres.select()
# ===== Types Model =====
self.model_types = QtSql.QSqlTableModel(self)
self.model_types.setTable("media_types")
self.model_types.setSort(1, QtCore.Qt.AscendingOrder)
self.model_types.select()
# ===== Proxy/Search Model =====
self.proxy = QtCore.QSortFilterProxyModel(self)
self.proxy.setSourceModel(self.model_media)
self.proxy.setFilterKeyColumn(1)
self.proxy.setFilterCaseSensitivity(QtCore.Qt.CaseInsensitive)
# ===== UI =====
self.cw = QtWidgets.QWidget(self)
self.vl = QtWidgets.QVBoxLayout(self.cw)
self.le_search = QtWidgets.QLineEdit()
self.le_search.textChanged.connect(
lambda: self.proxy.setFilterFixedString(
self.le_search.text()))
self.vl.addWidget(self.le_search)
self.view_media_list = QtWidgets.QListView()
self.view_media_list.setModel(self.proxy)
self.view_media_list.setModelColumn(1) # Title column.
self.vl.addWidget(self.view_media_list)
self.view_media = QtWidgets.QTableView()
self.view_media.setModel(self.proxy)
self.view_media.sortByColumn(1, QtCore.Qt.AscendingOrder)
self.vl.addWidget(self.view_media)
self.cb_genres = QtWidgets.QComboBox()
self.cb_genres.setModel(self.model_genres)
self.cb_genres.setModelColumn(1)
self.vl.addWidget(self.cb_genres)
self.view_genres = QtWidgets.QTableView()
self.view_genres.setModel(self.model_genres)
self.vl.addWidget(self.view_genres)
self.cb_types = QtWidgets.QComboBox()
self.cb_types.setModel(self.model_types)
self.cb_types.setModelColumn(1)
self.vl.addWidget(self.cb_types)
self.view_types = QtWidgets.QTableView()
self.view_types.setModel(self.model_types)
self.vl.addWidget(self.view_types)
# ===== Selected =====
self.selected_media = self.view_media.selectionModel()
self.selected_media.selectionChanged.connect(self.display_details)
self.setCentralWidget(self.cw)
def display_details(self):
"""Display a dialog with table cell contents, this is just a PoC."""
details = QtWidgets.QDialog(self)
details.setMinimumWidth(250)
lbl = QtWidgets.QLabel(details)
lbl.setText(str(self.selected_media.currentIndex().data()))
details.show()
if __name__ == "__main__":
import sys
app = QtWidgets.QApplication(sys.argv)
# Added an input to make t easier to swap
# between project and test databases.
db = input("Enter name of database >>> ")
window = DBQueries(db)
window.show()
sys.exit(app.exec_())
Понимая, что люди, желающие помочь, не будут иметь данныхя использую для проекта я создал следующий скрипт и использовал тестовый скрипт для новой базы данных с таким же положительным / рабочим результатом:
import sqlite3
import random
__author__ = "Dominic Lee"
__version__ = "0.0.1"
class DBGenerator:
"""Used to create an sqlite3 database with random data for testing."""
def __init__(self, db_name=":memory:", count=1000):
self.connection = sqlite3.connect(db_name)
self.cursor = self.connection.cursor()
self.file_name = db_name
self.create_media_table()
self.create_genres_table()
self.create_types_table()
self.create_test_entries(count)
self.create_test_genres()
self.create_test_types()
def create_media_table(self):
"""Create the main media table."""
self.cursor.execute("""
CREATE TABLE IF NOT EXISTS media (
id INTEGER PRIMARY KEY,
title VARCHAR NOT NULL,
description VARCHAR,
age_rating VARCHAR,
genre VARCHAR,
season INTEGER,
disc_count INTEGER,
media_type VARCHAR,
play_time INTEGER,
notes VARCHAR)""")
self.connection.commit()
return True
def create_genres_table(self):
"""Create the genres table."""
self.cursor.execute("""
CREATE TABLE IF NOT EXISTS genres (
id INTEGER PRIMARY KEY,
genre VARCHAR,
description VARCHAR,
examples VARCHAR)""")
self.connection.commit()
return True
def create_types_table(self):
"""Create the media_types table."""
self.cursor.execute("""
CREATE TABLE IF NOT EXISTS media_types (
id INTEGER PRIMARY KEY NOT NULL,
type VARCHAR)""")
self.connection.commit()
return True
def create_test_entries(self, count=1000):
"""
Add randomized dummy data to database for testing
:param count: the number of entries to add.
:return: True
"""
for i in range(1, count+1):
print(f"Adding entry: {str(i).zfill(len(str(count)))}")
self.cursor.execute("""
INSERT INTO media VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
""", (None,
f"Entry {str(i).zfill(len(str(count)))}",
f"Blank Description {str(i).zfill(len(str(count)))}",
f"{random.choice(['U: Universal', '15', '18', 'E: Exempt'])}",
f"{random.choice(['Action', 'Comedy', 'Drama', 'Sci-Fi'])}",
random.randint(0, 10),
random.randint(1, 6),
f"{random.choice(['DVD: Movie', 'DVD: Series', 'Audio CD', 'PS4 Game'])}",
random.randint(60, 1000),
f"Starring: {random.choice(['John', 'Paul', 'George', 'Ringo'])}"))
self.connection.commit()
return True
def create_test_genres(self):
"""Add a list of genres to the database for testing purposes."""
genres = ["Action",
"Anime",
"Biography",
"Cartoon",
"Comedy: Action",
"Comedy: Quiz Show",
"Comedy: Sitcom",
"Comedy: Stand-Up",
"Cookery",
"D.I.Y.",
"Documentary",
"Drama",
"Drama: Criminal",
"Educational",
"Fantasy",
"Game Show",
"Gardening",
"Horror",
"Kids/Children",
"Lifestyle",
"Makeover",
"Music",
"Mystery",
"News",
"Reality TV",
"Sci-Fi",
"Shopping",
"Soap",
"Talk Show",
"Thriller",
"Travel",
"Western"]
for g in genres:
print(f"Adding genre: {g}")
self.cursor.execute("""
INSERT INTO genres VALUES (?, ?, ?, ?)
""", (None, g, f"Description for {g}", f"Examples for {g}"))
self.connection.commit()
return True
def create_test_types(self):
"""Add media types to the database."""
types = ["Audio CD",
"Book: Educational",
"Book: Graphic Novel",
"Book: Manga",
"Book: Novel",
"Book: Programming",
"Cassett Tape",
"DVD: Movie",
"DVD: Series",
"Digital Download",
"Nintendo DS Game",
"Nintendo Wii Game",
"PC Game",
"PS1 Game",
"PS2 Game",
"PS3 Game",
"PS4 Game",
"PSP Game",
"PSVita Game"]
for t in types:
print(f"Adding media type: {t}")
self.cursor.execute("""
INSERT INTO media_types VALUES (?, ?)
""", (None, t))
self.connection.commit()
return True
if __name__ == "__main__":
# Create an instance of DBGenerator,
# give it a name and how many entries to create.
# DBGenerator(db_name, count)
# db_name defaults to ':memory:'
# count defaults to 1000
db = DBGenerator(count=1000)