mirror of
https://github.com/netbox-community/netbox.git
synced 2025-08-25 08:46:10 -06:00
Employ standard naming for Token view, form, table classes
This commit is contained in:
parent
d0c3c3f93b
commit
5064bd4574
@ -469,6 +469,7 @@ EXEMPT_EXCLUDE_MODELS = (
|
|||||||
('auth', 'group'),
|
('auth', 'group'),
|
||||||
('auth', 'user'),
|
('auth', 'user'),
|
||||||
('users', 'objectpermission'),
|
('users', 'objectpermission'),
|
||||||
|
('users', 'token'),
|
||||||
)
|
)
|
||||||
|
|
||||||
# All URLs starting with a string listed here are exempt from login enforcement
|
# All URLs starting with a string listed here are exempt from login enforcement
|
||||||
|
@ -34,7 +34,7 @@
|
|||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li>
|
||||||
<a class="dropdown-item" href="{% url 'users:token_list' %}">
|
<a class="dropdown-item" href="{% url 'users:usertoken_list' %}">
|
||||||
<i class="mdi mdi-key"></i> API Tokens
|
<i class="mdi mdi-key"></i> API Tokens
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
|
@ -3,6 +3,10 @@
|
|||||||
{% load helpers %}
|
{% load helpers %}
|
||||||
{% load plugins %}
|
{% load plugins %}
|
||||||
|
|
||||||
|
{% block breadcrumbs %}
|
||||||
|
<li class="breadcrumb-item"><a href="{% url 'users:usertoken_list' %}">Tokens</a></li>
|
||||||
|
{% endblock breadcrumbs %}
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col col-md-12">
|
<div class="col col-md-12">
|
||||||
@ -50,7 +54,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="col col-md-12 text-center">
|
<div class="col col-md-12 text-center">
|
||||||
<a href="{% url 'users:token_add' %}" class="btn btn-outline-primary">Add Another</a>
|
<a href="{% url 'users:usertoken_add' %}" class="btn btn-outline-primary">Add Another</a>
|
||||||
<a href="{{ return_url }}" class="btn btn-outline-danger">Cancel</a>
|
<a href="{{ return_url }}" class="btn btn-outline-danger">Cancel</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
{% block content %}
|
{% block content %}
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col col-md-12 text-end">
|
<div class="col col-md-12 text-end">
|
||||||
<a href="{% url 'users:token_add' %}" class="btn btn-sm btn-primary my-3">
|
<a href="{% url 'users:usertoken_add' %}" class="btn btn-sm btn-primary my-3">
|
||||||
<span class="mdi mdi-plus-thick" aria-hidden="true"></span> Add a Token
|
<span class="mdi mdi-plus-thick" aria-hidden="true"></span> Add a Token
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
|
@ -18,7 +18,7 @@
|
|||||||
</li>
|
</li>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
<li role="presentation" class="nav-item">
|
<li role="presentation" class="nav-item">
|
||||||
<a class="nav-link{% if active_tab == 'api-tokens' %} active{% endif %}" href="{% url 'users:token_list' %}">{% trans "API Tokens" %}</a>
|
<a class="nav-link{% if active_tab == 'api-tokens' %} active{% endif %}" href="{% url 'users:usertoken_list' %}">{% trans "API Tokens" %}</a>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
@ -12,7 +12,6 @@ __all__ = (
|
|||||||
'ObjectPermissionFilterSet',
|
'ObjectPermissionFilterSet',
|
||||||
'TokenFilterSet',
|
'TokenFilterSet',
|
||||||
'UserFilterSet',
|
'UserFilterSet',
|
||||||
'UserTokenFilterSet',
|
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@ -112,54 +111,6 @@ class TokenFilterSet(BaseFilterSet):
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
class UserTokenFilterSet(BaseFilterSet):
|
|
||||||
q = django_filters.CharFilter(
|
|
||||||
method='search',
|
|
||||||
label=_('Search'),
|
|
||||||
)
|
|
||||||
user_id = django_filters.ModelMultipleChoiceFilter(
|
|
||||||
field_name='user',
|
|
||||||
queryset=get_user_model().objects.all(),
|
|
||||||
label=_('User'),
|
|
||||||
)
|
|
||||||
user = django_filters.ModelMultipleChoiceFilter(
|
|
||||||
field_name='user__username',
|
|
||||||
queryset=get_user_model().objects.all(),
|
|
||||||
to_field_name='username',
|
|
||||||
label=_('User (name)'),
|
|
||||||
)
|
|
||||||
created = django_filters.DateTimeFilter()
|
|
||||||
created__gte = django_filters.DateTimeFilter(
|
|
||||||
field_name='created',
|
|
||||||
lookup_expr='gte'
|
|
||||||
)
|
|
||||||
created__lte = django_filters.DateTimeFilter(
|
|
||||||
field_name='created',
|
|
||||||
lookup_expr='lte'
|
|
||||||
)
|
|
||||||
expires = django_filters.DateTimeFilter()
|
|
||||||
expires__gte = django_filters.DateTimeFilter(
|
|
||||||
field_name='expires',
|
|
||||||
lookup_expr='gte'
|
|
||||||
)
|
|
||||||
expires__lte = django_filters.DateTimeFilter(
|
|
||||||
field_name='expires',
|
|
||||||
lookup_expr='lte'
|
|
||||||
)
|
|
||||||
|
|
||||||
class Meta:
|
|
||||||
model = Token
|
|
||||||
fields = ['id', 'key', 'write_enabled', 'description']
|
|
||||||
|
|
||||||
def search(self, queryset, name, value):
|
|
||||||
if not value.strip():
|
|
||||||
return queryset
|
|
||||||
return queryset.filter(
|
|
||||||
Q(user__username__icontains=value) |
|
|
||||||
Q(description__icontains=value)
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
class ObjectPermissionFilterSet(BaseFilterSet):
|
class ObjectPermissionFilterSet(BaseFilterSet):
|
||||||
q = django_filters.CharFilter(
|
q = django_filters.CharFilter(
|
||||||
method='search',
|
method='search',
|
||||||
|
@ -8,7 +8,7 @@ from utilities.forms.widgets import BulkEditNullBooleanSelect
|
|||||||
__all__ = (
|
__all__ = (
|
||||||
'ObjectPermissionBulkEditForm',
|
'ObjectPermissionBulkEditForm',
|
||||||
'UserBulkEditForm',
|
'UserBulkEditForm',
|
||||||
'UserTokenBulkEditForm',
|
'TokenBulkEditForm',
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@ -73,7 +73,7 @@ class ObjectPermissionBulkEditForm(BootstrapMixin, forms.Form):
|
|||||||
nullable_fields = ('description',)
|
nullable_fields = ('description',)
|
||||||
|
|
||||||
|
|
||||||
class UserTokenBulkEditForm(BulkEditForm):
|
class TokenBulkEditForm(BulkEditForm):
|
||||||
pk = forms.ModelMultipleChoiceField(
|
pk = forms.ModelMultipleChoiceField(
|
||||||
queryset=Token.objects.all(),
|
queryset=Token.objects.all(),
|
||||||
widget=forms.MultipleHiddenInput
|
widget=forms.MultipleHiddenInput
|
||||||
|
@ -7,7 +7,7 @@ from utilities.forms import CSVModelForm
|
|||||||
__all__ = (
|
__all__ = (
|
||||||
'GroupImportForm',
|
'GroupImportForm',
|
||||||
'UserImportForm',
|
'UserImportForm',
|
||||||
'UserTokenImportForm',
|
'TokenImportForm',
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@ -36,7 +36,7 @@ class UserImportForm(CSVModelForm):
|
|||||||
return super().save(*args, **kwargs)
|
return super().save(*args, **kwargs)
|
||||||
|
|
||||||
|
|
||||||
class UserTokenImportForm(CSVModelForm):
|
class TokenImportForm(CSVModelForm):
|
||||||
key = forms.CharField(
|
key = forms.CharField(
|
||||||
label=_('Key'), required=False, help_text=_("If no key is provided, one will be generated automatically.")
|
label=_('Key'), required=False, help_text=_("If no key is provided, one will be generated automatically.")
|
||||||
)
|
)
|
||||||
|
@ -16,7 +16,7 @@ __all__ = (
|
|||||||
'GroupFilterForm',
|
'GroupFilterForm',
|
||||||
'ObjectPermissionFilterForm',
|
'ObjectPermissionFilterForm',
|
||||||
'UserFilterForm',
|
'UserFilterForm',
|
||||||
'UserTokenFilterForm',
|
'TokenFilterForm',
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@ -116,7 +116,7 @@ class ObjectPermissionFilterForm(NetBoxModelFilterSetForm):
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
class UserTokenFilterForm(SavedFiltersMixin, FilterForm):
|
class TokenFilterForm(SavedFiltersMixin, FilterForm):
|
||||||
model = Token
|
model = Token
|
||||||
fieldsets = (
|
fieldsets = (
|
||||||
(None, ('q', 'filter_id',)),
|
(None, ('q', 'filter_id',)),
|
||||||
|
@ -20,12 +20,13 @@ from utilities.permissions import qs_filter_from_constraints
|
|||||||
from utilities.utils import flatten_dict
|
from utilities.utils import flatten_dict
|
||||||
|
|
||||||
__all__ = (
|
__all__ = (
|
||||||
|
'UserTokenForm',
|
||||||
'GroupForm',
|
'GroupForm',
|
||||||
'ObjectPermissionForm',
|
'ObjectPermissionForm',
|
||||||
'TokenForm',
|
'TokenForm',
|
||||||
'UserConfigForm',
|
'UserConfigForm',
|
||||||
'UserForm',
|
'UserForm',
|
||||||
'UserTokenForm',
|
'TokenForm',
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@ -108,9 +109,11 @@ class UserConfigForm(BootstrapMixin, forms.ModelForm, metaclass=UserConfigFormMe
|
|||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
class TokenForm(BootstrapMixin, forms.ModelForm):
|
class UserTokenForm(BootstrapMixin, forms.ModelForm):
|
||||||
key = forms.CharField(
|
key = forms.CharField(
|
||||||
label=_('Key'), required=False, help_text=_("If no key is provided, one will be generated automatically.")
|
label=_('Key'),
|
||||||
|
required=False,
|
||||||
|
help_text=_("If no key is provided, one will be generated automatically.")
|
||||||
)
|
)
|
||||||
allowed_ips = SimpleArrayField(
|
allowed_ips = SimpleArrayField(
|
||||||
base_field=IPNetworkFormField(validators=[prefix_validator]),
|
base_field=IPNetworkFormField(validators=[prefix_validator]),
|
||||||
@ -139,25 +142,13 @@ class TokenForm(BootstrapMixin, forms.ModelForm):
|
|||||||
del self.fields['key']
|
del self.fields['key']
|
||||||
|
|
||||||
|
|
||||||
class UserTokenForm(BootstrapMixin, forms.ModelForm):
|
class TokenForm(UserTokenForm):
|
||||||
key = forms.CharField(
|
|
||||||
label=_('Key'), required=False, help_text=_("If no key is provided, one will be generated automatically.")
|
|
||||||
)
|
|
||||||
user = forms.ModelChoiceField(
|
user = forms.ModelChoiceField(
|
||||||
queryset=get_user_model().objects.order_by(
|
queryset=get_user_model().objects.order_by(
|
||||||
'username'
|
'username'
|
||||||
),
|
),
|
||||||
required=False
|
required=False
|
||||||
)
|
)
|
||||||
allowed_ips = SimpleArrayField(
|
|
||||||
base_field=IPNetworkFormField(validators=[prefix_validator]),
|
|
||||||
required=False,
|
|
||||||
label=_('Allowed IPs'),
|
|
||||||
help_text=_(
|
|
||||||
'Allowed IPv4/IPv6 networks from where the token can be used. Leave blank for no restrictions. '
|
|
||||||
'Example: <code>10.1.1.0/24,192.168.10.16/32,2001:db8:1::/64</code>'
|
|
||||||
),
|
|
||||||
)
|
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = Token
|
model = Token
|
||||||
@ -168,13 +159,6 @@ class UserTokenForm(BootstrapMixin, forms.ModelForm):
|
|||||||
'expires': DateTimePicker(),
|
'expires': DateTimePicker(),
|
||||||
}
|
}
|
||||||
|
|
||||||
def __init__(self, *args, **kwargs):
|
|
||||||
super().__init__(*args, **kwargs)
|
|
||||||
|
|
||||||
# Omit the key field if token retrieval is not permitted
|
|
||||||
if self.instance.pk and not settings.ALLOW_TOKEN_RETRIEVAL:
|
|
||||||
del self.fields['key']
|
|
||||||
|
|
||||||
|
|
||||||
class UserForm(BootstrapMixin, forms.ModelForm):
|
class UserForm(BootstrapMixin, forms.ModelForm):
|
||||||
password = forms.CharField(
|
password = forms.CharField(
|
||||||
|
@ -8,7 +8,6 @@ __all__ = (
|
|||||||
'ObjectPermissionTable',
|
'ObjectPermissionTable',
|
||||||
'TokenTable',
|
'TokenTable',
|
||||||
'UserTable',
|
'UserTable',
|
||||||
'UserTokenTable',
|
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@ -32,31 +31,6 @@ class TokenActionsColumn(columns.ActionsColumn):
|
|||||||
|
|
||||||
|
|
||||||
class TokenTable(NetBoxTable):
|
class TokenTable(NetBoxTable):
|
||||||
key = columns.TemplateColumn(
|
|
||||||
template_code=TOKEN
|
|
||||||
)
|
|
||||||
write_enabled = columns.BooleanColumn(
|
|
||||||
verbose_name='Write'
|
|
||||||
)
|
|
||||||
created = columns.DateColumn()
|
|
||||||
expired = columns.DateColumn()
|
|
||||||
last_used = columns.DateTimeColumn()
|
|
||||||
allowed_ips = columns.TemplateColumn(
|
|
||||||
template_code=ALLOWED_IPS
|
|
||||||
)
|
|
||||||
actions = TokenActionsColumn(
|
|
||||||
actions=('edit', 'delete'),
|
|
||||||
extra_buttons=COPY_BUTTON
|
|
||||||
)
|
|
||||||
|
|
||||||
class Meta(NetBoxTable.Meta):
|
|
||||||
model = Token
|
|
||||||
fields = (
|
|
||||||
'pk', 'description', 'key', 'write_enabled', 'created', 'expires', 'last_used', 'allowed_ips',
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
class UserTokenTable(NetBoxTable):
|
|
||||||
key = columns.TemplateColumn(
|
key = columns.TemplateColumn(
|
||||||
verbose_name='Key',
|
verbose_name='Key',
|
||||||
template_code=TOKEN,
|
template_code=TOKEN,
|
||||||
|
@ -11,16 +11,17 @@ urlpatterns = [
|
|||||||
path('bookmarks/', views.BookmarkListView.as_view(), name='bookmarks'),
|
path('bookmarks/', views.BookmarkListView.as_view(), name='bookmarks'),
|
||||||
path('preferences/', views.UserConfigView.as_view(), name='preferences'),
|
path('preferences/', views.UserConfigView.as_view(), name='preferences'),
|
||||||
path('password/', views.ChangePasswordView.as_view(), name='change_password'),
|
path('password/', views.ChangePasswordView.as_view(), name='change_password'),
|
||||||
path('api-tokens/', views.TokenListView.as_view(), name='token_list'),
|
path('api-tokens/', views.UserTokenListView.as_view(), name='usertoken_list'),
|
||||||
path('api-tokens/add/', views.TokenEditView.as_view(), name='token_add'),
|
path('api-tokens/add/', views.UserTokenEditView.as_view(), name='usertoken_add'),
|
||||||
path('api-tokens/<int:pk>/', include(get_model_urls('users', 'token'))),
|
path('api-tokens/<int:pk>/edit/', views.UserTokenEditView.as_view(), name='usertoken_edit'),
|
||||||
|
path('api-tokens/<int:pk>/delete/', views.UserTokenDeleteView.as_view(), name='usertoken_delete'),
|
||||||
|
|
||||||
# Tokens
|
# Tokens
|
||||||
path('tokens/', views.UserTokenListView.as_view(), name='token_list'),
|
path('tokens/', views.TokenListView.as_view(), name='token_list'),
|
||||||
path('tokens/add/', views.UserTokenEditView.as_view(), name='token_add'),
|
path('tokens/add/', views.TokenEditView.as_view(), name='token_add'),
|
||||||
path('tokens/import/', views.UserTokenBulkImportView.as_view(), name='token_import'),
|
path('tokens/import/', views.TokenBulkImportView.as_view(), name='token_import'),
|
||||||
path('tokens/edit/', views.UserTokenBulkEditView.as_view(), name='token_bulk_edit'),
|
path('tokens/edit/', views.TokenBulkEditView.as_view(), name='token_bulk_edit'),
|
||||||
path('tokens/delete/', views.UserTokenBulkDeleteView.as_view(), name='token_bulk_delete'),
|
path('tokens/delete/', views.TokenBulkDeleteView.as_view(), name='token_bulk_delete'),
|
||||||
path('tokens/<int:pk>/', include(get_model_urls('users', 'token'))),
|
path('tokens/<int:pk>/', include(get_model_urls('users', 'token'))),
|
||||||
|
|
||||||
# Users
|
# Users
|
||||||
|
@ -252,7 +252,7 @@ class BookmarkListView(LoginRequiredMixin, generic.ObjectListView):
|
|||||||
# API tokens
|
# API tokens
|
||||||
#
|
#
|
||||||
|
|
||||||
class TokenListView(LoginRequiredMixin, View):
|
class UserTokenListView(LoginRequiredMixin, View):
|
||||||
|
|
||||||
def get(self, request):
|
def get(self, request):
|
||||||
|
|
||||||
@ -267,8 +267,7 @@ class TokenListView(LoginRequiredMixin, View):
|
|||||||
})
|
})
|
||||||
|
|
||||||
|
|
||||||
@register_model_view(Token, 'edit')
|
class UserTokenEditView(LoginRequiredMixin, View):
|
||||||
class TokenEditView(LoginRequiredMixin, View):
|
|
||||||
|
|
||||||
def get(self, request, pk=None):
|
def get(self, request, pk=None):
|
||||||
|
|
||||||
@ -277,7 +276,7 @@ class TokenEditView(LoginRequiredMixin, View):
|
|||||||
else:
|
else:
|
||||||
token = Token(user=request.user)
|
token = Token(user=request.user)
|
||||||
|
|
||||||
form = forms.TokenForm(instance=token)
|
form = forms.UserTokenForm(instance=token)
|
||||||
|
|
||||||
return render(request, 'generic/object_edit.html', {
|
return render(request, 'generic/object_edit.html', {
|
||||||
'object': token,
|
'object': token,
|
||||||
@ -289,10 +288,10 @@ class TokenEditView(LoginRequiredMixin, View):
|
|||||||
|
|
||||||
if pk:
|
if pk:
|
||||||
token = get_object_or_404(Token.objects.filter(user=request.user), pk=pk)
|
token = get_object_or_404(Token.objects.filter(user=request.user), pk=pk)
|
||||||
form = forms.TokenForm(request.POST, instance=token)
|
form = forms.UserTokenForm(request.POST, instance=token)
|
||||||
else:
|
else:
|
||||||
token = Token(user=request.user)
|
token = Token(user=request.user)
|
||||||
form = forms.TokenForm(request.POST)
|
form = forms.UserTokenForm(request.POST)
|
||||||
|
|
||||||
if form.is_valid():
|
if form.is_valid():
|
||||||
|
|
||||||
@ -322,8 +321,7 @@ class TokenEditView(LoginRequiredMixin, View):
|
|||||||
})
|
})
|
||||||
|
|
||||||
|
|
||||||
@register_model_view(Token, 'delete')
|
class UserTokenDeleteView(LoginRequiredMixin, View):
|
||||||
class TokenDeleteView(LoginRequiredMixin, View):
|
|
||||||
|
|
||||||
def get(self, request, pk):
|
def get(self, request, pk):
|
||||||
|
|
||||||
@ -356,18 +354,18 @@ class TokenDeleteView(LoginRequiredMixin, View):
|
|||||||
|
|
||||||
|
|
||||||
#
|
#
|
||||||
# User Token
|
# Tokens
|
||||||
#
|
#
|
||||||
|
|
||||||
class UserTokenListView(generic.ObjectListView):
|
class TokenListView(generic.ObjectListView):
|
||||||
queryset = Token.objects.all()
|
queryset = Token.objects.all()
|
||||||
filterset = filtersets.UserTokenFilterSet
|
filterset = filtersets.TokenFilterSet
|
||||||
filterset_form = forms.UserTokenFilterForm
|
filterset_form = forms.TokenFilterForm
|
||||||
table = tables.UserTokenTable
|
table = tables.TokenTable
|
||||||
|
|
||||||
|
|
||||||
@register_model_view(Token)
|
@register_model_view(Token)
|
||||||
class UserTokenView(generic.ObjectView):
|
class TokenView(generic.ObjectView):
|
||||||
queryset = Token.objects.all()
|
queryset = Token.objects.all()
|
||||||
|
|
||||||
def get_extra_context(self, request, instance):
|
def get_extra_context(self, request, instance):
|
||||||
@ -375,30 +373,30 @@ class UserTokenView(generic.ObjectView):
|
|||||||
|
|
||||||
|
|
||||||
@register_model_view(Token, 'edit')
|
@register_model_view(Token, 'edit')
|
||||||
class UserTokenEditView(generic.ObjectEditView):
|
class TokenEditView(generic.ObjectEditView):
|
||||||
queryset = Token.objects.all()
|
queryset = Token.objects.all()
|
||||||
form = forms.UserTokenForm
|
form = forms.TokenForm
|
||||||
|
|
||||||
|
|
||||||
@register_model_view(Token, 'delete')
|
@register_model_view(Token, 'delete')
|
||||||
class UserTokenDeleteView(generic.ObjectDeleteView):
|
class TokenDeleteView(generic.ObjectDeleteView):
|
||||||
queryset = Token.objects.all()
|
queryset = Token.objects.all()
|
||||||
|
|
||||||
|
|
||||||
class UserTokenBulkImportView(generic.BulkImportView):
|
class TokenBulkImportView(generic.BulkImportView):
|
||||||
queryset = Token.objects.all()
|
queryset = Token.objects.all()
|
||||||
model_form = forms.UserTokenImportForm
|
model_form = forms.TokenImportForm
|
||||||
|
|
||||||
|
|
||||||
class UserTokenBulkEditView(generic.BulkEditView):
|
class TokenBulkEditView(generic.BulkEditView):
|
||||||
queryset = Token.objects.all()
|
queryset = Token.objects.all()
|
||||||
table = tables.TokenTable
|
table = tables.TokenTable
|
||||||
form = forms.UserTokenBulkEditForm
|
form = forms.TokenBulkEditForm
|
||||||
|
|
||||||
|
|
||||||
class UserTokenBulkDeleteView(generic.BulkDeleteView):
|
class TokenBulkDeleteView(generic.BulkDeleteView):
|
||||||
queryset = Token.objects.all()
|
queryset = Token.objects.all()
|
||||||
table = tables.UserTokenTable
|
table = tables.TokenTable
|
||||||
|
|
||||||
|
|
||||||
#
|
#
|
||||||
|
Loading…
Reference in New Issue
Block a user