Нужна помощь с необработанным запросом MySQL в Django или вызовом представления в Django, которое не выдает ошибку из-за отсутствия первичного ключа
Я работаю над проектом, который касается планирования мощностей и ресурсов для малого бизнеса. Я создал приложение на Django, которое позволяет собирать данные по назначенным задачам и целевым целям, а затем сравнивать их с записями пользователей, сделанными по назначенным им задачам. Запрос для финансового отдела должен отображаться в виде двух таблиц на одной странице.
После исследования этой темы в течение некоторого времени, я нашел два способа, которые звучат лучше всего для работы с конкретными необходимыми SQL запросами:
- Use the Raw SQL option for Django to create the lists.
- Create a View in MySQL and set the model in the model file as a managed=False model.
Есть несколько проблем, препятствующих продвижению этого запроса, которые, похоже, проистекают из потребности наборов запросов в Django иметь значение первичного ключа.
SQL запросы
Ниже приведены два запроса, которые успешно выполняются в MySQL Workbench:
SELECT
projects.project_number AS 'project',
projects.start_date AS 'start_date',
projects.target_date AS 'target_date',
SUM(tasks.target_hours) AS 'target_hours',
SUM(activities.hours) AS 'billed_hours',
(SUM(tasks.target_hours) - SUM(activities.hours)) AS 'remaining_hours'
FROM activities
INNER JOIN tasks ON activities.task_id = tasks.id
INNER JOIN projects ON tasks.project_id = projects.id
GROUP BY projects.project_number, tasks.task_number, activities.activity_class_id
ORDER BY projects.target_date DESC, projects.project_number ASC;
SELECT
projects.project_number AS 'project',
CONCAT(users.first_name, ' ', users.last_name) AS 'employee',
SUM(activities.hours) AS 'hours'
FROM activities
INNER JOIN tasks ON activities.task_id = tasks.id
INNER JOIN users ON activities.assignee_id = users.id
INNER JOIN projects ON tasks.project_id = projects.id
GROUP BY projects.project_number, users.username
ORDER BY projects.project_number ASC, users.username ASC;
Случай 1
В первом сценарии файлу представления был придан следующий вид, основанный на функциях:
@login_required
def qcpat_reports(request):
# queries
qry_time_report = "SELECT (1) AS 'id', projects.project_number AS 'project', projects.start_date AS 'start_date', " \
"projects.target_date AS 'target_date', SUM(tasks.target_hours) AS 'target_hours', " \
"SUM(activities.hours) AS 'billed_hours', (SUM(tasks.target_hours) - SUM(activities.hours)) " \
"AS 'remaining_hours' " \
"FROM activities " \
"INNER JOIN tasks ON activities.task_id = tasks.id " \
"INNER JOIN projects ON tasks.project_id = projects.id " \
"GROUP BY projects.project_number, tasks.task_number, activities.activity_class_id " \
"ORDER BY projects.target_date DESC, projects.project_number ASC;"
qry_personnel_totals = "SELECT (1) AS 'id', projects.project_number AS 'project', " \
"CONCAT(users.first_name, ' ', users.last_name) AS 'employee', " \
"SUM(activities.hours) AS 'hours' " \
"FROM activities " \
"INNER JOIN tasks ON activities.task_id = tasks.id " \
"INNER JOIN users ON activities.assignee_id = users.id " \
"INNER JOIN projects ON tasks.project_id = projects.id " \
"GROUP BY projects.project_number, users.username " \
"ORDER BY projects.project_number ASC, users.username ASC;"
# execution of queries
time_remaining = models.Activity.objects.raw(qry_time_report)
personnel_totals = models.Activity.objects.raw(qry_personnel_totals)
return render(request, 'qcpat/reports.html', {'time_remaining':time_remaining, 'personnel_totals':personnel_totals})
Примечание: Фраза " (1) AS 'id'" была добавлена к каждому SQL-запросу в этом представлении на основании совета из сообщения Stack Exchange, в котором рассматривалась ошибка, когда набор запросов не имеет указанного первичного ключа.
Случай 2
Во втором случае представление было создано с помощью SQL-запросов в MySQL. MySQL не создает столбец id в представлении. Он просто отображает запрос, и ресурсы, которые я нашел до сих пор, указывают, что вы не можете добавить пользовательское значение в представление в MySQL. Некоторые люди предложили вызываемую процедуру, чтобы попытаться сделать представление с id для поста, который рассматривал эту специфическую функцию в MySQL.
Поскольку источник данных не имеет id для первичного ключа, то он выдает те же ошибки при вызове в следующем представлении с поддерживающей моделью из файла модели:
# Model File
class TimeRemainderReportView(models.Model):
project = models.CharField(max_length=250)
start_date = models.DateField()
target_date = models.DateField()
target_hours = models.IntegerField()
billed_hours = models.IntegerField()
remaining_hours = models.IntegerField()
class Meta():
db_table = 'timeRemainders'
managed = False
class PeopleTimeReportView(models.Model):
project = models.CharField(max_length=250)
employee = models.CharField(max_length=250)
hours = models.IntegerField(max_length=250)
class Meta():
db_table = 'peopleTime'
managed = False
# View File
@login_required
def qcpat_reports(request):
time_remaining = models.TimeRemainderReportView.objects.all()
personnel_totals = models.PeopleTimeReportView.objects.all()
return render(request, 'qcpat/reports.html', {'time_remaining':time_remaining, 'personnel_totals':personnel_totals})
Файл шаблона
Файл шаблона остается неизменным в любом случае, но продолжает выдавать ошибки или не отображать данные.
Тестирование и результаты
До сих пор ближе всего к визуализации данных было использование примера 1 с добавленным компонентом " (1) as 'id'". Результаты показали две таблицы с правильным количеством строк для результатов запроса; однако в таблице ничего не было напечатано.
Тестирование кода в оболочке с помощью следующей команды демонстрирует, что одно и то же значение многократно используется из запроса в качестве каждой записи в таблице.
>>>qry_time_report = "SELECT (1) AS 'id', projects.project_number AS 'project', projects.start_date AS 'start_date', " \
... "projects.target_date AS 'target_date', SUM(tasks.target_hours) AS 'target_hours', " \
... "SUM(activities.hours) AS 'billed_hours', (SUM(tasks.target_hours) - SUM(activities.hours)) " \
... "AS 'remaining_hours' " \
... "FROM activities " \
... "INNER JOIN tasks ON activities.task_id = tasks.id " \
... "INNER JOIN projects ON tasks.project_id = projects.id " \
... "GROUP BY projects.project_number, tasks.task_number, activities.activity_class_id " \
... "ORDER BY projects.target_date DESC, projects.project_number ASC;"
>>> qry_personnel_totals = "SELECT (1) AS 'id', projects.project_number AS 'project', " \
... "CONCAT(users.first_name, ' ', users.last_name) AS 'employee', " \
... "SUM(activities.hours) AS 'hours' " \
... "FROM activities " \
... "INNER JOIN tasks ON activities.task_id = tasks.id " \
... "INNER JOIN users ON activities.assignee_id = users.id " \
... "INNER JOIN projects ON tasks.project_id = projects.id " \
... "GROUP BY projects.project_number, users.username " \
... "ORDER BY projects.project_number ASC, users.username ASC;"
>>> time_remaining = models.Activity.objects.raw(qry_time_report)
>>> personnel_totals = models.Activity.objects.raw(qry_personnel_totals)
>>> for entry in time_remaining:
... print(entry)
...
Since short nice kitchen president.
Since short nice kitchen president.
Since short nice kitchen president.
Since short nice kitchen president.
Since short nice kitchen president.
Since short nice kitchen president.
Since short nice kitchen president.
Since short nice kitchen president.
Since short nice kitchen president.
Since short nice kitchen president.
Since short nice kitchen president.
Since short nice kitchen president.
Since short nice kitchen president.
Since short nice kitchen president.
Since short nice kitchen president.
Since short nice kitchen president.
Since short nice kitchen president.
Since short nice kitchen president.
Since short nice kitchen president.
Since short nice kitchen president.
Since short nice kitchen president.
Since short nice kitchen president.
Since short nice kitchen president.
...
Сфера вопроса
Какой метод лучше всего использовать для этого конкретного сценария, чтобы добиться корректного отображения каждого из объектов? Был ли у кого-нибудь опыт работы с подобными запросами в Django? Есть ли что-то лучшее для использования или jQuery будет проще. Пожалуйста, посоветуйте.