mirror of
				https://github.com/netbox-community/netbox.git
				synced 2024-05-10 07:54:54 +00:00 
			
		
		
		
	Closes #5608: Add REST API endpoint for custom links
This commit is contained in:
		@@ -43,6 +43,7 @@ The ObjectChange model (which is used to record the creation, modification, and
 | 
			
		||||
* [#5375](https://github.com/netbox-community/netbox/issues/5375) - Add `speed` attribute to console port models
 | 
			
		||||
* [#5401](https://github.com/netbox-community/netbox/issues/5401) - Extend custom field support to device component models
 | 
			
		||||
* [#5451](https://github.com/netbox-community/netbox/issues/5451) - Add support for multiple-selection custom fields
 | 
			
		||||
* [#5608](https://github.com/netbox-community/netbox/issues/5608) - Add REST API endpoint for custom links
 | 
			
		||||
* [#5894](https://github.com/netbox-community/netbox/issues/5894) - Use primary keys when filtering object lists by related objects in the UI
 | 
			
		||||
* [#5895](https://github.com/netbox-community/netbox/issues/5895) - Rename RackGroup to Location
 | 
			
		||||
* [#5901](https://github.com/netbox-community/netbox/issues/5901) - Add `created` and `last_updated` fields to device component models
 | 
			
		||||
@@ -83,6 +84,8 @@ The ObjectChange model (which is used to record the creation, modification, and
 | 
			
		||||
  * Added the `site_groups` many-to-many field to track the assignment of ConfigContexts to SiteGroups
 | 
			
		||||
* extras.CustomField
 | 
			
		||||
  * Added new custom field type: `multi-select`
 | 
			
		||||
* extras.CustomLink
 | 
			
		||||
  * Added the `/api/extras/custom-links/` endpoint
 | 
			
		||||
* extras.ObjectChange
 | 
			
		||||
  * Added the `prechange_data` field
 | 
			
		||||
  * Renamed `object_data` to `postchange_data`
 | 
			
		||||
 
 | 
			
		||||
@@ -132,15 +132,15 @@ class CustomLinkForm(forms.ModelForm):
 | 
			
		||||
        model = CustomLink
 | 
			
		||||
        exclude = []
 | 
			
		||||
        widgets = {
 | 
			
		||||
            'text': forms.Textarea,
 | 
			
		||||
            'url': forms.Textarea,
 | 
			
		||||
            'link_text': forms.Textarea,
 | 
			
		||||
            'link_url': forms.Textarea,
 | 
			
		||||
        }
 | 
			
		||||
        help_texts = {
 | 
			
		||||
            'weight': 'A numeric weight to influence the ordering of this link among its peers. Lower weights appear '
 | 
			
		||||
                      'first in a list.',
 | 
			
		||||
            'text': 'Jinja2 template code for the link text. Reference the object as <code>{{ obj }}</code>. Links '
 | 
			
		||||
                    'which render as empty text will not be displayed.',
 | 
			
		||||
            'url': 'Jinja2 template code for the link URL. Reference the object as <code>{{ obj }}</code>.',
 | 
			
		||||
            'link_text': 'Jinja2 template code for the link text. Reference the object as <code>{{ obj }}</code>. '
 | 
			
		||||
                         'Links which render as empty text will not be displayed.',
 | 
			
		||||
            'link_url': 'Jinja2 template code for the link URL. Reference the object as <code>{{ obj }}</code>.',
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
    def __init__(self, *args, **kwargs):
 | 
			
		||||
@@ -158,7 +158,7 @@ class CustomLinkAdmin(admin.ModelAdmin):
 | 
			
		||||
            'fields': ('content_type', 'name', 'group_name', 'weight', 'button_class', 'new_window')
 | 
			
		||||
        }),
 | 
			
		||||
        ('Templates', {
 | 
			
		||||
            'fields': ('text', 'url'),
 | 
			
		||||
            'fields': ('link_text', 'link_url'),
 | 
			
		||||
            'classes': ('monospace',)
 | 
			
		||||
        })
 | 
			
		||||
    )
 | 
			
		||||
 
 | 
			
		||||
@@ -7,6 +7,7 @@ from users.api.nested_serializers import NestedUserSerializer
 | 
			
		||||
__all__ = [
 | 
			
		||||
    'NestedConfigContextSerializer',
 | 
			
		||||
    'NestedCustomFieldSerializer',
 | 
			
		||||
    'NestedCustomLinkSerializer',
 | 
			
		||||
    'NestedExportTemplateSerializer',
 | 
			
		||||
    'NestedImageAttachmentSerializer',
 | 
			
		||||
    'NestedJobResultSerializer',
 | 
			
		||||
@@ -22,6 +23,14 @@ class NestedCustomFieldSerializer(WritableNestedSerializer):
 | 
			
		||||
        fields = ['id', 'url', 'name']
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class NestedCustomLinkSerializer(WritableNestedSerializer):
 | 
			
		||||
    url = serializers.HyperlinkedIdentityField(view_name='extras-api:customlink-detail')
 | 
			
		||||
 | 
			
		||||
    class Meta:
 | 
			
		||||
        model = models.CustomLink
 | 
			
		||||
        fields = ['id', 'url', 'name']
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class NestedConfigContextSerializer(WritableNestedSerializer):
 | 
			
		||||
    url = serializers.HyperlinkedIdentityField(view_name='extras-api:configcontext-detail')
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -10,7 +10,7 @@ from dcim.api.nested_serializers import (
 | 
			
		||||
from dcim.models import Device, DeviceRole, Platform, Rack, Region, Site, SiteGroup
 | 
			
		||||
from extras.choices import *
 | 
			
		||||
from extras.models import (
 | 
			
		||||
    ConfigContext, CustomField, ExportTemplate, ImageAttachment, ObjectChange, JobResult, Tag,
 | 
			
		||||
    ConfigContext, CustomField, CustomLink, ExportTemplate, ImageAttachment, ObjectChange, JobResult, Tag,
 | 
			
		||||
)
 | 
			
		||||
from extras.utils import FeatureQuery
 | 
			
		||||
from netbox.api import ChoiceField, ContentTypeField, SerializedPKRelatedField, ValidatedModelSerializer
 | 
			
		||||
@@ -45,6 +45,24 @@ class CustomFieldSerializer(ValidatedModelSerializer):
 | 
			
		||||
        ]
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#
 | 
			
		||||
# Custom links
 | 
			
		||||
#
 | 
			
		||||
 | 
			
		||||
class CustomLinkSerializer(ValidatedModelSerializer):
 | 
			
		||||
    url = serializers.HyperlinkedIdentityField(view_name='extras-api:customlink-detail')
 | 
			
		||||
    content_type = ContentTypeField(
 | 
			
		||||
        queryset=ContentType.objects.filter(FeatureQuery('custom_links').get_query())
 | 
			
		||||
    )
 | 
			
		||||
 | 
			
		||||
    class Meta:
 | 
			
		||||
        model = CustomLink
 | 
			
		||||
        fields = [
 | 
			
		||||
            'id', 'url', 'content_type', 'name', 'link_text', 'link_url', 'weight', 'group_name', 'button_class',
 | 
			
		||||
            'new_window',
 | 
			
		||||
        ]
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#
 | 
			
		||||
# Export templates
 | 
			
		||||
#
 | 
			
		||||
 
 | 
			
		||||
@@ -8,6 +8,9 @@ router.APIRootView = views.ExtrasRootView
 | 
			
		||||
# Custom fields
 | 
			
		||||
router.register('custom-fields', views.CustomFieldViewSet)
 | 
			
		||||
 | 
			
		||||
# Custom links
 | 
			
		||||
router.register('custom-links', views.CustomLinkViewSet)
 | 
			
		||||
 | 
			
		||||
# Export templates
 | 
			
		||||
router.register('export-templates', views.ExportTemplateViewSet)
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -12,7 +12,7 @@ from rq import Worker
 | 
			
		||||
from extras import filters
 | 
			
		||||
from extras.choices import JobResultStatusChoices
 | 
			
		||||
from extras.models import (
 | 
			
		||||
    ConfigContext, ExportTemplate, ImageAttachment, ObjectChange, JobResult, Tag, TaggedItem,
 | 
			
		||||
    ConfigContext, CustomLink, ExportTemplate, ImageAttachment, ObjectChange, JobResult, Tag, TaggedItem,
 | 
			
		||||
)
 | 
			
		||||
from extras.models import CustomField
 | 
			
		||||
from extras.reports import get_report, get_reports, run_report
 | 
			
		||||
@@ -84,6 +84,17 @@ class CustomFieldModelViewSet(ModelViewSet):
 | 
			
		||||
        return context
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#
 | 
			
		||||
# Custom links
 | 
			
		||||
#
 | 
			
		||||
 | 
			
		||||
class CustomLinkViewSet(ModelViewSet):
 | 
			
		||||
    metadata_class = ContentTypeMetadata
 | 
			
		||||
    queryset = CustomLink.objects.all()
 | 
			
		||||
    serializer_class = serializers.CustomLinkSerializer
 | 
			
		||||
    filterset_class = filters.CustomLinkFilterSet
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#
 | 
			
		||||
# Export templates
 | 
			
		||||
#
 | 
			
		||||
 
 | 
			
		||||
@@ -9,7 +9,9 @@ from tenancy.models import Tenant, TenantGroup
 | 
			
		||||
from utilities.filters import BaseFilterSet, ContentTypeFilter
 | 
			
		||||
from virtualization.models import Cluster, ClusterGroup
 | 
			
		||||
from .choices import *
 | 
			
		||||
from .models import ConfigContext, CustomField, ExportTemplate, ImageAttachment, JobResult, ObjectChange, Tag
 | 
			
		||||
from .models import (
 | 
			
		||||
    ConfigContext, CustomField, CustomLink, ExportTemplate, ImageAttachment, JobResult, ObjectChange, Tag,
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
__all__ = (
 | 
			
		||||
@@ -17,6 +19,7 @@ __all__ = (
 | 
			
		||||
    'ContentTypeFilterSet',
 | 
			
		||||
    'CreatedUpdatedFilterSet',
 | 
			
		||||
    'CustomFieldFilter',
 | 
			
		||||
    'CustomLinkFilterSet',
 | 
			
		||||
    'CustomFieldModelFilterSet',
 | 
			
		||||
    'ExportTemplateFilterSet',
 | 
			
		||||
    'ImageAttachmentFilterSet',
 | 
			
		||||
@@ -79,6 +82,13 @@ class CustomFieldFilterSet(django_filters.FilterSet):
 | 
			
		||||
        fields = ['id', 'content_types', 'name', 'required', 'filter_logic', 'weight']
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class CustomLinkFilterSet(BaseFilterSet):
 | 
			
		||||
 | 
			
		||||
    class Meta:
 | 
			
		||||
        model = CustomLink
 | 
			
		||||
        fields = ['id', 'content_type', 'name', 'link_text', 'link_url', 'weight', 'group_name', 'new_window']
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class ExportTemplateFilterSet(BaseFilterSet):
 | 
			
		||||
 | 
			
		||||
    class Meta:
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										28
									
								
								netbox/extras/migrations/0057_customlink_rename_fields.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										28
									
								
								netbox/extras/migrations/0057_customlink_rename_fields.py
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,28 @@
 | 
			
		||||
# Generated by Django 3.2b1 on 2021-03-09 01:42
 | 
			
		||||
 | 
			
		||||
from django.db import migrations, models
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class Migration(migrations.Migration):
 | 
			
		||||
 | 
			
		||||
    dependencies = [
 | 
			
		||||
        ('extras', '0056_sitegroup'),
 | 
			
		||||
    ]
 | 
			
		||||
 | 
			
		||||
    operations = [
 | 
			
		||||
        migrations.RenameField(
 | 
			
		||||
            model_name='customlink',
 | 
			
		||||
            old_name='text',
 | 
			
		||||
            new_name='link_text',
 | 
			
		||||
        ),
 | 
			
		||||
        migrations.RenameField(
 | 
			
		||||
            model_name='customlink',
 | 
			
		||||
            old_name='url',
 | 
			
		||||
            new_name='link_url',
 | 
			
		||||
        ),
 | 
			
		||||
        migrations.AlterField(
 | 
			
		||||
            model_name='customlink',
 | 
			
		||||
            name='new_window',
 | 
			
		||||
            field=models.BooleanField(default=False),
 | 
			
		||||
        ),
 | 
			
		||||
    ]
 | 
			
		||||
@@ -172,13 +172,13 @@ class CustomLink(BigIDModel):
 | 
			
		||||
        max_length=100,
 | 
			
		||||
        unique=True
 | 
			
		||||
    )
 | 
			
		||||
    text = models.CharField(
 | 
			
		||||
    link_text = models.CharField(
 | 
			
		||||
        max_length=500,
 | 
			
		||||
        help_text="Jinja2 template code for link text"
 | 
			
		||||
    )
 | 
			
		||||
    url = models.CharField(
 | 
			
		||||
    link_url = models.CharField(
 | 
			
		||||
        max_length=500,
 | 
			
		||||
        verbose_name='URL',
 | 
			
		||||
        verbose_name='Link URL',
 | 
			
		||||
        help_text="Jinja2 template code for link URL"
 | 
			
		||||
    )
 | 
			
		||||
    weight = models.PositiveSmallIntegerField(
 | 
			
		||||
@@ -196,9 +196,12 @@ class CustomLink(BigIDModel):
 | 
			
		||||
        help_text="The class of the first link in a group will be used for the dropdown button"
 | 
			
		||||
    )
 | 
			
		||||
    new_window = models.BooleanField(
 | 
			
		||||
        default=False,
 | 
			
		||||
        help_text="Force link to open in a new window"
 | 
			
		||||
    )
 | 
			
		||||
 | 
			
		||||
    objects = RestrictedQuerySet.as_manager()
 | 
			
		||||
 | 
			
		||||
    class Meta:
 | 
			
		||||
        ordering = ['group_name', 'weight', 'name']
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -52,9 +52,9 @@ def custom_links(context, obj):
 | 
			
		||||
        # Add non-grouped links
 | 
			
		||||
        else:
 | 
			
		||||
            try:
 | 
			
		||||
                text_rendered = render_jinja2(cl.text, link_context)
 | 
			
		||||
                text_rendered = render_jinja2(cl.link_text, link_context)
 | 
			
		||||
                if text_rendered:
 | 
			
		||||
                    link_rendered = render_jinja2(cl.url, link_context)
 | 
			
		||||
                    link_rendered = render_jinja2(cl.link_url, link_context)
 | 
			
		||||
                    link_target = ' target="_blank"' if cl.new_window else ''
 | 
			
		||||
                    template_code += LINK_BUTTON.format(
 | 
			
		||||
                        link_rendered, link_target, cl.button_class, text_rendered
 | 
			
		||||
@@ -70,10 +70,10 @@ def custom_links(context, obj):
 | 
			
		||||
 | 
			
		||||
        for cl in links:
 | 
			
		||||
            try:
 | 
			
		||||
                text_rendered = render_jinja2(cl.text, link_context)
 | 
			
		||||
                text_rendered = render_jinja2(cl.link_text, link_context)
 | 
			
		||||
                if text_rendered:
 | 
			
		||||
                    link_target = ' target="_blank"' if cl.new_window else ''
 | 
			
		||||
                    link_rendered = render_jinja2(cl.url, link_context)
 | 
			
		||||
                    link_rendered = render_jinja2(cl.link_url, link_context)
 | 
			
		||||
                    links_rendered.append(
 | 
			
		||||
                        GROUP_LINK.format(link_rendered, link_target, text_rendered)
 | 
			
		||||
                    )
 | 
			
		||||
 
 | 
			
		||||
@@ -11,7 +11,7 @@ from rq import Worker
 | 
			
		||||
 | 
			
		||||
from dcim.models import Device, DeviceRole, DeviceType, Manufacturer, Rack, Location, RackRole, Site
 | 
			
		||||
from extras.api.views import ReportViewSet, ScriptViewSet
 | 
			
		||||
from extras.models import ConfigContext, CustomField, ExportTemplate, ImageAttachment, Tag
 | 
			
		||||
from extras.models import ConfigContext, CustomField, CustomLink, ExportTemplate, ImageAttachment, Tag
 | 
			
		||||
from extras.reports import Report
 | 
			
		||||
from extras.scripts import BooleanVar, IntegerVar, Script, StringVar
 | 
			
		||||
from utilities.testing import APITestCase, APIViewTestCases
 | 
			
		||||
@@ -77,6 +77,60 @@ class CustomFieldTest(APIViewTestCases.APIViewTestCase):
 | 
			
		||||
            cf.content_types.add(site_ct)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class CustomLinkTest(APIViewTestCases.APIViewTestCase):
 | 
			
		||||
    model = CustomLink
 | 
			
		||||
    brief_fields = ['id', 'name', 'url']
 | 
			
		||||
    create_data = [
 | 
			
		||||
        {
 | 
			
		||||
            'content_type': 'dcim.site',
 | 
			
		||||
            'name': 'Custom Link 4',
 | 
			
		||||
            'link_text': 'Link 4',
 | 
			
		||||
            'link_url': 'http://example.com/?4',
 | 
			
		||||
        },
 | 
			
		||||
        {
 | 
			
		||||
            'content_type': 'dcim.site',
 | 
			
		||||
            'name': 'Custom Link 5',
 | 
			
		||||
            'link_text': 'Link 5',
 | 
			
		||||
            'link_url': 'http://example.com/?5',
 | 
			
		||||
        },
 | 
			
		||||
        {
 | 
			
		||||
            'content_type': 'dcim.site',
 | 
			
		||||
            'name': 'Custom Link 6',
 | 
			
		||||
            'link_text': 'Link 6',
 | 
			
		||||
            'link_url': 'http://example.com/?6',
 | 
			
		||||
        },
 | 
			
		||||
    ]
 | 
			
		||||
    bulk_update_data = {
 | 
			
		||||
        'new_window': True,
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @classmethod
 | 
			
		||||
    def setUpTestData(cls):
 | 
			
		||||
        site_ct = ContentType.objects.get_for_model(Site)
 | 
			
		||||
 | 
			
		||||
        custom_links = (
 | 
			
		||||
            CustomLink(
 | 
			
		||||
                content_type=site_ct,
 | 
			
		||||
                name='Custom Link 1',
 | 
			
		||||
                link_text='Link 1',
 | 
			
		||||
                link_url='http://example.com/?1',
 | 
			
		||||
            ),
 | 
			
		||||
            CustomLink(
 | 
			
		||||
                content_type=site_ct,
 | 
			
		||||
                name='Custom Link 2',
 | 
			
		||||
                link_text='Link 2',
 | 
			
		||||
                link_url='http://example.com/?2',
 | 
			
		||||
            ),
 | 
			
		||||
            CustomLink(
 | 
			
		||||
                content_type=site_ct,
 | 
			
		||||
                name='Custom Link 3',
 | 
			
		||||
                link_text='Link 3',
 | 
			
		||||
                link_url='http://example.com/?3',
 | 
			
		||||
            ),
 | 
			
		||||
        )
 | 
			
		||||
        CustomLink.objects.bulk_create(custom_links)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class ExportTemplateTest(APIViewTestCases.APIViewTestCase):
 | 
			
		||||
    model = ExportTemplate
 | 
			
		||||
    brief_fields = ['id', 'name', 'url']
 | 
			
		||||
 
 | 
			
		||||
@@ -7,12 +7,71 @@ from django.test import TestCase
 | 
			
		||||
from dcim.models import DeviceRole, Platform, Rack, Region, Site, SiteGroup
 | 
			
		||||
from extras.choices import ObjectChangeActionChoices
 | 
			
		||||
from extras.filters import *
 | 
			
		||||
from extras.models import ConfigContext, ExportTemplate, ImageAttachment, ObjectChange, Tag
 | 
			
		||||
from extras.models import ConfigContext, CustomLink, ExportTemplate, ImageAttachment, ObjectChange, Tag
 | 
			
		||||
from ipam.models import IPAddress
 | 
			
		||||
from tenancy.models import Tenant, TenantGroup
 | 
			
		||||
from virtualization.models import Cluster, ClusterGroup, ClusterType
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class CustomLinkTestCase(TestCase):
 | 
			
		||||
    queryset = CustomLink.objects.all()
 | 
			
		||||
    filterset = CustomLinkFilterSet
 | 
			
		||||
 | 
			
		||||
    @classmethod
 | 
			
		||||
    def setUpTestData(cls):
 | 
			
		||||
        content_types = ContentType.objects.filter(model__in=['site', 'rack', 'device'])
 | 
			
		||||
 | 
			
		||||
        custom_links = (
 | 
			
		||||
            CustomLink(
 | 
			
		||||
                name='Custom Link 1',
 | 
			
		||||
                content_type=content_types[0],
 | 
			
		||||
                weight=100,
 | 
			
		||||
                new_window=False,
 | 
			
		||||
                link_text='Link 1',
 | 
			
		||||
                link_url='http://example.com/?1'
 | 
			
		||||
            ),
 | 
			
		||||
            CustomLink(
 | 
			
		||||
                name='Custom Link 2',
 | 
			
		||||
                content_type=content_types[1],
 | 
			
		||||
                weight=200,
 | 
			
		||||
                new_window=False,
 | 
			
		||||
                link_text='Link 1',
 | 
			
		||||
                link_url='http://example.com/?2'
 | 
			
		||||
            ),
 | 
			
		||||
            CustomLink(
 | 
			
		||||
                name='Custom Link 3',
 | 
			
		||||
                content_type=content_types[2],
 | 
			
		||||
                weight=300,
 | 
			
		||||
                new_window=True,
 | 
			
		||||
                link_text='Link 1',
 | 
			
		||||
                link_url='http://example.com/?3'
 | 
			
		||||
            ),
 | 
			
		||||
        )
 | 
			
		||||
        CustomLink.objects.bulk_create(custom_links)
 | 
			
		||||
 | 
			
		||||
    def test_id(self):
 | 
			
		||||
        params = {'id': self.queryset.values_list('pk', flat=True)[:2]}
 | 
			
		||||
        self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
 | 
			
		||||
 | 
			
		||||
    def test_name(self):
 | 
			
		||||
        params = {'name': ['Custom Link 1', 'Custom Link 2']}
 | 
			
		||||
        self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
 | 
			
		||||
 | 
			
		||||
    def test_content_type(self):
 | 
			
		||||
        params = {'content_type': ContentType.objects.get(model='site').pk}
 | 
			
		||||
        self.assertEqual(self.filterset(params, self.queryset).qs.count(), 1)
 | 
			
		||||
 | 
			
		||||
    def test_weight(self):
 | 
			
		||||
        params = {'weight': [100, 200]}
 | 
			
		||||
        self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
 | 
			
		||||
 | 
			
		||||
    def test_new_window(self):
 | 
			
		||||
        params = {'new_window': False}
 | 
			
		||||
        self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
 | 
			
		||||
        params = {'new_window': True}
 | 
			
		||||
        self.assertEqual(self.filterset(params, self.queryset).qs.count(), 1)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class ExportTemplateTestCase(TestCase):
 | 
			
		||||
    queryset = ExportTemplate.objects.all()
 | 
			
		||||
    filterset = ExportTemplateFilterSet
 | 
			
		||||
 
 | 
			
		||||
@@ -135,8 +135,8 @@ class CustomLinkTest(TestCase):
 | 
			
		||||
        customlink = CustomLink(
 | 
			
		||||
            content_type=ContentType.objects.get_for_model(Site),
 | 
			
		||||
            name='Test',
 | 
			
		||||
            text='FOO {{ obj.name }} BAR',
 | 
			
		||||
            url='http://example.com/?site={{ obj.slug }}',
 | 
			
		||||
            link_text='FOO {{ obj.name }} BAR',
 | 
			
		||||
            link_url='http://example.com/?site={{ obj.slug }}',
 | 
			
		||||
            new_window=False
 | 
			
		||||
        )
 | 
			
		||||
        customlink.save()
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user