def mail_scene(objects: QuerySet, field: Optional[str] = None, value=None, ctype=None, object_pk=None): tr: TestRun = objects[0].run # scence_templates format: # template, subject, context tcrs = (objects.select_related('case', 'assignee').only( 'case__summary', 'assignee__username').order_by('pk')) tcr: TestCaseRun scence_templates = { 'assignee': { 'template_name': 'mail/change_case_run_assignee.txt', 'subject': f'Assignee of run {tr.pk} has been changed', 'recipients': tr.get_notification_recipients(), 'context': { 'run_id': tr.pk, 'summary': tr.summary, 'full_url': tr.get_full_url(), 'test_case_runs': [{ 'pk': tcr.pk, 'case_summary': tcr.case.summary, 'assignee': tcr.assignee.username, } for tcr in tcrs] } } } return scence_templates.get(field)
def decorate_queryset( cls, feature_type: FeatureType, queryset: models.QuerySet, output_crs: CRS, **params, ) -> models.QuerySet: """Make sure relations are included with select-related to avoid N-queries. Using prefetch_related() isn't possible with .iterator(). """ xsd_type: XsdComplexType = feature_type.xsd_type # Take all relations that are expanded to complex elements, # and all relations that are fetched for flattened elements. related = { xsd_element.orm_path for xsd_element in xsd_type.complex_elements if not xsd_element.is_many } | { xsd_element.orm_relation[0] for xsd_element in xsd_type.flattened_elements if not xsd_element.is_many } if related: queryset = queryset.select_related(*related) return queryset
def mail_scene(objects: QuerySet, field: Optional[str] = None, value=None, ctype=None, object_pk=None): tcs = (objects.select_related('reviewer').only( 'summary', 'reviewer__email').order_by('pk')) tc: TestCase scence_templates = { 'reviewer': { 'template_name': 'mail/change_case_reviewer.txt', 'subject': 'You have been the reviewer of cases', 'recipients': list(set(tcs.values_list('reviewer__email', flat=True))), 'context': { 'test_cases': [{ 'pk': tc.pk, 'summary': tc.summary, 'full_url': tc.get_full_url() } for tc in tcs], } } } return scence_templates.get(field)
def optimize_query(query: QuerySet, meta: FieldMeta) -> QuerySet: model = query.model only_cols = get_only_cols(model, meta.sections) select_related_cols, prefetchs = get_related_cols(model, meta.sub_fields) if only_cols: query = query.only(*only_cols) if select_related_cols: query = query.select_related(*select_related_cols) if prefetchs: query = query.prefetch_related(*prefetchs) return query
def filter_queryset(self, request: Request, queryset: QuerySet, view: GenericViewSet): if (not issubclass(view.get_serializer_class(), FlexFieldsSerializerMixin) or request.method != "GET"): return queryset auto_remove_fields_from_query = getattr( view, "auto_remove_fields_from_query", True) auto_select_related_on_query = getattr(view, "auto_select_related_on_query", True) required_query_fields = list(getattr(view, "required_query_fields", [])) serializer = view.get_serializer( # type: FlexFieldsSerializerMixin context=view.get_serializer_context()) serializer.apply_flex_fields() model_fields = [ self._get_field(field.source, queryset.model) for field in serializer.fields.values() if self._get_field(field.source, queryset.model) ] nested_model_fields = [ self._get_field(field.source, queryset.model) for field in serializer.fields.values() if self._get_field(field.source, queryset.model) and field.field_name in serializer.expanded_fields ] if auto_remove_fields_from_query: queryset = queryset.only(*(required_query_fields + [ model_field.name for model_field in model_fields if not model_field.is_relation or model_field.many_to_one ])) if auto_select_related_on_query and nested_model_fields: queryset = queryset.select_related( *(model_field.name for model_field in nested_model_fields if model_field.is_relation and model_field.many_to_one)) queryset = queryset.prefetch_related( *(model_field.name for model_field in nested_model_fields if model_field.is_relation and not model_field.many_to_one)) return queryset
def build_queryset(self, queryset: models.QuerySet) -> models.QuerySet: if self.query: queryset = self.query.apply_to_queryset(queryset) if self.order_by: queryset = queryset.order_by(*self.order_by) if self.distinct: queryset = queryset.distinct(*self.distinct) if self.prefetch_trees: select_related = [] for prefetch_tree in self.prefetch_trees: tree_select_related = self._flatten_prefetch_tree( prefetch_tree=prefetch_tree) if tree_select_related is not None: select_related += tree_select_related queryset = queryset.select_related( *[sr for sr in select_related if sr is not None]) return queryset
def setup_eager_loading(cls, queryset: QuerySet): return queryset.select_related('service', 'user_profile', 'user_profile__account')
def _optimize_query( self, qs: QuerySet, blocked_user: Optional[List[Tuple[int, Optional[int]]]] = None): return qs.select_related()
def select_url_needed_staff(cls, qs: QuerySet) -> QuerySet: return qs.select_related('brand', 'category__parent', 'category__parent__parent', 'category__parent__parent__parent', 'category__parent__parent__parent__parent')
def setup_eager_loading(queryset: QuerySet): return queryset.select_related('stream')
def bulk_updater(self, queryset: QuerySet, update_fields: Optional[Set[str]] = None, return_pks: bool = False, local_only: bool = False, querysize: Optional[int] = None) -> Optional[Set[Any]]: """ Update local computed fields and descent in the dependency tree by calling ``update_dependent`` for dependent models. This method does the local field updates on `queryset`: - eval local `MRO` of computed fields - expand `update_fields` - apply optional `select_related` and `prefetch_related` rules to `queryset` - walk all records and recalculate fields in `update_fields` - aggregate changeset and save as batched `bulk_update` to the database By default this method triggers the update of dependent models by calling ``update_dependent`` with `update_fields` (next level of tree traversal). This can be suppressed by setting `local_only=True`. If `return_pks` is set, the method returns a set of altered pks of `queryset`. """ model: Type[Model] = queryset.model # distinct issue workaround # the workaround is needed for already sliced/distinct querysets coming from outside # TODO: distinct is a major query perf smell, and is in fact only needed on back relations # may need some rework in _querysets_for_update # ideally we find a way to avoid it for forward relations # also see #101 if queryset.query.can_filter() and not queryset.query.distinct_fields: queryset = queryset.distinct() else: queryset = model.objects.filter( pk__in=subquery_pk(queryset, queryset.db)) # correct update_fields by local mro mro = self.get_local_mro(model, update_fields) fields: Any = set( mro) # FIXME: narrow type once issue in django-stubs is resolved if update_fields: update_fields.update(fields) select = self.get_select_related(model, fields) prefetch = self.get_prefetch_related(model, fields) if select: queryset = queryset.select_related(*select) if prefetch: queryset = queryset.prefetch_related(*prefetch) pks = [] if fields: q_size = self.get_querysize(model, fields, querysize) change: List[Model] = [] for elem in slice_iterator(queryset, q_size): # note on the loop: while it is technically not needed to batch things here, # we still prebatch to not cause memory issues for very big querysets has_changed = False for comp_field in mro: new_value = self._compute(elem, model, comp_field) if new_value != getattr(elem, comp_field): has_changed = True setattr(elem, comp_field, new_value) if has_changed: change.append(elem) pks.append(elem.pk) if len(change) >= self._batchsize: self._update(queryset, change, fields) change = [] if change: self._update(queryset, change, fields) # trigger dependent comp field updates from changed records # other than before we exit the update tree early, if we have no changes at all # also cuts the update tree for recursive deps (tree-like) if not local_only and pks: self.update_dependent(model.objects.filter(pk__in=pks), model, fields, update_local=False) return set(pks) if return_pks else None