2

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?

cjm
  • 451
  • 4
  • 20
  • 1
    This might answer the question: https://stackoverflow.com/questions/2064480/django-best-practice-way-to-get-model-from-an-instance-of-that-model – alecxe Nov 09 '19 at 18:39
  • @alecxe Indeed it does. I’ll edit my answer sometime later. – cjm Nov 09 '19 at 19:50
  • @alecxe I've edited my comment to incorporate that answer and make a much more full-featured function that I originally envisioned. – cjm Nov 11 '19 at 05:35

1 Answers1

2

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:

cjm
  • 451
  • 4
  • 20