Skip to content

Commit

Permalink
docs format
Browse files Browse the repository at this point in the history
  • Loading branch information
RamezIssac committed Oct 6, 2023
1 parent 0039553 commit 51b0772
Show file tree
Hide file tree
Showing 7 changed files with 174 additions and 110 deletions.
1 change: 1 addition & 0 deletions docs/source/howto/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ The interface is simple, only 3 mandatory methods to implement, The rest are man
# forms.py
from slick_reporting.forms import BaseReportForm
class RequestFilterForm(BaseReportForm, forms.Form):
SECURE_CHOICES = (
Expand Down
2 changes: 0 additions & 2 deletions docs/source/ref/view_options.rst
Original file line number Diff line number Diff line change
Expand Up @@ -54,10 +54,8 @@ Below is the list of general options that is used across all types of reports.
columns = [
# a computation field created on the fly
ComputationField.create(Sum, "value", verbose_name=_("Value"), name="value"),
# A computation Field class
MyTotalReportField,
# a computation field registered in the computation field registry
"__total__",
]
Expand Down
84 changes: 59 additions & 25 deletions docs/source/topics/computation_field.rst
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,16 @@ ComputationFields are the basic unit in a report.they represent a number that is
Computation Fields can be add to a report as a class, as you saw in other examples , or by name.


Reusing Computation Fields
Creating Computation Fields
---------------------------

You do not have to create the Computation Field each time you need one. You can create one and register it and reuse it.
There are 3 ways you can create a Computation Field

1. Create a subclass of ComputationField and set the needed attributes and use it in the columns attribute of the ReportView
2. Use the `ComputationField.create()` method and pass the needed attributes and use it in the columns attribute of the ReportView
3. Use the `report_field_register` decorator to register a ComputationField subclass and use it by its name in the columns attribute of the ReportView


Let's say you want to compute the total quantity of a product in a report.

.. code-block:: python
Expand All @@ -24,23 +28,24 @@ Let's say you want to compute the total quantity of a product in a report.
@report_field_register
class TotalQTYReportField(ComputationField):
name = '__total_quantity__' # The name to use when using this field in the generator
calculation_field = 'quantity' # the field we want to compute on
calculation_method = Sum # What method we want, default to Sum
verbose name = 'Total quantity' # A verbose name
name = "__total_quantity__"
calculation_field = "quantity" # the field we want to compute on
calculation_method = Sum # What method we want, default to Sum
verbose_name = _("Total quantity")
class ProductSales(ReportView):
report_title = _("Product Sales")
report_model = SalesTransaction
date_field = "date"
group_by = "product"
# ..
columns = [
"name",
"__total_quantity__",
# TotalQTYReportField,
# ComputationField.create(Sum, "quantity", name="__total_quantity__", verbose_name=_("Total quantity"))
]
# ...
"__total_quantity__", # Use the ComputationField by its registered name
TotalQTYReportField, # Use Computation Field as a class
ComputationField.create(
Sum, "quantity", name="__total_quantity__", verbose_name=_("Total quantity")
)
# Using the ComputationField.create() method
]
What happened here is that we:

Expand All @@ -49,26 +54,28 @@ What happened here is that we:
3. Used it by name inside the columns attribute (or in time_series_columns, or in crosstab_columns)
4. Note that this is same as using the class directly in the columns , also the same as using `ComputationField.create()`

Another example, If you want AVG to the field `price` then it would look like this
Another example, adding and AVG to the field `price`:

.. code-block:: python
from django.db.models import Avg
from slick_reporting.decorators import report_field_register
@report_field_register
class TotalQTYReportField(ComputationField):
name = '__avg_price__'
calculation_field = 'price'
name = "__avg_price__"
calculation_field = "price"
calculation_method = Avg
verbose name = 'Avg. Price'
verbose_name = _("Avg. Price")
class ProductSales(ReportView):
# ..
columns = [
"name",
"__avg_price__",
]
]
Using Value of a Computation Field within a another
---------------------------------------------------
Expand All @@ -86,13 +93,28 @@ Sometime you want to stack values on top of each other. For example: Net revenue
prevent_group_by = True
def resolve(self, prepared_results, required_computation_results: dict, current_pk, current_row=None) -> float:
result = super().resolve(prepared_results, required_computation_results, current_pk, current_row)
def resolve(
self,
prepared_results,
required_computation_results: dict,
current_pk,
current_row=None,
) -> float:
result = super().resolve(
prepared_results, required_computation_results, current_pk, current_row
)
return required_computation_results.get("__balance__") / result * 100
We need to override ``resolve`` to do the needed calculation. The ``required_computation_results`` is a dictionary of the results of the required fields, where the keys are the names.

Note:

1. The ``requires`` attribute is a list of the required fields to be computed before this field.
2. The values of the ``requires`` fields are available in the ``required_computation_results`` dictionary.
3. In the example we used the ``prevent_group_by`` attribute. It's as the name sounds, it prevents the rows from being grouped for teh ComputationField giving us the result over the whole set.


How it works ?
--------------
When the `ReportGenerator` is initialized, it generates a list of the needed fields to be displayed and computed.
Expand All @@ -116,11 +138,23 @@ The results are prepared in 2 main stages
class MyCustomComputationField(ComputationField):
name = "__custom_field__"
def prepare(self, q_filters: list | object = None, kwargs_filters: dict = None, queryset=None, **kwargs):
def prepare(
self,
q_filters: list | object = None,
kwargs_filters: dict = None,
queryset=None,
**kwargs
):
# do all you calculation here for the whole set if any and return the prepared results
pass
def resolve(self, prepared_results, required_computation_results: dict, current_pk, current_row=None) -> float:
def resolve(
self,
prepared_results,
required_computation_results: dict,
current_pk,
current_row=None,
) -> float:
# does the calculation for each record, return a value
pass
Expand Down
11 changes: 2 additions & 9 deletions docs/source/topics/crosstab_options.rst
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,6 @@ Here is a general use case:
"name",
"__crosstab__",
# You can customize where the crosstab columns are displayed in relation to the other columns
ComputationField.create(Sum, "value", verbose_name=_("Total Value")),
# This is the same as the calculation in the crosstab,
# but this one will be on the whole set. IE total value.
Expand Down Expand Up @@ -72,7 +71,6 @@ Example:
class CrosstabWithIdsCustomFilter(CrosstabReport):
crosstab_ids_custom_filters = [
(~Q(product__size__in=["extra_big", "big"]), dict()),
(None, dict(product__size__in=["extra_big", "big"])),
]
# Note:
Expand Down Expand Up @@ -111,16 +109,13 @@ Example 1: On a "regular" crosstab report
class CrossTabReportWithCustomVerboseName(CrosstabReport):
crosstab_columns = [
CustomCrossTabTotalField
]
crosstab_columns = [CustomCrossTabTotalField]
Example 2: On the ``crosstab_ids_custom_filters`` one

.. code-block:: python
class CustomCrossTabTotalField2(CustomCrossTabTotalField):
@classmethod
def get_crosstab_field_verbose_name(cls, model, id):
if id == 0:
Expand All @@ -129,9 +124,7 @@ Example 2: On the ``crosstab_ids_custom_filters`` one
class CrossTabReportWithCustomVerboseNameCustomFilter(CrosstabWithIdsCustomFilter):
crosstab_columns = [
CustomCrossTabTotalField2
]
crosstab_columns = [CustomCrossTabTotalField2]
Expand Down
64 changes: 37 additions & 27 deletions docs/source/topics/group_by_report.rst
Original file line number Diff line number Diff line change
Expand Up @@ -15,27 +15,31 @@ Example:
.. code-block:: python
class GroupByReport(ReportView):
report_model = SalesTransaction
report_title = _("Group By Report")
date_field = "date"
group_by = "product"
columns = [
"name",
ComputationField.create(
method=Sum, field="value", name="value__sum", verbose_name="Total sold $", is_summable=True,
),
]
# Charts
chart_settings = [
Chart(
"Total sold $",
Chart.BAR,
data_source=["value__sum"],
title_source=["name"],
),
]
report_model = SalesTransaction
report_title = _("Group By Report")
date_field = "date"
group_by = "product"
columns = [
"name",
ComputationField.create(
method=Sum,
field="value",
name="value__sum",
verbose_name="Total sold $",
is_summable=True,
),
]
# Charts
chart_settings = [
Chart(
"Total sold $",
Chart.BAR,
data_source=["value__sum"],
title_source=["name"],
),
]
A Sample group by report would look like this:
Expand All @@ -62,7 +66,7 @@ Example:
class GroupByTraversingFieldReport(GroupByReport):
report_title = _("Group By Traversing Field")
group_by = "product__product_category" # Note the traversing
group_by = "product__product_category" # Note the traversing
Expand All @@ -89,7 +93,9 @@ Example:
columns = [
"__index__",
ComputationField.create(Sum, "value", verbose_name=_("Total Sold $"), name="value"),
ComputationField.create(
Sum, "value", verbose_name=_("Total Sold $"), name="value"
),
]
chart_settings = [
Expand All @@ -109,13 +115,13 @@ Example:
def format_row(self, row_obj):
# Put the verbose names we need instead of the integer index
index = row_obj['__index__']
index = row_obj["__index__"]
if index == 0:
row_obj["__index__"] = "Big"
elif index == 1:
row_obj['__index__'] = "Small"
row_obj["__index__"] = "Small"
elif index == 2:
row_obj['__index__'] = "Medium"
row_obj["__index__"] = "Medium"
return row_obj
Expand Down Expand Up @@ -144,7 +150,11 @@ Example:
columns = [
ComputationField.create(
method=Sum, field="value", name="value__sum", verbose_name="Total sold $", is_summable=True,
method=Sum,
field="value",
name="value__sum",
verbose_name="Total sold $",
is_summable=True,
),
]
Expand Down
Loading

0 comments on commit 51b0772

Please sign in to comment.