def get_value_data(self, value):
        # Given a data value (which may be None, a model instance, or a PK here),
        # extract the necessary data for rendering the widget with that value.
        # In the case of StreamField (in Wagtail >=2.13), this data will be serialised via
        # telepath https://wagtail.github.io/telepath/ to be rendered client-side, which means it
        # cannot include model instances. Instead, we return the raw values used in rendering -
        # namely: pk, display_markup and edit_url

        if value is None or isinstance(value, self.target_model):
            instance = value
        else:  # assume this is an instance ID
            instance = self.target_model.objects.get(pk=value)

        app_label = self.target_model._meta.app_label
        model_name = self.target_model._meta.model_name
        model = registry.get_model(app_label, model_name)
        instance_selector = registry.get_instance_selector(model)
        display_markup = instance_selector.get_instance_display_markup(
            instance)
        edit_url = instance_selector.get_instance_edit_url(instance)

        return {
            "pk": instance.pk if instance else None,
            "display_markup": display_markup,
            "edit_url": edit_url,
        }
    def render_html(self, name, value, attrs):
        original_field_html = super().render_html(name, value, attrs)

        instance, value = self.get_instance_and_id(self.target_model, value)

        app_label = self.target_model._meta.app_label
        model_name = self.target_model._meta.model_name
        model = registry.get_model(app_label, model_name)
        instance_selector = registry.get_instance_selector(model)

        embed_url = reverse(
            "wagtail_instance_selector_embed",
            kwargs={
                "app_label": app_label,
                "model_name": model_name
            },
        )
        # We use the input name for the embed id so that wagtail's block code will automatically
        # replace any `__prefix__` substring with a specific id for the widget instance
        embed_id = name
        embed_url += "#instance_selector_embed_id:" + embed_id

        lookup_url = reverse(
            "wagtail_instance_selector_lookup",
            kwargs={
                "app_label": app_label,
                "model_name": model_name
            },
        )

        display_markup = instance_selector.get_instance_display_markup(
            instance)
        edit_url = instance_selector.get_instance_edit_url(instance)

        return render_to_string(
            "instance_selector/instance_selector_widget.html",
            {
                "name": name,
                "value": value,
                "widget": self,
                "input_id": attrs["id"],
                "widget_id": "%s-instance-selector-widget" % attrs["id"],
                "original_field_html": original_field_html,
                "embed_url": embed_url,
                "embed_id": embed_id,
                "lookup_url": lookup_url,
                "OBJECT_PK_PARAM": OBJECT_PK_PARAM,
                "display_markup": display_markup,
                "edit_url": edit_url,
            },
        )
def instance_selector_embed(request, app_label, model_name):
    if not user_can_access_admin(request.user):
        raise PermissionDenied

    model = registry.get_model(app_label, model_name)
    instance_selector = registry.get_instance_selector(model)
    instance_selector_url = instance_selector.get_instance_selector_url()
    embed_id = slugify("%s-%s-%s" % (app_label, model_name, time.time()))
    embed_url = "%s#instance_selector_embed_id:%s" % (instance_selector_url,
                                                      embed_id)

    context = {"embed_url": embed_url, "embed_id": embed_id}
    return TemplateResponse(request,
                            "instance_selector/instance_selector_embed.html",
                            context)
def instance_selector_lookup(request, app_label, model_name):
    if not user_can_access_admin(request.user):
        raise PermissionDenied

    object_pk = request.GET.get(OBJECT_PK_PARAM)
    if not object_pk:
        return HttpResponseBadRequest("Param `%s` does have a value defined" %
                                      OBJECT_PK_PARAM)

    model = registry.get_model(app_label, model_name)
    instance = model.objects.get(pk=object_pk)
    instance_selector = registry.get_instance_selector(model)

    display_markup = instance_selector.get_instance_display_markup(instance)
    edit_url = instance_selector.get_instance_edit_url(instance)

    return JsonResponse({
        "display_markup": display_markup,
        "edit_url": edit_url,
        "pk": object_pk
    })
    def test_custom_model_can_be_registered(self):
        class Model:
            pass

        registry.register_model("foo", "bar", Model)
        self.assertEqual(registry.get_model("foo", "bar"), Model)
 def test_registry_throws_for_unknown_models(self):
     self.assertRaises(
         LookupError,
         lambda: registry.get_model("test_app", "SomeUnknownModel"))
 def test_registry_automatically_discovers_models(self):
     self.assertEqual(registry.get_model("test_app", "TestModelB"),
                      TestModelB)