cjm
cjm

Reputation: 493

Function to take a Django object and return it wrapped in a QuerySet?

How do I take a Django object and wrap it to become a QuerySet with one item?

m: SomeModel = SomeModel.objects.get(pk=8)

However, later functions expect m to be a QuerySet (even with a length of 1).

The answer below works for if you only need to wrap specific models, but is there a way to do something like the below pseudocode?

def generic_model2qs(m: Model) -> "QuerySet[Model]":
    return m.get_model().objects.filter(pk=m.pk)

Does Django have something like a .get_model() function?

Upvotes: 2

Views: 1525

Answers (1)

cjm
cjm

Reputation: 493

One way to do this is something like the below function

def wrap_some_model(m: SomeModel) -> "QuerySet[SomeModel]":
    return SomeModel.objects.filter(pk=m.pk)

However, this is not a generic case and would need to be re-implemented for each different model.


A more generic answer with hints from this answer for getting the model name from an unknown object that I have implemented for my own project:

def self_as_qs(s, model: Optional[models.Model] = None) -> "QuerySet[models.Model]":
    """
    Takes the input and returns it wrapped in a QuerySet
    :param s: the thing you want to transform
    :param model: optional specification to stop errors when using potentially-heterogeneous (nested) Iterables
    :return: A QuerySet representation of the input
    """

    # since you can't create a generic empty QuerySet
    generic_empty: QuerySet = model.objects.none() if model else SomeModel.objects.none()

    if isinstance(s, QuerySet) and not model:  # check inner QS if a model is specified
        return s  # it's already a QuerySet

    if isinstance(s, Iterable):
        # only works if all items are of the same model
        n = generic_empty
        for item in s:
            n = n | self_as_qs(item, model)  # handle nested lists
        return n

    if not s:
        return generic_empty
    if model and not isinstance(s, type(model.objects.all()[0])):
        return generic_empty

    # for future extensibility
    m = type(s)
    n = [s.pk]
    return m.objects.filter(pk__in=n)

Notes:

Upvotes: 2

Related Questions