We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Django template span has invalid description
### Environment

How do you use Sentry?
Self-hosted, version 21.2.0

Which SDK and version?
Python 1.0.0

### Steps to Reproduce

1. Set up performance tracing for a Django application
2. Send performance data for a view which is a subclass of `TemplateView`
3. View the performance information for the view in Sentry

### Expected Result

Sentry accepts all of the submitted performance data.

### Actual Result

The following alert appears above the performance information:

<img width="1304" alt="Sentry Error" src="https://user-images.githubusercontent.com/50265209/110369051-d15bf580-8017-11eb-80c4-b983385d9a21.png">

This is caused by #957.

At https://github.com/Christophe31/sentry-python/blob/db2d87e503b0178a7d56bdedb00db19ac6ddc9d8/sentry_sdk/integrations/django/templates.py#L60, a span is created with the description `self.template_name`. If the `TemplateResponse` was created by a Django `TemplateView`, `template_name` will be a list, not a string.

A similar error can occur with `django.shortcuts.render`, but I don't use it, so I haven't experienced the issue there.


--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `sentry_sdk/integrations/django/templates.py`
Content:
```
1 from django.template import TemplateSyntaxError
2 from django import VERSION as DJANGO_VERSION
3 
4 from sentry_sdk import _functools, Hub
5 from sentry_sdk._types import MYPY
6 
7 if MYPY:
8     from typing import Any
9     from typing import Dict
10     from typing import Optional
11     from typing import Iterator
12     from typing import Tuple
13 
14 try:
15     # support Django 1.9
16     from django.template.base import Origin
17 except ImportError:
18     # backward compatibility
19     from django.template.loader import LoaderOrigin as Origin
20 
21 
22 def get_template_frame_from_exception(exc_value):
23     # type: (Optional[BaseException]) -> Optional[Dict[str, Any]]
24 
25     # As of Django 1.9 or so the new template debug thing showed up.
26     if hasattr(exc_value, "template_debug"):
27         return _get_template_frame_from_debug(exc_value.template_debug)  # type: ignore
28 
29     # As of r16833 (Django) all exceptions may contain a
30     # ``django_template_source`` attribute (rather than the legacy
31     # ``TemplateSyntaxError.source`` check)
32     if hasattr(exc_value, "django_template_source"):
33         return _get_template_frame_from_source(
34             exc_value.django_template_source  # type: ignore
35         )
36 
37     if isinstance(exc_value, TemplateSyntaxError) and hasattr(exc_value, "source"):
38         source = exc_value.source
39         if isinstance(source, (tuple, list)) and isinstance(source[0], Origin):
40             return _get_template_frame_from_source(source)  # type: ignore
41 
42     return None
43 
44 
45 def patch_templates():
46     # type: () -> None
47     from django.template.response import SimpleTemplateResponse
48     from sentry_sdk.integrations.django import DjangoIntegration
49 
50     real_rendered_content = SimpleTemplateResponse.rendered_content
51 
52     @property  # type: ignore
53     def rendered_content(self):
54         # type: (SimpleTemplateResponse) -> str
55         hub = Hub.current
56         if hub.get_integration(DjangoIntegration) is None:
57             return real_rendered_content.fget(self)
58 
59         with hub.start_span(
60             op="django.template.render", description=self.template_name
61         ) as span:
62             span.set_data("context", self.context_data)
63             return real_rendered_content.fget(self)
64 
65     SimpleTemplateResponse.rendered_content = rendered_content
66 
67     if DJANGO_VERSION < (1, 7):
68         return
69     import django.shortcuts
70 
71     real_render = django.shortcuts.render
72 
73     @_functools.wraps(real_render)
74     def render(request, template_name, context=None, *args, **kwargs):
75         # type: (django.http.HttpRequest, str, Optional[Dict[str, Any]], *Any, **Any) -> django.http.HttpResponse
76         hub = Hub.current
77         if hub.get_integration(DjangoIntegration) is None:
78             return real_render(request, template_name, context, *args, **kwargs)
79 
80         with hub.start_span(
81             op="django.template.render", description=template_name
82         ) as span:
83             span.set_data("context", context)
84             return real_render(request, template_name, context, *args, **kwargs)
85 
86     django.shortcuts.render = render
87 
88 
89 def _get_template_frame_from_debug(debug):
90     # type: (Dict[str, Any]) -> Dict[str, Any]
91     if debug is None:
92         return None
93 
94     lineno = debug["line"]
95     filename = debug["name"]
96     if filename is None:
97         filename = "<django template>"
98 
99     pre_context = []
100     post_context = []
101     context_line = None
102 
103     for i, line in debug["source_lines"]:
104         if i < lineno:
105             pre_context.append(line)
106         elif i > lineno:
107             post_context.append(line)
108         else:
109             context_line = line
110 
111     return {
112         "filename": filename,
113         "lineno": lineno,
114         "pre_context": pre_context[-5:],
115         "post_context": post_context[:5],
116         "context_line": context_line,
117         "in_app": True,
118     }
119 
120 
121 def _linebreak_iter(template_source):
122     # type: (str) -> Iterator[int]
123     yield 0
124     p = template_source.find("\n")
125     while p >= 0:
126         yield p + 1
127         p = template_source.find("\n", p + 1)
128 
129 
130 def _get_template_frame_from_source(source):
131     # type: (Tuple[Origin, Tuple[int, int]]) -> Optional[Dict[str, Any]]
132     if not source:
133         return None
134 
135     origin, (start, end) = source
136     filename = getattr(origin, "loadname", None)
137     if filename is None:
138         filename = "<django template>"
139     template_source = origin.reload()
140     lineno = None
141     upto = 0
142     pre_context = []
143     post_context = []
144     context_line = None
145 
146     for num, next in enumerate(_linebreak_iter(template_source)):
147         line = template_source[upto:next]
148         if start >= upto and end <= next:
149             lineno = num
150             context_line = line
151         elif lineno is None:
152             pre_context.append(line)
153         else:
154             post_context.append(line)
155 
156         upto = next
157 
158     if context_line is None or lineno is None:
159         return None
160 
161     return {
162         "filename": filename,
163         "lineno": lineno,
164         "pre_context": pre_context[-5:],
165         "post_context": post_context[:5],
166         "context_line": context_line,
167     }
168
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/sentry_sdk/integrations/django/templates.py b/sentry_sdk/integrations/django/templates.py
--- a/sentry_sdk/integrations/django/templates.py
+++ b/sentry_sdk/integrations/django/templates.py
@@ -42,6 +42,15 @@
     return None
 
 
+def _get_template_name_description(template_name):
+    # type: (str) -> str
+    if isinstance(template_name, (list, tuple)):
+        if template_name:
+            return "[{}, ...]".format(template_name[0])
+    else:
+        return template_name
+
+
 def patch_templates():
     # type: () -> None
     from django.template.response import SimpleTemplateResponse
@@ -57,7 +66,8 @@
             return real_rendered_content.fget(self)
 
         with hub.start_span(
-            op="django.template.render", description=self.template_name
+            op="django.template.render",
+            description=_get_template_name_description(self.template_name),
         ) as span:
             span.set_data("context", self.context_data)
             return real_rendered_content.fget(self)
@@ -78,7 +88,8 @@
             return real_render(request, template_name, context, *args, **kwargs)
 
         with hub.start_span(
-            op="django.template.render", description=template_name
+            op="django.template.render",
+            description=_get_template_name_description(template_name),
         ) as span:
             span.set_data("context", context)
             return real_render(request, template_name, context, *args, **kwargs)

{"golden_diff": "diff --git a/sentry_sdk/integrations/django/templates.py b/sentry_sdk/integrations/django/templates.py\n--- a/sentry_sdk/integrations/django/templates.py\n+++ b/sentry_sdk/integrations/django/templates.py\n@@ -42,6 +42,15 @@\n     return None\n \n \n+def _get_template_name_description(template_name):\n+    # type: (str) -> str\n+    if isinstance(template_name, (list, tuple)):\n+        if template_name:\n+            return \"[{}, ...]\".format(template_name[0])\n+    else:\n+        return template_name\n+\n+\n def patch_templates():\n     # type: () -> None\n     from django.template.response import SimpleTemplateResponse\n@@ -57,7 +66,8 @@\n             return real_rendered_content.fget(self)\n \n         with hub.start_span(\n-            op=\"django.template.render\", description=self.template_name\n+            op=\"django.template.render\",\n+            description=_get_template_name_description(self.template_name),\n         ) as span:\n             span.set_data(\"context\", self.context_data)\n             return real_rendered_content.fget(self)\n@@ -78,7 +88,8 @@\n             return real_render(request, template_name, context, *args, **kwargs)\n \n         with hub.start_span(\n-            op=\"django.template.render\", description=template_name\n+            op=\"django.template.render\",\n+            description=_get_template_name_description(template_name),\n         ) as span:\n             span.set_data(\"context\", context)\n             return real_render(request, template_name, context, *args, **kwargs)\n", "issue": "Django template span has invalid description\n### Environment\r\n\r\nHow do you use Sentry?\r\nSelf-hosted, version 21.2.0\r\n\r\nWhich SDK and version?\r\nPython 1.0.0\r\n\r\n### Steps to Reproduce\r\n\r\n1. Set up performance tracing for a Django application\r\n2. Send performance data for a view which is a subclass of `TemplateView`\r\n3. View the performance information for the view in Sentry\r\n\r\n### Expected Result\r\n\r\nSentry accepts all of the submitted performance data.\r\n\r\n### Actual Result\r\n\r\nThe following alert appears above the performance information:\r\n\r\n<img width=\"1304\" alt=\"Sentry Error\" src=\"https://user-images.githubusercontent.com/50265209/110369051-d15bf580-8017-11eb-80c4-b983385d9a21.png\">\r\n\r\nThis is caused by #957.\r\n\r\nAt https://github.com/Christophe31/sentry-python/blob/db2d87e503b0178a7d56bdedb00db19ac6ddc9d8/sentry_sdk/integrations/django/templates.py#L60, a span is created with the description `self.template_name`. If the `TemplateResponse` was created by a Django `TemplateView`, `template_name` will be a list, not a string.\r\n\r\nA similar error can occur with `django.shortcuts.render`, but I don't use it, so I haven't experienced the issue there.\r\n\n", "before_files": [{"content": "from django.template import TemplateSyntaxError\nfrom django import VERSION as DJANGO_VERSION\n\nfrom sentry_sdk import _functools, Hub\nfrom sentry_sdk._types import MYPY\n\nif MYPY:\n    from typing import Any\n    from typing import Dict\n    from typing import Optional\n    from typing import Iterator\n    from typing import Tuple\n\ntry:\n    # support Django 1.9\n    from django.template.base import Origin\nexcept ImportError:\n    # backward compatibility\n    from django.template.loader import LoaderOrigin as Origin\n\n\ndef get_template_frame_from_exception(exc_value):\n    # type: (Optional[BaseException]) -> Optional[Dict[str, Any]]\n\n    # As of Django 1.9 or so the new template debug thing showed up.\n    if hasattr(exc_value, \"template_debug\"):\n        return _get_template_frame_from_debug(exc_value.template_debug)  # type: ignore\n\n    # As of r16833 (Django) all exceptions may contain a\n    # ``django_template_source`` attribute (rather than the legacy\n    # ``TemplateSyntaxError.source`` check)\n    if hasattr(exc_value, \"django_template_source\"):\n        return _get_template_frame_from_source(\n            exc_value.django_template_source  # type: ignore\n        )\n\n    if isinstance(exc_value, TemplateSyntaxError) and hasattr(exc_value, \"source\"):\n        source = exc_value.source\n        if isinstance(source, (tuple, list)) and isinstance(source[0], Origin):\n            return _get_template_frame_from_source(source)  # type: ignore\n\n    return None\n\n\ndef patch_templates():\n    # type: () -> None\n    from django.template.response import SimpleTemplateResponse\n    from sentry_sdk.integrations.django import DjangoIntegration\n\n    real_rendered_content = SimpleTemplateResponse.rendered_content\n\n    @property  # type: ignore\n    def rendered_content(self):\n        # type: (SimpleTemplateResponse) -> str\n        hub = Hub.current\n        if hub.get_integration(DjangoIntegration) is None:\n            return real_rendered_content.fget(self)\n\n        with hub.start_span(\n            op=\"django.template.render\", description=self.template_name\n        ) as span:\n            span.set_data(\"context\", self.context_data)\n            return real_rendered_content.fget(self)\n\n    SimpleTemplateResponse.rendered_content = rendered_content\n\n    if DJANGO_VERSION < (1, 7):\n        return\n    import django.shortcuts\n\n    real_render = django.shortcuts.render\n\n    @_functools.wraps(real_render)\n    def render(request, template_name, context=None, *args, **kwargs):\n        # type: (django.http.HttpRequest, str, Optional[Dict[str, Any]], *Any, **Any) -> django.http.HttpResponse\n        hub = Hub.current\n        if hub.get_integration(DjangoIntegration) is None:\n            return real_render(request, template_name, context, *args, **kwargs)\n\n        with hub.start_span(\n            op=\"django.template.render\", description=template_name\n        ) as span:\n            span.set_data(\"context\", context)\n            return real_render(request, template_name, context, *args, **kwargs)\n\n    django.shortcuts.render = render\n\n\ndef _get_template_frame_from_debug(debug):\n    # type: (Dict[str, Any]) -> Dict[str, Any]\n    if debug is None:\n        return None\n\n    lineno = debug[\"line\"]\n    filename = debug[\"name\"]\n    if filename is None:\n        filename = \"<django template>\"\n\n    pre_context = []\n    post_context = []\n    context_line = None\n\n    for i, line in debug[\"source_lines\"]:\n        if i < lineno:\n            pre_context.append(line)\n        elif i > lineno:\n            post_context.append(line)\n        else:\n            context_line = line\n\n    return {\n        \"filename\": filename,\n        \"lineno\": lineno,\n        \"pre_context\": pre_context[-5:],\n        \"post_context\": post_context[:5],\n        \"context_line\": context_line,\n        \"in_app\": True,\n    }\n\n\ndef _linebreak_iter(template_source):\n    # type: (str) -> Iterator[int]\n    yield 0\n    p = template_source.find(\"\\n\")\n    while p >= 0:\n        yield p + 1\n        p = template_source.find(\"\\n\", p + 1)\n\n\ndef _get_template_frame_from_source(source):\n    # type: (Tuple[Origin, Tuple[int, int]]) -> Optional[Dict[str, Any]]\n    if not source:\n        return None\n\n    origin, (start, end) = source\n    filename = getattr(origin, \"loadname\", None)\n    if filename is None:\n        filename = \"<django template>\"\n    template_source = origin.reload()\n    lineno = None\n    upto = 0\n    pre_context = []\n    post_context = []\n    context_line = None\n\n    for num, next in enumerate(_linebreak_iter(template_source)):\n        line = template_source[upto:next]\n        if start >= upto and end <= next:\n            lineno = num\n            context_line = line\n        elif lineno is None:\n            pre_context.append(line)\n        else:\n            post_context.append(line)\n\n        upto = next\n\n    if context_line is None or lineno is None:\n        return None\n\n    return {\n        \"filename\": filename,\n        \"lineno\": lineno,\n        \"pre_context\": pre_context[-5:],\n        \"post_context\": post_context[:5],\n        \"context_line\": context_line,\n    }\n", "path": "sentry_sdk/integrations/django/templates.py"}], "after_files": [{"content": "from django.template import TemplateSyntaxError\nfrom django import VERSION as DJANGO_VERSION\n\nfrom sentry_sdk import _functools, Hub\nfrom sentry_sdk._types import MYPY\n\nif MYPY:\n    from typing import Any\n    from typing import Dict\n    from typing import Optional\n    from typing import Iterator\n    from typing import Tuple\n\ntry:\n    # support Django 1.9\n    from django.template.base import Origin\nexcept ImportError:\n    # backward compatibility\n    from django.template.loader import LoaderOrigin as Origin\n\n\ndef get_template_frame_from_exception(exc_value):\n    # type: (Optional[BaseException]) -> Optional[Dict[str, Any]]\n\n    # As of Django 1.9 or so the new template debug thing showed up.\n    if hasattr(exc_value, \"template_debug\"):\n        return _get_template_frame_from_debug(exc_value.template_debug)  # type: ignore\n\n    # As of r16833 (Django) all exceptions may contain a\n    # ``django_template_source`` attribute (rather than the legacy\n    # ``TemplateSyntaxError.source`` check)\n    if hasattr(exc_value, \"django_template_source\"):\n        return _get_template_frame_from_source(\n            exc_value.django_template_source  # type: ignore\n        )\n\n    if isinstance(exc_value, TemplateSyntaxError) and hasattr(exc_value, \"source\"):\n        source = exc_value.source\n        if isinstance(source, (tuple, list)) and isinstance(source[0], Origin):\n            return _get_template_frame_from_source(source)  # type: ignore\n\n    return None\n\n\ndef _get_template_name_description(template_name):\n    # type: (str) -> str\n    if isinstance(template_name, (list, tuple)):\n        if template_name:\n            return \"[{}, ...]\".format(template_name[0])\n    else:\n        return template_name\n\n\ndef patch_templates():\n    # type: () -> None\n    from django.template.response import SimpleTemplateResponse\n    from sentry_sdk.integrations.django import DjangoIntegration\n\n    real_rendered_content = SimpleTemplateResponse.rendered_content\n\n    @property  # type: ignore\n    def rendered_content(self):\n        # type: (SimpleTemplateResponse) -> str\n        hub = Hub.current\n        if hub.get_integration(DjangoIntegration) is None:\n            return real_rendered_content.fget(self)\n\n        with hub.start_span(\n            op=\"django.template.render\",\n            description=_get_template_name_description(self.template_name),\n        ) as span:\n            span.set_data(\"context\", self.context_data)\n            return real_rendered_content.fget(self)\n\n    SimpleTemplateResponse.rendered_content = rendered_content\n\n    if DJANGO_VERSION < (1, 7):\n        return\n    import django.shortcuts\n\n    real_render = django.shortcuts.render\n\n    @_functools.wraps(real_render)\n    def render(request, template_name, context=None, *args, **kwargs):\n        # type: (django.http.HttpRequest, str, Optional[Dict[str, Any]], *Any, **Any) -> django.http.HttpResponse\n        hub = Hub.current\n        if hub.get_integration(DjangoIntegration) is None:\n            return real_render(request, template_name, context, *args, **kwargs)\n\n        with hub.start_span(\n            op=\"django.template.render\",\n            description=_get_template_name_description(template_name),\n        ) as span:\n            span.set_data(\"context\", context)\n            return real_render(request, template_name, context, *args, **kwargs)\n\n    django.shortcuts.render = render\n\n\ndef _get_template_frame_from_debug(debug):\n    # type: (Dict[str, Any]) -> Dict[str, Any]\n    if debug is None:\n        return None\n\n    lineno = debug[\"line\"]\n    filename = debug[\"name\"]\n    if filename is None:\n        filename = \"<django template>\"\n\n    pre_context = []\n    post_context = []\n    context_line = None\n\n    for i, line in debug[\"source_lines\"]:\n        if i < lineno:\n            pre_context.append(line)\n        elif i > lineno:\n            post_context.append(line)\n        else:\n            context_line = line\n\n    return {\n        \"filename\": filename,\n        \"lineno\": lineno,\n        \"pre_context\": pre_context[-5:],\n        \"post_context\": post_context[:5],\n        \"context_line\": context_line,\n        \"in_app\": True,\n    }\n\n\ndef _linebreak_iter(template_source):\n    # type: (str) -> Iterator[int]\n    yield 0\n    p = template_source.find(\"\\n\")\n    while p >= 0:\n        yield p + 1\n        p = template_source.find(\"\\n\", p + 1)\n\n\ndef _get_template_frame_from_source(source):\n    # type: (Tuple[Origin, Tuple[int, int]]) -> Optional[Dict[str, Any]]\n    if not source:\n        return None\n\n    origin, (start, end) = source\n    filename = getattr(origin, \"loadname\", None)\n    if filename is None:\n        filename = \"<django template>\"\n    template_source = origin.reload()\n    lineno = None\n    upto = 0\n    pre_context = []\n    post_context = []\n    context_line = None\n\n    for num, next in enumerate(_linebreak_iter(template_source)):\n        line = template_source[upto:next]\n        if start >= upto and end <= next:\n            lineno = num\n            context_line = line\n        elif lineno is None:\n            pre_context.append(line)\n        else:\n            post_context.append(line)\n\n        upto = next\n\n    if context_line is None or lineno is None:\n        return None\n\n    return {\n        \"filename\": filename,\n        \"lineno\": lineno,\n        \"pre_context\": pre_context[-5:],\n        \"post_context\": post_context[:5],\n        \"context_line\": context_line,\n    }\n", "path": "sentry_sdk/integrations/django/templates.py"}]}