Open Parthian opened 12 months ago
Figured out group_by. That it exposes the FK fields rather than report_model.
But still having trouble with a simple ListReportView E.g.
class EmployeeGenderReport(ListReportView):
report_model = Employee
report_title = "Employee Gender Report"
columns = [ 'surname', 'firstname', 'gender' ]
Results in Errors in uwsgi.log
Could not resolve form field 'start_date'.
Traceback (most recent call last):
File "/home/username/apps/appname/env/lib/python3.10/site-packages/django/forms/forms.py", line 178, in __getitem__
field = self.fields[name]
KeyError: 'start_date'
KeyError: "Key 'start_date' not found in 'Form'. Choices are: ."
Could not resolve form field 'end_date'.
Traceback (most recent call last):
File "/home/username/apps/appname/env/lib/python3.10/site-packages/django/forms/forms.py", line 178, in __getitem__
field = self.fields[name]
KeyError: 'end_date'
During handling of the above exception, another exception occurred:
File "/home/username/apps/appname/env/lib/python3.10/site-packages/slick_reporting/views.py", line 480, in get_report_generator
start_date=self.form.get_start_date(),
AttributeError: 'Form' object has no attribute 'get_start_date'
Upset by a lack of dates. Tried adding start_date and end_date to the View but no impact.
Related. All my Reports start at the beginning of the year. Tried start_date = '1900-01-01 00:00:00' but that has no impact.
Thanks. Using 1.1.1
Thank you for the update and the report
There is a fix in the develop branch just made today for the initials.
You should be able to set your initials via
get_initial()
on the ReportViewAlso,Check slick reporting settings here https://django-slick-reporting.readthedocs.io/en/latest/ref/settings.html to change the default value of your dates.
Updated the settings and no change. Which is probably correct for 1.1.1 pre your fix. What is the best pip command to update to develop version. I remember I tried 3 different ways before and none worked. Very odd.
Updated to develop version by copying files (seems wrong). My reports no longer work (some were suspect to start). This was a bit swish showing the number of people in each age range. Using dob (Date of Birth) as Count is a bit random as it is really a Count of how many entries are in the queryset.
def age_range(min_age, max_age):
current = now().date()
min_date = date(current.year - min_age, current.month, current.day)
max_date = date(current.year - max_age, current.month, current.day)
return Employee.objects.filter(dob__gte=max_date,
dob__lte=min_date).order_by("dob")
class EmployeeDemographic(ReportView):
report_model = Employee
report_title = "Employee Demographic Report"
date_field = 'dob'
start_date = '1900-01-01 00:00:00'
# group_by = 'location'
group_by_custom_querysets = [
age_range(0,30),
age_range(31,40),
age_range(41,50),
age_range(51,70)
]
group_by_custom_querysets_column_verbose_name = _("Date Range Verbose")
# ComputationField below was SlickReportField
columns = [
"__index__",
# can't use these as rows are aggregated. "surname", "location__location_name",
ComputationField.create(method=Count, field="dob", name="age", verbose_name="Age Range", is_summable=False,),
]
#default_order_by = "-doc_date"
limit_records = 20
auto_load = True # False if demanding. DOESN'T SEEM TO WORK
chart_settings = [
Chart(
_("Age Chart"),
Chart.BAR,
data_source=["age"],
title_source=["__index__"]
),
]
def format_row(self, row_obj):
# Put the verbose names we need instead of the integer index
index = row_obj['__index__']
if index == 0:
row_obj["__index__"] = "0,30"
elif index == 1:
row_obj['__index__'] = "31,40"
elif index == 2:
row_obj['__index__'] = "41,50"
elif index == 3:
row_obj['__index__'] = "51,70"
return row_obj
uwsgi.log ends
File "/home/username/apps/appname/env/lib/python3.10/site-packages/slick_reporting/generator.py", line 540, in <listcomp>
data = [format_row(get_record_data(obj, all_columns)) for obj in main_queryset]
File "/home/username/apps/appname/env/lib/python3.10/site-packages/slick_reporting/generator.py", line 520, in _get_record_data
value = computation_class.do_resolve(group_by_val, data)
AttributeError: 'ReportField_age' object has no attribute 'do_resolve'
[pid: 210510|app: 0|req: 2/2] 127.0.0.1 () {62 vars in 1341 bytes} [Fri Oct 6 11:35:39 2023] GET /employeedemographic/?start_date=2000-01-01+00%3A00%3A00&end_date=2023-10-06+11%3A35%3A25 => generated 145 bytes in 1056 msecs (HTTP/1.1 500) 8 headers in 288 bytes (1 switches on core 1)
ReportField_age refers to my ComputedField name of 'age'. Note also that auto_load may not be working. I only get the 500 error after filtering or changing the date forces a refresh.
I had overridden the base.html to change title tag and add some inline css. The develop version has this. {% block extrajs %} {% include "slick_reporting/js_resources.html" %} {% endblock %} I've copied that over and I no longer get the 500 error. But my Select2 has gone and my reports no longer work. I think a conflict with my settings.py SLICK_REPORTING_SETTINGS_DEFAULT
I've added this to my reports. Works. From date is now 2001. Super. Reports still broken from this morning.
def get_initial(self):
initial = super().get_initial()
initial["start_date"] = '2001-01-01 00:00:00'
return initial
I will look into that and get back to you asap
To setup from develop branch pip install -e -e git+https://github.com/ra-systems/django-slick-reporting.git@develop#egg=django-slick-reporting
"'ReportField_age' object has no attribute 'do_resolve'" can you share the ReprotField_age structure?
auto_load
issue : iwill check it... but did you remember to collectstatic after upgrading ?!
SLICK_REPORTING_SETTINGS_DEFAULT
: It's SLICK_REPORTING_SETTINGS
(there is no _DEFAULT)
1) The new pip runs - magical. Still states it is 1.1.1 but that's possibly due to not being an official release. My Reports still don't work as they were this morning [update - see 3)] with the official 1.1.1 - note you've a typo with an extra -e. These egg installs didn't work for me before (probably ERP). Never sussed why. Can't find my notes, possibly an email.
2) Age is shown above a name for a ComputeField just counting the number of dob entries. A bit daft but acts as a count of members of each age_range custom queryset. This was working and showing the correct number of people in each age range. But my silly mistake with base.html that I'd overridden was the solution to that particular do_resolve thing. Please ignore.
3) Jackpot. I'm sure I did a collectstatic earlier today but another one just after the proper pip install moved 5 more files over. And my Report now works. Select2 now working as well. My Swish Bar Graph showing the number of people in each age range is back. Awesome.
I assume in my settings I can just add the dictionary settings I want to change. e.g.
SLICK_REPORTING_SETTINGS = {
"DEFAULT_START_DATE_TIME": '1999-01-01 00:00:00',
"DEFAULT_END_DATE_TIME": datetime.datetime.today(), # today
}
The coded get_initial is really handy as one start_date for all Reports isn't handy. So this way I've a nice default and a handy override for any Reports that need a different timescale. Super. I didn't understand your earlier option You should be able to set your initials via 1) the initial attribute
Thanks so much. It must be late in Egypt.
Only 11.05 PM and tomorrow is off so .. Yayy ! :-)
I didn't understand your earlier option, "the initial attribute"
class MyReport(ReportView):
initial = {} # it's a CBV option and it's now integrated, `get_initial` is more powerful of course.
Will update the develop to have a higher version number. i remember times when i had to uninstall and reinstall again if version numbers were the same.
Now your reports are working as expected ?! If yes then is there anythign else pending on this issue ?
My pleasure
All good. The bug fixes and my brain getting around some of the concepts is leading to positive results after a bit of a battle.
I think the biggest problem I've had is group_by with a FK results in only fields from the FK model being available. Took a while for that to sink in. It is documented but it seems odd and kept catching me out. Of course, it is an aggregation thing. No good getting the names for all Employees if they are lumped into one row for a ComputeField.
And maybe you could add another Tutorial example but without the focus on Sales and Values? You may find a lot of people will be interested in Slick Reporting but not for Sales tracking. Could make it easier for folks.
Now to figure out a Time Series and Crosstab solution. But not today.
And maybe you could add another Tutorial example but without the focus on Sales and Values? You may find a lot of people will be interested in Slick Reporting but not for Sales tracking. Could make it easier for folks.
I understand, What kind of use case you would find clearer to put in a tutorial ?
Time Series and crosstab will be pieace of cake ;-) Follow with the docs and i'm always happy to receive your feedback .
Cheers
I think a good Tutorial would be something classic like Person. Very similar to my Employee. And could be easily re-worked into other database classics like People - Student - Staff. Or Django's project docs favourite of Author Books. Where date would be Date of Birth or date a Person joined the School either as Staff or Student.
I've got a nice pie chart of genders using.
models.py
class genderOptions(models.TextChoices):
MALE = 'Male', _('Male')
FEMALE = 'Female', _('Female')
....
gender = models.CharField(_('Gender'), max_length=32, choices=genderOptions.choices, default=genderOptions.MALE )
....
reports.py (ReportView)
group_by_custom_querysets = [
Employee.objects.filter(gender='Male'),
Employee.objects.filter(gender='Female'),
]
columns = [ "__index__", ComputationField.create(method=Count, field='gender', name='gender_count', verbose_name=_('Count'))
]
chart_settings = [
Chart(
_("Gender Mix"),
Chart.PIE,
data_source=["gender_count"],
title_source=["__index__"]
),
]
def format_row(self, row_obj):
# Put the verbose names we need instead of the integer index
index = row_obj['__index__']
if index == 0:
row_obj["__index__"] = "Male"
elif index == 1:
row_obj['__index__'] = "Female"
return row_obj
A question. The above is neat for 2-4 options. But after that it gets a bit cumbersome. The gender model type is a ChoiceField. I've another field where there are 10+ entries in the ChoiceField. With the above approach I'd have to have all 10 entries in the group_by_custom_querysets and in the format_row.
The docs suggest that group_by can work with Text but I've not had any success. So could the above work with group_by = "gender"?
UPDATE. I can get ChoiceFields to work with group_by. I think the problem I had was my usual of trying to show columns that can't be shown - usually the fields from the group_by model but in this case I think only the field itself plus the calculation can be a column. Does that make sense?
Here is an example of what goes into the columns atttribute of the ReportView / Generator API
class Report(ReprotView):
columns = ["field_on_group_by_model", "group_by_model__traversing_field", "get_attribute", ComputationField.create(name="example")]
def get_attribute(self, obj: dict, row: dict) -> any:
# obj: a dictionary of the current group_by row
# row: a the current row of the report.
return f"{obj["field_on_group_by_model_2"]} - {row["group_by_model__traversing_field"]}"
get_attribute.verbose_name = "My awesome title"
Hope this helps , not sure where the documentation for that went... will find a place to add it
The initial error away at the top:
class EmployeePPEOwnerReport(ListReportView):
report_model = PPEOwner
report_title = "Employee PPEOwner Report"
date_field = 'date_assigned'
columns = ['date_assigned', 'attachment' # doesn't matter what columns I try.]
Loads of errors about start_date and end_date.
It's due to having a date_field on a ListReportView. I usually end up leaving the date_field as I blunder around trying to fix things. Sometimes switching from ReportView to ListReportView and getting more confused.
Could you update the ListReportView doc https://django-slick-reporting.readthedocs.io/en/latest/topics/list_report_options.html#list-reports to state not to use a date_field. It doesn't show one but an easy thing to miss for a newbie.
Than you ... i will check and update
@Parthian not sure what you mean about using date field, it does not have an effect , I can not reproduce any errors . Can you elaborate ?
Now on develop, date_field only need to b set for time series. for less issues with date field
I ran into the same error / warning. Just from a fresh clone from github, then switched to master and checkout out tag v1.3.1 (to reflect PyPi).
When running the "last 10 sales" report I get the following in the console where I started by ./manage.py runserver:
./manage.py runserver
Watching for file changes with StatReloader
Performing system checks...
System check identified no issues (0 silenced).
August 18, 2024 - 14:58:43
Django version 5.1, using settings 'demo_proj.settings'
Starting development server at http://127.0.0.1:8000/
Quit the server with CONTROL-C.
WARNING:root:Could not resolve form field 'start_date'.
Traceback (most recent call last):
File "/home/roland/.virtualenvs/django-slick-reporting/lib/python3.10/site-packages/django/forms/forms.py", line 174, in __getitem__
field = self.fields[name]
KeyError: 'start_date'
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "/home/roland/.virtualenvs/django-slick-reporting/lib/python3.10/site-packages/crispy_forms/utils.py", line 69, in render_field
bound_field = form[field]
File "/home/roland/.virtualenvs/django-slick-reporting/lib/python3.10/site-packages/django/forms/forms.py", line 176, in __getitem__
raise KeyError(
KeyError: "Key 'start_date' not found in 'SalesTransactionForm'. Choices are: client, date, product."
WARNING:root:Could not resolve form field 'end_date'.
Traceback (most recent call last):
File "/home/roland/.virtualenvs/django-slick-reporting/lib/python3.10/site-packages/django/forms/forms.py", line 174, in __getitem__
field = self.fields[name]
KeyError: 'end_date'
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "/home/roland/.virtualenvs/django-slick-reporting/lib/python3.10/site-packages/crispy_forms/utils.py", line 69, in render_field
bound_field = form[field]
File "/home/roland/.virtualenvs/django-slick-reporting/lib/python3.10/site-packages/django/forms/forms.py", line 176, in __getitem__
raise KeyError(
KeyError: "Key 'end_date' not found in 'SalesTransactionForm'. Choices are: client, date, product."
[18/Aug/2024 14:58:50] "GET /last-10-sales/ HTTP/1.1" 200 22708
/home/roland/.virtualenvs/django-slick-reporting/lib/python3.10/site-packages/django/db/models/fields/__init__.py:1665: RuntimeWarning: DateTimeField SalesTransaction.date received a naive datetime (2024-01-01 00:00:00) while time zone support is active.
warnings.warn(
/home/roland/.virtualenvs/django-slick-reporting/lib/python3.10/site-packages/django/db/models/fields/__init__.py:1665: RuntimeWarning: DateTimeField SalesTransaction.date received a naive datetime (2024-08-18 14:58:50.359619) while time zone support is active.
warnings.warn(
[18/Aug/2024 14:58:50] "GET /last-10-sales/?product=&client=&date= HTTP/1.1" 200 1704
Ok, it says WARNING but an exception during another exception does not sound like a warning to me. Also the date-from and date_to buttons are missing. I believe that is what the original poster tried to point out.
So, does this mean ListReportViews do have a bug?
Thank you for considering.
Trying some basic reports with django-slick-reporting (1.1.0) a ListReportView
Then an oddity with group_by. Two Reports. The first works but needs to have the group_by model fields for anything to appear. The second report fails to compile with the error message hinting that group_by has changed the report_model.
This looks similar to the closed issue https://github.com/ra-systems/django-slick-reporting/issues/58
Jan29 comment - "Note that both customer and customer__origin have a company_name field, but the ReportView tries to read that field on the report_model instead of the group_by model." I seem to have the opposite. ReportView is reading fields from group-by not report_model.
I may have misunderstood group_by.
Thanks.