Refs #33646 -- Added RawModelIterable.
This commit is contained in:
parent
aca9bb2a12
commit
77926176b2
|
@ -140,6 +140,50 @@ class ModelIterable(BaseIterable):
|
|||
yield obj
|
||||
|
||||
|
||||
class RawModelIterable(BaseIterable):
|
||||
"""
|
||||
Iterable that yields a model instance for each row from a raw queryset.
|
||||
"""
|
||||
|
||||
def __iter__(self):
|
||||
# Cache some things for performance reasons outside the loop.
|
||||
db = self.queryset.db
|
||||
query = self.queryset.query
|
||||
connection = connections[db]
|
||||
compiler = connection.ops.compiler("SQLCompiler")(query, connection, db)
|
||||
query_iterator = iter(query)
|
||||
|
||||
try:
|
||||
(
|
||||
model_init_names,
|
||||
model_init_pos,
|
||||
annotation_fields,
|
||||
) = self.queryset.resolve_model_init_order()
|
||||
model_cls = self.queryset.model
|
||||
if model_cls._meta.pk.attname not in model_init_names:
|
||||
raise exceptions.FieldDoesNotExist(
|
||||
"Raw query must include the primary key"
|
||||
)
|
||||
fields = [self.queryset.model_fields.get(c) for c in self.queryset.columns]
|
||||
converters = compiler.get_converters(
|
||||
[f.get_col(f.model._meta.db_table) if f else None for f in fields]
|
||||
)
|
||||
if converters:
|
||||
query_iterator = compiler.apply_converters(query_iterator, converters)
|
||||
for values in query_iterator:
|
||||
# Associate fields to values
|
||||
model_init_values = [values[pos] for pos in model_init_pos]
|
||||
instance = model_cls.from_db(db, model_init_names, model_init_values)
|
||||
if annotation_fields:
|
||||
for column, pos in annotation_fields:
|
||||
setattr(instance, column, values[pos])
|
||||
yield instance
|
||||
finally:
|
||||
# Done iterating the Query. If it has its own cursor, close it.
|
||||
if hasattr(query, "cursor") and query.cursor:
|
||||
query.cursor.close()
|
||||
|
||||
|
||||
class ValuesIterable(BaseIterable):
|
||||
"""
|
||||
Iterable returned by QuerySet.values() that yields a dict for each row.
|
||||
|
@ -1994,41 +2038,7 @@ class RawQuerySet:
|
|||
return iter(self._result_cache)
|
||||
|
||||
def iterator(self):
|
||||
# Cache some things for performance reasons outside the loop.
|
||||
db = self.db
|
||||
connection = connections[db]
|
||||
compiler = connection.ops.compiler("SQLCompiler")(self.query, connection, db)
|
||||
query = iter(self.query)
|
||||
|
||||
try:
|
||||
(
|
||||
model_init_names,
|
||||
model_init_pos,
|
||||
annotation_fields,
|
||||
) = self.resolve_model_init_order()
|
||||
if self.model._meta.pk.attname not in model_init_names:
|
||||
raise exceptions.FieldDoesNotExist(
|
||||
"Raw query must include the primary key"
|
||||
)
|
||||
model_cls = self.model
|
||||
fields = [self.model_fields.get(c) for c in self.columns]
|
||||
converters = compiler.get_converters(
|
||||
[f.get_col(f.model._meta.db_table) if f else None for f in fields]
|
||||
)
|
||||
if converters:
|
||||
query = compiler.apply_converters(query, converters)
|
||||
for values in query:
|
||||
# Associate fields to values
|
||||
model_init_values = [values[pos] for pos in model_init_pos]
|
||||
instance = model_cls.from_db(db, model_init_names, model_init_values)
|
||||
if annotation_fields:
|
||||
for column, pos in annotation_fields:
|
||||
setattr(instance, column, values[pos])
|
||||
yield instance
|
||||
finally:
|
||||
# Done iterating the Query. If it has its own cursor, close it.
|
||||
if hasattr(self.query, "cursor") and self.query.cursor:
|
||||
self.query.cursor.close()
|
||||
yield from RawModelIterable(self)
|
||||
|
||||
def __repr__(self):
|
||||
return "<%s: %s>" % (self.__class__.__name__, self.query)
|
||||
|
|
Loading…
Reference in New Issue