2018-02-16 10:00:31 +08:00
|
|
|
|
import datetime
|
2017-01-07 19:11:46 +08:00
|
|
|
|
from io import StringIO
|
2015-02-06 07:30:11 +08:00
|
|
|
|
from wsgiref.util import FileWrapper
|
2011-09-21 02:16:49 +08:00
|
|
|
|
|
2011-10-14 02:51:33 +08:00
|
|
|
|
from django import forms
|
2011-09-21 02:16:49 +08:00
|
|
|
|
from django.contrib import admin
|
2015-01-28 20:35:27 +08:00
|
|
|
|
from django.contrib.admin import BooleanFieldListFilter
|
2011-09-21 02:16:49 +08:00
|
|
|
|
from django.contrib.admin.views.main import ChangeList
|
2015-01-28 20:35:27 +08:00
|
|
|
|
from django.contrib.auth.admin import GroupAdmin, UserAdmin
|
|
|
|
|
from django.contrib.auth.models import Group, User
|
2013-11-15 10:26:19 +08:00
|
|
|
|
from django.core.exceptions import ValidationError
|
2011-09-21 02:16:49 +08:00
|
|
|
|
from django.core.mail import EmailMessage
|
2015-07-05 01:24:28 +08:00
|
|
|
|
from django.db import models
|
2011-10-14 02:51:33 +08:00
|
|
|
|
from django.forms.models import BaseModelFormSet
|
2021-01-12 21:37:56 +08:00
|
|
|
|
from django.http import HttpResponse, JsonResponse, StreamingHttpResponse
|
2018-12-08 06:52:28 +08:00
|
|
|
|
from django.urls import path
|
2015-09-09 03:46:26 +08:00
|
|
|
|
from django.utils.html import format_html
|
2014-03-23 00:00:50 +08:00
|
|
|
|
from django.utils.safestring import mark_safe
|
2021-01-12 21:37:56 +08:00
|
|
|
|
from django.views.decorators.common import no_append_slash
|
2011-09-21 02:16:49 +08:00
|
|
|
|
|
2016-07-20 19:38:07 +08:00
|
|
|
|
from .forms import MediaActionForm
|
2014-11-28 02:34:14 +08:00
|
|
|
|
from .models import (
|
2015-01-28 20:35:27 +08:00
|
|
|
|
Actor,
|
|
|
|
|
AdminOrderedAdminMethod,
|
|
|
|
|
AdminOrderedCallable,
|
|
|
|
|
AdminOrderedField,
|
2017-02-24 23:22:25 +08:00
|
|
|
|
AdminOrderedModelMethod,
|
|
|
|
|
Album,
|
|
|
|
|
Answer,
|
|
|
|
|
Answer2,
|
|
|
|
|
Article,
|
|
|
|
|
BarAccount,
|
|
|
|
|
Book,
|
2021-09-01 20:01:40 +08:00
|
|
|
|
Bookmark,
|
|
|
|
|
Box,
|
|
|
|
|
Category,
|
|
|
|
|
Chapter,
|
|
|
|
|
ChapterXtra1,
|
|
|
|
|
Child,
|
|
|
|
|
ChildOfReferer,
|
|
|
|
|
Choice,
|
|
|
|
|
City,
|
|
|
|
|
Collector,
|
|
|
|
|
Color,
|
|
|
|
|
Color2,
|
|
|
|
|
ComplexSortedPerson,
|
|
|
|
|
CoverLetter,
|
2015-08-28 04:13:24 +08:00
|
|
|
|
CustomArticle,
|
|
|
|
|
CyclicOne,
|
|
|
|
|
CyclicTwo,
|
|
|
|
|
DependentChild,
|
|
|
|
|
DooHickey,
|
|
|
|
|
EmptyModel,
|
2015-01-28 20:35:27 +08:00
|
|
|
|
EmptyModelHidden,
|
|
|
|
|
EmptyModelMixin,
|
|
|
|
|
EmptyModelVisible,
|
|
|
|
|
ExplicitlyProvidedPK,
|
|
|
|
|
ExternalSubscriber,
|
|
|
|
|
Fabric,
|
|
|
|
|
FancyDoodad,
|
|
|
|
|
FieldOverridePost,
|
|
|
|
|
FilteredManager,
|
|
|
|
|
FooAccount,
|
|
|
|
|
FoodDelivery,
|
|
|
|
|
FunkyTag,
|
|
|
|
|
Gadget,
|
|
|
|
|
Gallery,
|
2015-10-28 23:25:25 +08:00
|
|
|
|
GenRelReference,
|
|
|
|
|
Grommet,
|
|
|
|
|
ImplicitlyGeneratedPK,
|
|
|
|
|
Ingredient,
|
|
|
|
|
InlineReference,
|
|
|
|
|
InlineReferer,
|
|
|
|
|
Inquisition,
|
|
|
|
|
Language,
|
|
|
|
|
Link,
|
|
|
|
|
MainPrepopulated,
|
|
|
|
|
ModelWithStringPrimaryKey,
|
|
|
|
|
NotReferenced,
|
|
|
|
|
OldSubscriber,
|
2016-01-07 17:07:15 +08:00
|
|
|
|
OtherStory,
|
|
|
|
|
Paper,
|
|
|
|
|
Parent,
|
|
|
|
|
ParentWithDependentChildren,
|
|
|
|
|
ParentWithUUIDPK,
|
2016-01-10 04:15:21 +08:00
|
|
|
|
Person,
|
|
|
|
|
Persona,
|
|
|
|
|
Picture,
|
|
|
|
|
Pizza,
|
|
|
|
|
Plot,
|
|
|
|
|
PlotDetails,
|
|
|
|
|
PlotProxy,
|
|
|
|
|
PluggableSearchPerson,
|
|
|
|
|
Podcast,
|
|
|
|
|
Post,
|
|
|
|
|
PrePopulatedPost,
|
2017-04-05 11:54:46 +08:00
|
|
|
|
PrePopulatedPostLargeSlug,
|
|
|
|
|
PrePopulatedSubPost,
|
|
|
|
|
Promo,
|
|
|
|
|
Question,
|
2020-01-19 02:03:03 +08:00
|
|
|
|
ReadablePizza,
|
|
|
|
|
ReadOnlyPizza,
|
|
|
|
|
ReadOnlyRelatedField,
|
|
|
|
|
Recipe,
|
|
|
|
|
Recommendation,
|
|
|
|
|
Recommender,
|
|
|
|
|
ReferencedByGenRel,
|
|
|
|
|
ReferencedByInline,
|
|
|
|
|
ReferencedByParent,
|
2017-08-23 07:48:55 +08:00
|
|
|
|
RelatedPrepopulated,
|
|
|
|
|
RelatedWithUUIDPKModel,
|
|
|
|
|
Report,
|
|
|
|
|
Reservation,
|
|
|
|
|
Restaurant,
|
|
|
|
|
RowLevelChangePermissionModel,
|
|
|
|
|
Section,
|
|
|
|
|
ShortMessage,
|
|
|
|
|
Simple,
|
2016-10-10 15:23:35 +08:00
|
|
|
|
Sketch,
|
|
|
|
|
Song,
|
|
|
|
|
State,
|
|
|
|
|
Story,
|
|
|
|
|
StumpJoke,
|
|
|
|
|
Subscriber,
|
|
|
|
|
SuperVillain,
|
|
|
|
|
Telegram,
|
|
|
|
|
Thing,
|
|
|
|
|
Topping,
|
|
|
|
|
UnchangeableObject,
|
|
|
|
|
UndeletableObject,
|
|
|
|
|
UnorderedObject,
|
2019-01-16 23:07:28 +08:00
|
|
|
|
UserMessenger,
|
|
|
|
|
UserProxy,
|
|
|
|
|
Villain,
|
|
|
|
|
Vodcast,
|
|
|
|
|
Whatsit,
|
|
|
|
|
Widget,
|
|
|
|
|
Worker,
|
|
|
|
|
WorkHour,
|
2014-11-28 02:34:14 +08:00
|
|
|
|
)
|
2011-09-21 02:16:49 +08:00
|
|
|
|
|
|
|
|
|
|
2021-01-14 00:19:22 +08:00
|
|
|
|
@admin.display(ordering="date")
|
2011-09-21 02:16:49 +08:00
|
|
|
|
def callable_year(dt_value):
|
2012-09-08 23:18:08 +08:00
|
|
|
|
try:
|
|
|
|
|
return dt_value.year
|
|
|
|
|
except AttributeError:
|
|
|
|
|
return None
|
2016-11-13 01:11:23 +08:00
|
|
|
|
|
|
|
|
|
|
2011-09-21 02:16:49 +08:00
|
|
|
|
class ArticleInline(admin.TabularInline):
|
|
|
|
|
model = Article
|
2013-11-18 06:26:20 +08:00
|
|
|
|
fk_name = "section"
|
2012-02-05 18:26:05 +08:00
|
|
|
|
prepopulated_fields = {"title": ("content",)}
|
2013-10-23 18:09:29 +08:00
|
|
|
|
fieldsets = (
|
2012-02-05 18:26:05 +08:00
|
|
|
|
("Some fields", {"classes": ("collapse",), "fields": ("title", "content")}),
|
|
|
|
|
("Some other fields", {"classes": ("wide",), "fields": ("date", "section")}),
|
|
|
|
|
)
|
2011-09-21 02:16:49 +08:00
|
|
|
|
|
2013-11-03 06:50:35 +08:00
|
|
|
|
|
2011-09-21 02:16:49 +08:00
|
|
|
|
class ChapterInline(admin.TabularInline):
|
|
|
|
|
model = Chapter
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class ChapterXtra1Admin(admin.ModelAdmin):
|
2017-06-05 02:10:48 +08:00
|
|
|
|
list_filter = (
|
|
|
|
|
"chap",
|
|
|
|
|
"chap__title",
|
|
|
|
|
"chap__book",
|
|
|
|
|
"chap__book__name",
|
|
|
|
|
"chap__book__promo",
|
|
|
|
|
"chap__book__promo__name",
|
|
|
|
|
"guest_author__promo__book",
|
|
|
|
|
)
|
2011-09-21 02:16:49 +08:00
|
|
|
|
|
|
|
|
|
|
2018-08-19 04:15:18 +08:00
|
|
|
|
class ArticleForm(forms.ModelForm):
|
|
|
|
|
extra_form_field = forms.BooleanField(required=False)
|
|
|
|
|
|
|
|
|
|
class Meta:
|
|
|
|
|
fields = "__all__"
|
|
|
|
|
model = Article
|
|
|
|
|
|
|
|
|
|
|
2021-01-12 21:37:56 +08:00
|
|
|
|
class ArticleAdminWithExtraUrl(admin.ModelAdmin):
|
|
|
|
|
def get_urls(self):
|
|
|
|
|
urlpatterns = super().get_urls()
|
|
|
|
|
urlpatterns.append(
|
|
|
|
|
path(
|
|
|
|
|
"extra.json",
|
|
|
|
|
self.admin_site.admin_view(self.extra_json),
|
|
|
|
|
name="article_extra_json",
|
|
|
|
|
)
|
|
|
|
|
)
|
|
|
|
|
return urlpatterns
|
|
|
|
|
|
|
|
|
|
def extra_json(self, request):
|
|
|
|
|
return JsonResponse({})
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class ArticleAdmin(ArticleAdminWithExtraUrl):
|
2015-12-21 21:36:41 +08:00
|
|
|
|
list_display = (
|
|
|
|
|
"content",
|
|
|
|
|
"date",
|
|
|
|
|
callable_year,
|
|
|
|
|
"model_year",
|
|
|
|
|
"modeladmin_year",
|
2015-12-29 04:31:45 +08:00
|
|
|
|
"model_year_reversed",
|
|
|
|
|
"section",
|
|
|
|
|
lambda obj: obj.title,
|
2019-04-01 21:11:54 +08:00
|
|
|
|
"order_by_expression",
|
|
|
|
|
"model_property_year",
|
|
|
|
|
"model_month",
|
2019-11-16 04:59:22 +08:00
|
|
|
|
"order_by_f_expression",
|
|
|
|
|
"order_by_orderby_expression",
|
2015-12-21 21:36:41 +08:00
|
|
|
|
)
|
|
|
|
|
list_editable = ("section",)
|
2011-09-21 02:16:49 +08:00
|
|
|
|
list_filter = ("date", "section")
|
2017-05-10 20:48:57 +08:00
|
|
|
|
autocomplete_fields = ("section",)
|
2013-10-24 23:28:09 +08:00
|
|
|
|
view_on_site = False
|
2018-08-19 04:15:18 +08:00
|
|
|
|
form = ArticleForm
|
2013-10-23 18:09:29 +08:00
|
|
|
|
fieldsets = (
|
2013-02-20 00:01:29 +08:00
|
|
|
|
(
|
|
|
|
|
"Some fields",
|
|
|
|
|
{
|
|
|
|
|
"classes": ("collapse",),
|
2018-08-19 04:15:18 +08:00
|
|
|
|
"fields": ("title", "content", "extra_form_field"),
|
2013-02-20 00:01:29 +08:00
|
|
|
|
},
|
|
|
|
|
),
|
|
|
|
|
(
|
|
|
|
|
"Some other fields",
|
2013-11-18 06:26:20 +08:00
|
|
|
|
{"classes": ("wide",), "fields": ("date", "section", "sub_section")},
|
2022-02-04 03:24:19 +08:00
|
|
|
|
),
|
2013-02-20 00:01:29 +08:00
|
|
|
|
)
|
2011-09-21 02:16:49 +08:00
|
|
|
|
|
2019-11-16 04:59:22 +08:00
|
|
|
|
# These orderings aren't particularly useful but show that expressions can
|
|
|
|
|
# be used for admin_order_field.
|
2021-01-14 00:19:22 +08:00
|
|
|
|
@admin.display(ordering=models.F("date") + datetime.timedelta(days=3))
|
2018-02-16 10:00:31 +08:00
|
|
|
|
def order_by_expression(self, obj):
|
|
|
|
|
return obj.model_year
|
|
|
|
|
|
2021-01-14 00:19:22 +08:00
|
|
|
|
@admin.display(ordering=models.F("date"))
|
2019-11-16 04:59:22 +08:00
|
|
|
|
def order_by_f_expression(self, obj):
|
|
|
|
|
return obj.model_year
|
|
|
|
|
|
2021-01-14 00:19:22 +08:00
|
|
|
|
@admin.display(ordering=models.F("date").asc(nulls_last=True))
|
2019-11-16 04:59:22 +08:00
|
|
|
|
def order_by_orderby_expression(self, obj):
|
|
|
|
|
return obj.model_year
|
|
|
|
|
|
2011-09-21 02:16:49 +08:00
|
|
|
|
def changelist_view(self, request):
|
2017-01-21 21:13:44 +08:00
|
|
|
|
return super().changelist_view(request, extra_context={"extra_var": "Hello!"})
|
2011-09-21 02:16:49 +08:00
|
|
|
|
|
2021-01-14 00:19:22 +08:00
|
|
|
|
@admin.display(ordering="date", description=None)
|
2011-09-21 02:16:49 +08:00
|
|
|
|
def modeladmin_year(self, obj):
|
|
|
|
|
return obj.date.year
|
|
|
|
|
|
|
|
|
|
def delete_model(self, request, obj):
|
|
|
|
|
EmailMessage(
|
|
|
|
|
"Greetings from a deleted object",
|
|
|
|
|
"I hereby inform you that some user deleted me",
|
|
|
|
|
"from@example.com",
|
|
|
|
|
["to@example.com"],
|
|
|
|
|
).send()
|
2017-01-21 21:13:44 +08:00
|
|
|
|
return super().delete_model(request, obj)
|
2011-09-21 02:16:49 +08:00
|
|
|
|
|
|
|
|
|
def save_model(self, request, obj, form, change=True):
|
|
|
|
|
EmailMessage(
|
|
|
|
|
"Greetings from a created object",
|
|
|
|
|
"I hereby inform you that some user created me",
|
|
|
|
|
"from@example.com",
|
|
|
|
|
["to@example.com"],
|
|
|
|
|
).send()
|
2017-01-21 21:13:44 +08:00
|
|
|
|
return super().save_model(request, obj, form, change)
|
2011-09-21 02:16:49 +08:00
|
|
|
|
|
|
|
|
|
|
2014-05-29 00:07:27 +08:00
|
|
|
|
class ArticleAdmin2(admin.ModelAdmin):
|
|
|
|
|
def has_module_permission(self, request):
|
|
|
|
|
return False
|
|
|
|
|
|
|
|
|
|
|
2011-09-21 02:16:49 +08:00
|
|
|
|
class RowLevelChangePermissionModelAdmin(admin.ModelAdmin):
|
|
|
|
|
def has_change_permission(self, request, obj=None):
|
|
|
|
|
"""Only allow changing objects with even id number"""
|
|
|
|
|
return request.user.is_staff and (obj is not None) and (obj.id % 2 == 0)
|
|
|
|
|
|
2018-05-02 16:39:12 +08:00
|
|
|
|
def has_view_permission(self, request, obj=None):
|
|
|
|
|
"""Only allow viewing objects if id is a multiple of 3."""
|
|
|
|
|
return request.user.is_staff and obj is not None and obj.id % 3 == 0
|
|
|
|
|
|
2011-09-21 02:16:49 +08:00
|
|
|
|
|
|
|
|
|
class CustomArticleAdmin(admin.ModelAdmin):
|
|
|
|
|
"""
|
|
|
|
|
Tests various hooks for using custom templates and contexts.
|
|
|
|
|
"""
|
2022-02-04 03:24:19 +08:00
|
|
|
|
|
2011-09-21 02:16:49 +08:00
|
|
|
|
change_list_template = "custom_admin/change_list.html"
|
|
|
|
|
change_form_template = "custom_admin/change_form.html"
|
|
|
|
|
add_form_template = "custom_admin/add_form.html"
|
|
|
|
|
object_history_template = "custom_admin/object_history.html"
|
|
|
|
|
delete_confirmation_template = "custom_admin/delete_confirmation.html"
|
|
|
|
|
delete_selected_confirmation_template = (
|
|
|
|
|
"custom_admin/delete_selected_confirmation.html"
|
2022-02-04 03:24:19 +08:00
|
|
|
|
)
|
2016-11-13 03:09:15 +08:00
|
|
|
|
popup_response_template = "custom_admin/popup_response.html"
|
2011-09-21 02:16:49 +08:00
|
|
|
|
|
|
|
|
|
def changelist_view(self, request):
|
2017-01-21 21:13:44 +08:00
|
|
|
|
return super().changelist_view(request, extra_context={"extra_var": "Hello!"})
|
2011-09-21 02:16:49 +08:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class ThingAdmin(admin.ModelAdmin):
|
2017-06-04 06:13:38 +08:00
|
|
|
|
list_filter = ("color", "color__warm", "color__value", "pub_date")
|
2011-09-21 02:16:49 +08:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class InquisitionAdmin(admin.ModelAdmin):
|
2015-08-24 23:52:58 +08:00
|
|
|
|
list_display = ("leader", "country", "expected", "sketch")
|
|
|
|
|
|
2021-01-14 00:19:22 +08:00
|
|
|
|
@admin.display
|
2015-08-24 23:52:58 +08:00
|
|
|
|
def sketch(self, obj):
|
|
|
|
|
# A method with the same name as a reverse accessor.
|
|
|
|
|
return "list-display-sketch"
|
2011-09-21 02:16:49 +08:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class SketchAdmin(admin.ModelAdmin):
|
2013-05-28 00:31:49 +08:00
|
|
|
|
raw_id_fields = ("inquisition", "defendant0", "defendant1")
|
2011-09-21 02:16:49 +08:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class FabricAdmin(admin.ModelAdmin):
|
|
|
|
|
list_display = ("surface",)
|
|
|
|
|
list_filter = ("surface",)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class BasePersonModelFormSet(BaseModelFormSet):
|
|
|
|
|
def clean(self):
|
|
|
|
|
for person_dict in self.cleaned_data:
|
|
|
|
|
person = person_dict.get("id")
|
|
|
|
|
alive = person_dict.get("alive")
|
|
|
|
|
if person and alive and person.name == "Grace Hopper":
|
2020-02-12 21:48:49 +08:00
|
|
|
|
raise ValidationError("Grace is not a Zombie")
|
2011-09-21 02:16:49 +08:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class PersonAdmin(admin.ModelAdmin):
|
|
|
|
|
list_display = ("name", "gender", "alive")
|
|
|
|
|
list_editable = ("gender", "alive")
|
|
|
|
|
list_filter = ("gender",)
|
|
|
|
|
search_fields = ("^name",)
|
|
|
|
|
save_as = True
|
|
|
|
|
|
|
|
|
|
def get_changelist_formset(self, request, **kwargs):
|
2017-01-21 21:13:44 +08:00
|
|
|
|
return super().get_changelist_formset(
|
|
|
|
|
request, formset=BasePersonModelFormSet, **kwargs
|
|
|
|
|
)
|
2011-09-21 02:16:49 +08:00
|
|
|
|
|
2013-03-08 22:15:23 +08:00
|
|
|
|
def get_queryset(self, request):
|
2011-09-21 02:16:49 +08:00
|
|
|
|
# Order by a field that isn't in list display, to be able to test
|
|
|
|
|
# whether ordering is preserved.
|
2017-01-21 21:13:44 +08:00
|
|
|
|
return super().get_queryset(request).order_by("age")
|
2011-09-21 02:16:49 +08:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class FooAccountAdmin(admin.StackedInline):
|
|
|
|
|
model = FooAccount
|
|
|
|
|
extra = 1
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class BarAccountAdmin(admin.StackedInline):
|
|
|
|
|
model = BarAccount
|
|
|
|
|
extra = 1
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class PersonaAdmin(admin.ModelAdmin):
|
|
|
|
|
inlines = (FooAccountAdmin, BarAccountAdmin)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class SubscriberAdmin(admin.ModelAdmin):
|
|
|
|
|
actions = ["mail_admin"]
|
2016-07-20 19:38:07 +08:00
|
|
|
|
action_form = MediaActionForm
|
2011-09-21 02:16:49 +08:00
|
|
|
|
|
2017-09-04 17:24:34 +08:00
|
|
|
|
def delete_queryset(self, request, queryset):
|
|
|
|
|
SubscriberAdmin.overridden = True
|
|
|
|
|
super().delete_queryset(request, queryset)
|
|
|
|
|
|
2021-01-14 00:19:22 +08:00
|
|
|
|
@admin.action
|
2011-09-21 02:16:49 +08:00
|
|
|
|
def mail_admin(self, request, selected):
|
|
|
|
|
EmailMessage(
|
|
|
|
|
"Greetings from a ModelAdmin action",
|
2014-05-29 08:39:14 +08:00
|
|
|
|
"This is the test email from an admin action",
|
2011-09-21 02:16:49 +08:00
|
|
|
|
"from@example.com",
|
|
|
|
|
["to@example.com"],
|
|
|
|
|
).send()
|
|
|
|
|
|
|
|
|
|
|
2021-01-14 00:19:22 +08:00
|
|
|
|
@admin.action(description="External mail (Another awesome action)")
|
2011-09-21 02:16:49 +08:00
|
|
|
|
def external_mail(modeladmin, request, selected):
|
|
|
|
|
EmailMessage(
|
|
|
|
|
"Greetings from a function action",
|
|
|
|
|
"This is the test email from a function action",
|
|
|
|
|
"from@example.com",
|
|
|
|
|
["to@example.com"],
|
|
|
|
|
).send()
|
2016-11-13 01:11:23 +08:00
|
|
|
|
|
|
|
|
|
|
2021-01-14 00:19:22 +08:00
|
|
|
|
@admin.action(description="Redirect to (Awesome action)")
|
2011-09-21 02:16:49 +08:00
|
|
|
|
def redirect_to(modeladmin, request, selected):
|
|
|
|
|
from django.http import HttpResponseRedirect
|
2016-11-13 01:11:23 +08:00
|
|
|
|
|
2011-09-21 02:16:49 +08:00
|
|
|
|
return HttpResponseRedirect("/some-where-else/")
|
2016-11-13 01:11:23 +08:00
|
|
|
|
|
2022-02-04 03:24:19 +08:00
|
|
|
|
|
2021-01-14 00:19:22 +08:00
|
|
|
|
@admin.action(description="Download subscription")
|
2013-05-29 22:55:56 +08:00
|
|
|
|
def download(modeladmin, request, selected):
|
|
|
|
|
buf = StringIO("This is the content of the file")
|
|
|
|
|
return StreamingHttpResponse(FileWrapper(buf))
|
2016-11-13 01:11:23 +08:00
|
|
|
|
|
|
|
|
|
|
2021-01-14 00:19:22 +08:00
|
|
|
|
@admin.action(description="No permission to run")
|
2013-05-29 22:55:56 +08:00
|
|
|
|
def no_perm(modeladmin, request, selected):
|
2018-03-16 17:54:34 +08:00
|
|
|
|
return HttpResponse(content="No permission to perform this action", status=403)
|
2016-11-13 01:11:23 +08:00
|
|
|
|
|
|
|
|
|
|
2011-09-21 02:16:49 +08:00
|
|
|
|
class ExternalSubscriberAdmin(admin.ModelAdmin):
|
2013-05-29 22:55:56 +08:00
|
|
|
|
actions = [redirect_to, external_mail, download, no_perm]
|
2011-09-21 02:16:49 +08:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class PodcastAdmin(admin.ModelAdmin):
|
|
|
|
|
list_display = ("name", "release_date")
|
|
|
|
|
list_editable = ("release_date",)
|
|
|
|
|
date_hierarchy = "release_date"
|
|
|
|
|
ordering = ("name",)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class VodcastAdmin(admin.ModelAdmin):
|
|
|
|
|
list_display = ("name", "released")
|
|
|
|
|
list_editable = ("released",)
|
|
|
|
|
|
|
|
|
|
ordering = ("name",)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class ChildInline(admin.StackedInline):
|
|
|
|
|
model = Child
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class ParentAdmin(admin.ModelAdmin):
|
|
|
|
|
model = Parent
|
|
|
|
|
inlines = [ChildInline]
|
2015-04-25 09:31:26 +08:00
|
|
|
|
save_as = True
|
2016-08-05 22:20:38 +08:00
|
|
|
|
list_display = (
|
|
|
|
|
"id",
|
|
|
|
|
"name",
|
|
|
|
|
)
|
|
|
|
|
list_display_links = ("id",)
|
2011-09-21 02:16:49 +08:00
|
|
|
|
list_editable = ("name",)
|
|
|
|
|
|
|
|
|
|
def save_related(self, request, form, formsets, change):
|
2017-01-21 21:13:44 +08:00
|
|
|
|
super().save_related(request, form, formsets, change)
|
2011-09-21 02:16:49 +08:00
|
|
|
|
first_name, last_name = form.instance.name.split()
|
|
|
|
|
for child in form.instance.child_set.all():
|
|
|
|
|
if len(child.name.split()) < 2:
|
|
|
|
|
child.name = child.name + " " + last_name
|
|
|
|
|
child.save()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class EmptyModelAdmin(admin.ModelAdmin):
|
2013-03-08 22:15:23 +08:00
|
|
|
|
def get_queryset(self, request):
|
2017-01-21 21:13:44 +08:00
|
|
|
|
return super().get_queryset(request).filter(pk__gt=1)
|
2011-09-21 02:16:49 +08:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class OldSubscriberAdmin(admin.ModelAdmin):
|
|
|
|
|
actions = None
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class PictureInline(admin.TabularInline):
|
|
|
|
|
model = Picture
|
|
|
|
|
extra = 1
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class GalleryAdmin(admin.ModelAdmin):
|
|
|
|
|
inlines = [PictureInline]
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class PictureAdmin(admin.ModelAdmin):
|
|
|
|
|
pass
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class LanguageAdmin(admin.ModelAdmin):
|
|
|
|
|
list_display = ["iso", "shortlist", "english_name", "name"]
|
|
|
|
|
list_editable = ["shortlist"]
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class RecommendationAdmin(admin.ModelAdmin):
|
2014-09-23 00:46:43 +08:00
|
|
|
|
show_full_result_count = False
|
2016-08-05 23:19:09 +08:00
|
|
|
|
search_fields = (
|
|
|
|
|
"=titletranslation__text",
|
|
|
|
|
"=the_recommender__titletranslation__text",
|
|
|
|
|
)
|
2011-09-21 02:16:49 +08:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class WidgetInline(admin.StackedInline):
|
|
|
|
|
model = Widget
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class DooHickeyInline(admin.StackedInline):
|
|
|
|
|
model = DooHickey
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class GrommetInline(admin.StackedInline):
|
|
|
|
|
model = Grommet
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class WhatsitInline(admin.StackedInline):
|
|
|
|
|
model = Whatsit
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class FancyDoodadInline(admin.StackedInline):
|
|
|
|
|
model = FancyDoodad
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class CategoryAdmin(admin.ModelAdmin):
|
|
|
|
|
list_display = ("id", "collector", "order")
|
|
|
|
|
list_editable = ("order",)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class CategoryInline(admin.StackedInline):
|
|
|
|
|
model = Category
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class CollectorAdmin(admin.ModelAdmin):
|
|
|
|
|
inlines = [
|
|
|
|
|
WidgetInline,
|
|
|
|
|
DooHickeyInline,
|
|
|
|
|
GrommetInline,
|
|
|
|
|
WhatsitInline,
|
|
|
|
|
FancyDoodadInline,
|
|
|
|
|
CategoryInline,
|
|
|
|
|
]
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class LinkInline(admin.TabularInline):
|
|
|
|
|
model = Link
|
|
|
|
|
extra = 1
|
|
|
|
|
|
2015-12-25 05:32:53 +08:00
|
|
|
|
readonly_fields = ("posted", "multiline", "readonly_link_content")
|
2012-12-06 16:47:51 +08:00
|
|
|
|
|
2021-01-14 00:19:22 +08:00
|
|
|
|
@admin.display
|
2012-12-06 16:47:51 +08:00
|
|
|
|
def multiline(self, instance):
|
|
|
|
|
return "InlineMultiline\ntest\nstring"
|
2011-09-21 02:16:49 +08:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class SubPostInline(admin.TabularInline):
|
|
|
|
|
model = PrePopulatedSubPost
|
|
|
|
|
|
|
|
|
|
prepopulated_fields = {"subslug": ("subtitle",)}
|
|
|
|
|
|
|
|
|
|
def get_readonly_fields(self, request, obj=None):
|
|
|
|
|
if obj and obj.published:
|
|
|
|
|
return ("subslug",)
|
|
|
|
|
return self.readonly_fields
|
|
|
|
|
|
|
|
|
|
def get_prepopulated_fields(self, request, obj=None):
|
|
|
|
|
if obj and obj.published:
|
|
|
|
|
return {}
|
|
|
|
|
return self.prepopulated_fields
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class PrePopulatedPostAdmin(admin.ModelAdmin):
|
|
|
|
|
list_display = ["title", "slug"]
|
|
|
|
|
prepopulated_fields = {"slug": ("title",)}
|
|
|
|
|
|
|
|
|
|
inlines = [SubPostInline]
|
|
|
|
|
|
|
|
|
|
def get_readonly_fields(self, request, obj=None):
|
|
|
|
|
if obj and obj.published:
|
|
|
|
|
return ("slug",)
|
|
|
|
|
return self.readonly_fields
|
|
|
|
|
|
|
|
|
|
def get_prepopulated_fields(self, request, obj=None):
|
|
|
|
|
if obj and obj.published:
|
|
|
|
|
return {}
|
|
|
|
|
return self.prepopulated_fields
|
|
|
|
|
|
|
|
|
|
|
2018-11-10 04:41:55 +08:00
|
|
|
|
class PrePopulatedPostReadOnlyAdmin(admin.ModelAdmin):
|
|
|
|
|
prepopulated_fields = {"slug": ("title",)}
|
|
|
|
|
|
|
|
|
|
def has_change_permission(self, *args, **kwargs):
|
|
|
|
|
return False
|
|
|
|
|
|
|
|
|
|
|
2011-09-21 02:16:49 +08:00
|
|
|
|
class PostAdmin(admin.ModelAdmin):
|
|
|
|
|
list_display = ["title", "public"]
|
2012-11-18 00:06:24 +08:00
|
|
|
|
readonly_fields = (
|
2014-03-23 00:00:50 +08:00
|
|
|
|
"posted",
|
|
|
|
|
"awesomeness_level",
|
|
|
|
|
"coolness",
|
|
|
|
|
"value",
|
2015-09-09 03:46:26 +08:00
|
|
|
|
"multiline",
|
|
|
|
|
"multiline_html",
|
|
|
|
|
lambda obj: "foo",
|
2016-12-31 21:26:23 +08:00
|
|
|
|
"readonly_content",
|
2012-11-18 00:06:24 +08:00
|
|
|
|
)
|
2011-09-21 02:16:49 +08:00
|
|
|
|
|
|
|
|
|
inlines = [LinkInline]
|
|
|
|
|
|
2021-01-14 00:19:22 +08:00
|
|
|
|
@admin.display
|
2011-09-21 02:16:49 +08:00
|
|
|
|
def coolness(self, instance):
|
|
|
|
|
if instance.pk:
|
|
|
|
|
return "%d amount of cool." % instance.pk
|
|
|
|
|
else:
|
2014-04-27 01:18:45 +08:00
|
|
|
|
return "Unknown coolness."
|
2011-09-21 02:16:49 +08:00
|
|
|
|
|
2021-01-14 00:19:22 +08:00
|
|
|
|
@admin.display(description="Value in $US")
|
2011-09-21 02:16:49 +08:00
|
|
|
|
def value(self, instance):
|
|
|
|
|
return 1000
|
2012-11-18 00:06:24 +08:00
|
|
|
|
|
2021-01-14 00:19:22 +08:00
|
|
|
|
@admin.display
|
2012-11-18 00:06:24 +08:00
|
|
|
|
def multiline(self, instance):
|
|
|
|
|
return "Multiline\ntest\nstring"
|
|
|
|
|
|
2021-01-14 00:19:22 +08:00
|
|
|
|
@admin.display
|
2014-03-23 00:00:50 +08:00
|
|
|
|
def multiline_html(self, instance):
|
|
|
|
|
return mark_safe("Multiline<br>\nhtml<br>\ncontent")
|
|
|
|
|
|
2011-09-21 02:16:49 +08:00
|
|
|
|
|
2014-02-19 06:44:33 +08:00
|
|
|
|
class FieldOverridePostForm(forms.ModelForm):
|
|
|
|
|
model = FieldOverridePost
|
|
|
|
|
|
|
|
|
|
class Meta:
|
|
|
|
|
help_texts = {
|
|
|
|
|
"posted": "Overridden help text for the date",
|
|
|
|
|
}
|
|
|
|
|
labels = {
|
|
|
|
|
"public": "Overridden public label",
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class FieldOverridePostAdmin(PostAdmin):
|
|
|
|
|
form = FieldOverridePostForm
|
|
|
|
|
|
|
|
|
|
|
2011-09-21 02:16:49 +08:00
|
|
|
|
class CustomChangeList(ChangeList):
|
2013-03-08 22:15:23 +08:00
|
|
|
|
def get_queryset(self, request):
|
2016-06-07 19:24:19 +08:00
|
|
|
|
return self.root_queryset.order_by("pk").filter(pk=9999) # Doesn't exist
|
2011-09-21 02:16:49 +08:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class GadgetAdmin(admin.ModelAdmin):
|
|
|
|
|
def get_changelist(self, request, **kwargs):
|
|
|
|
|
return CustomChangeList
|
|
|
|
|
|
|
|
|
|
|
2013-08-29 21:39:31 +08:00
|
|
|
|
class ToppingAdmin(admin.ModelAdmin):
|
|
|
|
|
readonly_fields = ("pizzas",)
|
|
|
|
|
|
|
|
|
|
|
2011-09-21 02:16:49 +08:00
|
|
|
|
class PizzaAdmin(admin.ModelAdmin):
|
|
|
|
|
readonly_fields = ("toppings",)
|
|
|
|
|
|
|
|
|
|
|
2020-01-19 02:03:03 +08:00
|
|
|
|
class ReadOnlyRelatedFieldAdmin(admin.ModelAdmin):
|
|
|
|
|
readonly_fields = ("chapter", "language", "user")
|
|
|
|
|
|
|
|
|
|
|
2017-05-10 20:48:57 +08:00
|
|
|
|
class StudentAdmin(admin.ModelAdmin):
|
|
|
|
|
search_fields = ("name",)
|
|
|
|
|
|
|
|
|
|
|
2017-08-23 07:48:55 +08:00
|
|
|
|
class ReadOnlyPizzaAdmin(admin.ModelAdmin):
|
|
|
|
|
readonly_fields = ("name", "toppings")
|
|
|
|
|
|
|
|
|
|
def has_add_permission(self, request):
|
|
|
|
|
return False
|
|
|
|
|
|
|
|
|
|
def has_change_permission(self, request, obj=None):
|
|
|
|
|
return True
|
|
|
|
|
|
|
|
|
|
def has_delete_permission(self, request, obj=None):
|
|
|
|
|
return True
|
|
|
|
|
|
|
|
|
|
|
2011-09-21 02:16:49 +08:00
|
|
|
|
class WorkHourAdmin(admin.ModelAdmin):
|
|
|
|
|
list_display = ("datum", "employee")
|
|
|
|
|
list_filter = ("employee",)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class FoodDeliveryAdmin(admin.ModelAdmin):
|
2013-10-23 18:09:29 +08:00
|
|
|
|
list_display = ("reference", "driver", "restaurant")
|
2011-09-21 02:16:49 +08:00
|
|
|
|
list_editable = ("driver", "restaurant")
|
|
|
|
|
|
|
|
|
|
|
2012-12-25 03:17:16 +08:00
|
|
|
|
class CoverLetterAdmin(admin.ModelAdmin):
|
|
|
|
|
"""
|
2013-03-08 22:15:23 +08:00
|
|
|
|
A ModelAdmin with a custom get_queryset() method that uses defer(), to test
|
2012-12-25 03:17:16 +08:00
|
|
|
|
verbose_name display in messages shown after adding/editing CoverLetter
|
2015-11-20 04:33:22 +08:00
|
|
|
|
instances. Note that the CoverLetter model defines a __str__ method.
|
2012-12-25 03:17:16 +08:00
|
|
|
|
For testing fix for ticket #14529.
|
|
|
|
|
"""
|
|
|
|
|
|
2013-03-08 22:15:23 +08:00
|
|
|
|
def get_queryset(self, request):
|
2017-01-21 21:13:44 +08:00
|
|
|
|
return super().get_queryset(request).defer("date_written")
|
2012-12-25 03:17:16 +08:00
|
|
|
|
|
|
|
|
|
|
2011-09-21 02:16:49 +08:00
|
|
|
|
class PaperAdmin(admin.ModelAdmin):
|
|
|
|
|
"""
|
2013-03-08 22:15:23 +08:00
|
|
|
|
A ModelAdmin with a custom get_queryset() method that uses only(), to test
|
2012-12-25 03:17:16 +08:00
|
|
|
|
verbose_name display in messages shown after adding/editing Paper
|
|
|
|
|
instances.
|
|
|
|
|
For testing fix for ticket #14529.
|
2011-09-21 02:16:49 +08:00
|
|
|
|
"""
|
|
|
|
|
|
2013-03-08 22:15:23 +08:00
|
|
|
|
def get_queryset(self, request):
|
2017-01-21 21:13:44 +08:00
|
|
|
|
return super().get_queryset(request).only("title")
|
2011-09-21 02:16:49 +08:00
|
|
|
|
|
|
|
|
|
|
2012-12-25 03:17:16 +08:00
|
|
|
|
class ShortMessageAdmin(admin.ModelAdmin):
|
|
|
|
|
"""
|
2013-03-08 22:15:23 +08:00
|
|
|
|
A ModelAdmin with a custom get_queryset() method that uses defer(), to test
|
2012-12-25 03:17:16 +08:00
|
|
|
|
verbose_name display in messages shown after adding/editing ShortMessage
|
|
|
|
|
instances.
|
|
|
|
|
For testing fix for ticket #14529.
|
|
|
|
|
"""
|
|
|
|
|
|
2013-03-08 22:15:23 +08:00
|
|
|
|
def get_queryset(self, request):
|
2017-01-21 21:13:44 +08:00
|
|
|
|
return super().get_queryset(request).defer("timestamp")
|
2012-12-25 03:17:16 +08:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class TelegramAdmin(admin.ModelAdmin):
|
2011-09-21 02:16:49 +08:00
|
|
|
|
"""
|
2013-03-08 22:15:23 +08:00
|
|
|
|
A ModelAdmin with a custom get_queryset() method that uses only(), to test
|
2012-12-25 03:17:16 +08:00
|
|
|
|
verbose_name display in messages shown after adding/editing Telegram
|
2015-11-20 04:33:22 +08:00
|
|
|
|
instances. Note that the Telegram model defines a __str__ method.
|
2012-12-25 03:17:16 +08:00
|
|
|
|
For testing fix for ticket #14529.
|
2011-09-21 02:16:49 +08:00
|
|
|
|
"""
|
|
|
|
|
|
2013-03-08 22:15:23 +08:00
|
|
|
|
def get_queryset(self, request):
|
2017-01-21 21:13:44 +08:00
|
|
|
|
return super().get_queryset(request).only("title")
|
2011-09-21 02:16:49 +08:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class StoryForm(forms.ModelForm):
|
|
|
|
|
class Meta:
|
|
|
|
|
widgets = {"title": forms.HiddenInput}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class StoryAdmin(admin.ModelAdmin):
|
|
|
|
|
list_display = ("id", "title", "content")
|
2013-11-03 05:02:56 +08:00
|
|
|
|
list_display_links = ("title",) # 'id' not in list_display_links
|
2017-12-29 04:07:29 +08:00
|
|
|
|
list_editable = ("content",)
|
2011-09-21 02:16:49 +08:00
|
|
|
|
form = StoryForm
|
2016-08-05 22:20:38 +08:00
|
|
|
|
ordering = ["-id"]
|
2011-09-21 02:16:49 +08:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class OtherStoryAdmin(admin.ModelAdmin):
|
|
|
|
|
list_display = ("id", "title", "content")
|
2013-11-03 05:02:56 +08:00
|
|
|
|
list_display_links = ("title", "id") # 'id' in list_display_links
|
2017-12-29 04:07:29 +08:00
|
|
|
|
list_editable = ("content",)
|
2016-08-05 22:20:38 +08:00
|
|
|
|
ordering = ["-id"]
|
2011-09-21 02:16:49 +08:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class ComplexSortedPersonAdmin(admin.ModelAdmin):
|
|
|
|
|
list_display = ("name", "age", "is_employee", "colored_name")
|
|
|
|
|
ordering = ("name",)
|
|
|
|
|
|
2021-01-14 00:19:22 +08:00
|
|
|
|
@admin.display(ordering="name")
|
2011-09-21 02:16:49 +08:00
|
|
|
|
def colored_name(self, obj):
|
2015-09-09 03:46:26 +08:00
|
|
|
|
return format_html('<span style="color: #ff00ff;">{}</span>', obj.name)
|
2011-09-21 02:16:49 +08:00
|
|
|
|
|
|
|
|
|
|
2013-05-19 16:52:29 +08:00
|
|
|
|
class PluggableSearchPersonAdmin(admin.ModelAdmin):
|
|
|
|
|
list_display = ("name", "age")
|
|
|
|
|
search_fields = ("name",)
|
|
|
|
|
|
|
|
|
|
def get_search_results(self, request, queryset, search_term):
|
2021-04-26 15:30:40 +08:00
|
|
|
|
queryset, may_have_duplicates = super().get_search_results(
|
|
|
|
|
request,
|
|
|
|
|
queryset,
|
|
|
|
|
search_term,
|
|
|
|
|
)
|
2013-05-19 16:52:29 +08:00
|
|
|
|
try:
|
|
|
|
|
search_term_as_int = int(search_term)
|
2015-11-16 02:52:47 +08:00
|
|
|
|
except ValueError:
|
2013-05-19 16:52:29 +08:00
|
|
|
|
pass
|
2015-11-16 02:52:47 +08:00
|
|
|
|
else:
|
|
|
|
|
queryset |= self.model.objects.filter(age=search_term_as_int)
|
2021-04-26 15:30:40 +08:00
|
|
|
|
return queryset, may_have_duplicates
|
2013-05-19 16:52:29 +08:00
|
|
|
|
|
|
|
|
|
|
2011-09-21 02:16:49 +08:00
|
|
|
|
class AlbumAdmin(admin.ModelAdmin):
|
|
|
|
|
list_filter = ["title"]
|
|
|
|
|
|
|
|
|
|
|
2017-05-10 20:48:57 +08:00
|
|
|
|
class QuestionAdmin(admin.ModelAdmin):
|
|
|
|
|
ordering = ["-posted"]
|
|
|
|
|
search_fields = ["question"]
|
|
|
|
|
autocomplete_fields = ["related_questions"]
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class AnswerAdmin(admin.ModelAdmin):
|
|
|
|
|
autocomplete_fields = ["question"]
|
|
|
|
|
|
|
|
|
|
|
2011-11-22 17:14:09 +08:00
|
|
|
|
class PrePopulatedPostLargeSlugAdmin(admin.ModelAdmin):
|
|
|
|
|
prepopulated_fields = {"slug": ("title",)}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class AdminOrderedFieldAdmin(admin.ModelAdmin):
|
|
|
|
|
ordering = ("order",)
|
|
|
|
|
list_display = ("stuff", "order")
|
|
|
|
|
|
2013-11-03 06:50:35 +08:00
|
|
|
|
|
2011-11-22 17:14:09 +08:00
|
|
|
|
class AdminOrderedModelMethodAdmin(admin.ModelAdmin):
|
|
|
|
|
ordering = ("order",)
|
|
|
|
|
list_display = ("stuff", "some_order")
|
|
|
|
|
|
2013-11-03 06:50:35 +08:00
|
|
|
|
|
2011-11-22 17:14:09 +08:00
|
|
|
|
class AdminOrderedAdminMethodAdmin(admin.ModelAdmin):
|
2021-01-14 00:19:22 +08:00
|
|
|
|
@admin.display(ordering="order")
|
2011-11-22 17:14:09 +08:00
|
|
|
|
def some_admin_order(self, obj):
|
|
|
|
|
return obj.order
|
2022-02-04 03:24:19 +08:00
|
|
|
|
|
2011-11-22 17:14:09 +08:00
|
|
|
|
ordering = ("order",)
|
|
|
|
|
list_display = ("stuff", "some_admin_order")
|
|
|
|
|
|
2013-11-03 06:50:35 +08:00
|
|
|
|
|
2021-01-14 00:19:22 +08:00
|
|
|
|
@admin.display(ordering="order")
|
2011-11-22 17:14:09 +08:00
|
|
|
|
def admin_ordered_callable(obj):
|
|
|
|
|
return obj.order
|
2016-11-13 01:11:23 +08:00
|
|
|
|
|
|
|
|
|
|
2011-11-22 17:14:09 +08:00
|
|
|
|
class AdminOrderedCallableAdmin(admin.ModelAdmin):
|
|
|
|
|
ordering = ("order",)
|
|
|
|
|
list_display = ("stuff", admin_ordered_callable)
|
|
|
|
|
|
2013-11-03 06:50:35 +08:00
|
|
|
|
|
2011-12-19 22:59:14 +08:00
|
|
|
|
class ReportAdmin(admin.ModelAdmin):
|
|
|
|
|
def extra(self, request):
|
|
|
|
|
return HttpResponse()
|
|
|
|
|
|
|
|
|
|
def get_urls(self):
|
|
|
|
|
# Corner case: Don't call parent implementation
|
2018-12-08 06:52:28 +08:00
|
|
|
|
return [path("extra/", self.extra, name="cable_extra")]
|
2011-11-22 17:14:09 +08:00
|
|
|
|
|
2012-02-05 18:26:05 +08:00
|
|
|
|
|
2012-02-10 02:59:05 +08:00
|
|
|
|
class CustomTemplateBooleanFieldListFilter(BooleanFieldListFilter):
|
|
|
|
|
template = "custom_filter_template.html"
|
|
|
|
|
|
2013-11-03 06:50:35 +08:00
|
|
|
|
|
2012-02-10 02:59:05 +08:00
|
|
|
|
class CustomTemplateFilterColorAdmin(admin.ModelAdmin):
|
|
|
|
|
list_filter = (("warm", CustomTemplateBooleanFieldListFilter),)
|
|
|
|
|
|
2012-02-20 00:42:12 +08:00
|
|
|
|
|
|
|
|
|
# For Selenium Prepopulated tests -------------------------------------
|
|
|
|
|
class RelatedPrepopulatedInline1(admin.StackedInline):
|
|
|
|
|
fieldsets = (
|
|
|
|
|
(
|
|
|
|
|
None,
|
|
|
|
|
{
|
2017-05-10 20:48:57 +08:00
|
|
|
|
"fields": (
|
|
|
|
|
("fk", "m2m"),
|
|
|
|
|
("pubdate", "status"),
|
|
|
|
|
(
|
|
|
|
|
"name",
|
|
|
|
|
"slug1",
|
|
|
|
|
"slug2",
|
|
|
|
|
),
|
2012-02-20 00:42:12 +08:00
|
|
|
|
),
|
|
|
|
|
},
|
2022-02-04 03:24:19 +08:00
|
|
|
|
),
|
2012-02-20 00:42:12 +08:00
|
|
|
|
)
|
2015-07-05 01:24:28 +08:00
|
|
|
|
formfield_overrides = {models.CharField: {"strip": False}}
|
2012-02-20 00:42:12 +08:00
|
|
|
|
model = RelatedPrepopulated
|
|
|
|
|
extra = 1
|
2017-05-10 20:48:57 +08:00
|
|
|
|
autocomplete_fields = ["fk", "m2m"]
|
2019-01-03 07:18:19 +08:00
|
|
|
|
prepopulated_fields = {
|
|
|
|
|
"slug1": ["name", "pubdate"],
|
|
|
|
|
"slug2": ["status", "name"],
|
|
|
|
|
}
|
2012-02-20 00:42:12 +08:00
|
|
|
|
|
2013-11-03 06:50:35 +08:00
|
|
|
|
|
2012-02-20 00:42:12 +08:00
|
|
|
|
class RelatedPrepopulatedInline2(admin.TabularInline):
|
|
|
|
|
model = RelatedPrepopulated
|
|
|
|
|
extra = 1
|
2017-05-10 20:48:57 +08:00
|
|
|
|
autocomplete_fields = ["fk", "m2m"]
|
2019-01-03 07:18:19 +08:00
|
|
|
|
prepopulated_fields = {
|
|
|
|
|
"slug1": ["name", "pubdate"],
|
|
|
|
|
"slug2": ["status", "name"],
|
|
|
|
|
}
|
2012-02-20 00:42:12 +08:00
|
|
|
|
|
2013-11-03 06:50:35 +08:00
|
|
|
|
|
2017-05-10 20:48:57 +08:00
|
|
|
|
class RelatedPrepopulatedInline3(admin.TabularInline):
|
|
|
|
|
model = RelatedPrepopulated
|
|
|
|
|
extra = 0
|
|
|
|
|
autocomplete_fields = ["fk", "m2m"]
|
|
|
|
|
|
|
|
|
|
|
2021-11-15 22:27:11 +08:00
|
|
|
|
class RelatedPrepopulatedStackedInlineNoFieldsets(admin.StackedInline):
|
|
|
|
|
model = RelatedPrepopulated
|
|
|
|
|
extra = 1
|
|
|
|
|
prepopulated_fields = {
|
|
|
|
|
"slug1": ["name", "pubdate"],
|
|
|
|
|
"slug2": ["status"],
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2012-02-20 00:42:12 +08:00
|
|
|
|
class MainPrepopulatedAdmin(admin.ModelAdmin):
|
2021-11-15 22:27:11 +08:00
|
|
|
|
inlines = [
|
|
|
|
|
RelatedPrepopulatedInline1,
|
|
|
|
|
RelatedPrepopulatedInline2,
|
|
|
|
|
RelatedPrepopulatedInline3,
|
|
|
|
|
RelatedPrepopulatedStackedInlineNoFieldsets,
|
|
|
|
|
]
|
2012-02-20 00:42:12 +08:00
|
|
|
|
fieldsets = (
|
|
|
|
|
(
|
|
|
|
|
None,
|
2015-04-16 06:28:49 +08:00
|
|
|
|
{"fields": (("pubdate", "status"), ("name", "slug1", "slug2", "slug3"))},
|
2012-02-20 00:42:12 +08:00
|
|
|
|
),
|
|
|
|
|
)
|
2015-07-05 01:24:28 +08:00
|
|
|
|
formfield_overrides = {models.CharField: {"strip": False}}
|
2015-04-16 06:28:49 +08:00
|
|
|
|
prepopulated_fields = {
|
|
|
|
|
"slug1": ["name", "pubdate"],
|
|
|
|
|
"slug2": ["status", "name"],
|
|
|
|
|
"slug3": ["name"],
|
|
|
|
|
}
|
2012-02-20 00:42:12 +08:00
|
|
|
|
|
|
|
|
|
|
2012-03-03 10:13:35 +08:00
|
|
|
|
class UnorderedObjectAdmin(admin.ModelAdmin):
|
2016-08-05 22:20:38 +08:00
|
|
|
|
list_display = ["id", "name"]
|
|
|
|
|
list_display_links = ["id"]
|
2012-03-03 10:13:35 +08:00
|
|
|
|
list_editable = ["name"]
|
|
|
|
|
list_per_page = 2
|
|
|
|
|
|
2012-02-20 00:42:12 +08:00
|
|
|
|
|
2012-07-22 09:10:24 +08:00
|
|
|
|
class UndeletableObjectAdmin(admin.ModelAdmin):
|
|
|
|
|
def change_view(self, *args, **kwargs):
|
|
|
|
|
kwargs["extra_context"] = {"show_delete": False}
|
2017-01-21 21:13:44 +08:00
|
|
|
|
return super().change_view(*args, **kwargs)
|
2012-07-22 09:10:24 +08:00
|
|
|
|
|
2012-02-20 00:42:12 +08:00
|
|
|
|
|
2013-08-18 06:05:13 +08:00
|
|
|
|
class UnchangeableObjectAdmin(admin.ModelAdmin):
|
|
|
|
|
def get_urls(self):
|
|
|
|
|
# Disable change_view, but leave other urls untouched
|
2017-01-21 21:13:44 +08:00
|
|
|
|
urlpatterns = super().get_urls()
|
2015-02-08 00:55:47 +08:00
|
|
|
|
return [p for p in urlpatterns if p.name and not p.name.endswith("_change")]
|
2013-08-18 06:05:13 +08:00
|
|
|
|
|
|
|
|
|
|
2021-01-14 00:19:22 +08:00
|
|
|
|
@admin.display
|
2012-09-08 23:18:08 +08:00
|
|
|
|
def callable_on_unknown(obj):
|
|
|
|
|
return obj.unknown
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class AttributeErrorRaisingAdmin(admin.ModelAdmin):
|
2017-12-29 04:07:29 +08:00
|
|
|
|
list_display = [callable_on_unknown]
|
2012-09-08 23:18:08 +08:00
|
|
|
|
|
2013-09-07 04:28:48 +08:00
|
|
|
|
|
|
|
|
|
class CustomManagerAdmin(admin.ModelAdmin):
|
|
|
|
|
def get_queryset(self, request):
|
|
|
|
|
return FilteredManager.objects
|
|
|
|
|
|
|
|
|
|
|
2012-11-18 05:53:31 +08:00
|
|
|
|
class MessageTestingAdmin(admin.ModelAdmin):
|
|
|
|
|
actions = [
|
|
|
|
|
"message_debug",
|
|
|
|
|
"message_info",
|
|
|
|
|
"message_success",
|
|
|
|
|
"message_warning",
|
|
|
|
|
"message_error",
|
|
|
|
|
"message_extra_tags",
|
|
|
|
|
]
|
|
|
|
|
|
2021-01-14 00:19:22 +08:00
|
|
|
|
@admin.action
|
2012-11-18 05:53:31 +08:00
|
|
|
|
def message_debug(self, request, selected):
|
|
|
|
|
self.message_user(request, "Test debug", level="debug")
|
|
|
|
|
|
2021-01-14 00:19:22 +08:00
|
|
|
|
@admin.action
|
2012-11-18 05:53:31 +08:00
|
|
|
|
def message_info(self, request, selected):
|
|
|
|
|
self.message_user(request, "Test info", level="info")
|
|
|
|
|
|
2021-01-14 00:19:22 +08:00
|
|
|
|
@admin.action
|
2012-11-18 05:53:31 +08:00
|
|
|
|
def message_success(self, request, selected):
|
|
|
|
|
self.message_user(request, "Test success", level="success")
|
|
|
|
|
|
2021-01-14 00:19:22 +08:00
|
|
|
|
@admin.action
|
2012-11-18 05:53:31 +08:00
|
|
|
|
def message_warning(self, request, selected):
|
|
|
|
|
self.message_user(request, "Test warning", level="warning")
|
|
|
|
|
|
2021-01-14 00:19:22 +08:00
|
|
|
|
@admin.action
|
2012-11-18 05:53:31 +08:00
|
|
|
|
def message_error(self, request, selected):
|
|
|
|
|
self.message_user(request, "Test error", level="error")
|
|
|
|
|
|
2021-01-14 00:19:22 +08:00
|
|
|
|
@admin.action
|
2012-11-18 05:53:31 +08:00
|
|
|
|
def message_extra_tags(self, request, selected):
|
|
|
|
|
self.message_user(request, "Test tags", extra_tags="extra_tag")
|
|
|
|
|
|
2012-09-08 23:18:08 +08:00
|
|
|
|
|
2012-11-26 06:13:22 +08:00
|
|
|
|
class ChoiceList(admin.ModelAdmin):
|
|
|
|
|
list_display = ["choice"]
|
|
|
|
|
readonly_fields = ["choice"]
|
|
|
|
|
fields = ["choice"]
|
|
|
|
|
|
|
|
|
|
|
2013-11-15 10:26:19 +08:00
|
|
|
|
class DependentChildAdminForm(forms.ModelForm):
|
|
|
|
|
"""
|
|
|
|
|
Issue #20522
|
|
|
|
|
Form to test child dependency on parent object's validation
|
|
|
|
|
"""
|
2022-02-04 03:24:19 +08:00
|
|
|
|
|
2013-11-15 10:26:19 +08:00
|
|
|
|
def clean(self):
|
|
|
|
|
parent = self.cleaned_data.get("parent")
|
|
|
|
|
if parent.family_name and parent.family_name != self.cleaned_data.get(
|
|
|
|
|
"family_name"
|
|
|
|
|
):
|
|
|
|
|
raise ValidationError(
|
|
|
|
|
"Children must share a family name with their parents "
|
|
|
|
|
+ "in this contrived test case"
|
|
|
|
|
)
|
2017-01-21 21:13:44 +08:00
|
|
|
|
return super().clean()
|
2013-11-15 10:26:19 +08:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class DependentChildInline(admin.TabularInline):
|
|
|
|
|
model = DependentChild
|
|
|
|
|
form = DependentChildAdminForm
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class ParentWithDependentChildrenAdmin(admin.ModelAdmin):
|
|
|
|
|
inlines = [DependentChildInline]
|
|
|
|
|
|
|
|
|
|
|
2013-02-24 01:57:48 +08:00
|
|
|
|
# Tests for ticket 11277 ----------------------------------
|
|
|
|
|
|
2022-02-04 03:24:19 +08:00
|
|
|
|
|
2013-02-24 01:57:48 +08:00
|
|
|
|
class FormWithoutHiddenField(forms.ModelForm):
|
|
|
|
|
first = forms.CharField()
|
|
|
|
|
second = forms.CharField()
|
|
|
|
|
|
2013-11-03 06:50:35 +08:00
|
|
|
|
|
2013-02-24 01:57:48 +08:00
|
|
|
|
class FormWithoutVisibleField(forms.ModelForm):
|
|
|
|
|
first = forms.CharField(widget=forms.HiddenInput)
|
|
|
|
|
second = forms.CharField(widget=forms.HiddenInput)
|
|
|
|
|
|
2013-11-03 06:50:35 +08:00
|
|
|
|
|
2013-02-24 01:57:48 +08:00
|
|
|
|
class FormWithVisibleAndHiddenField(forms.ModelForm):
|
|
|
|
|
first = forms.CharField(widget=forms.HiddenInput)
|
|
|
|
|
second = forms.CharField()
|
|
|
|
|
|
2013-11-03 06:50:35 +08:00
|
|
|
|
|
2013-02-24 01:57:48 +08:00
|
|
|
|
class EmptyModelVisibleAdmin(admin.ModelAdmin):
|
|
|
|
|
form = FormWithoutHiddenField
|
|
|
|
|
fieldsets = (
|
|
|
|
|
(
|
|
|
|
|
None,
|
|
|
|
|
{
|
2013-10-25 01:30:03 +08:00
|
|
|
|
"fields": (("first", "second"),),
|
2013-02-24 01:57:48 +08:00
|
|
|
|
},
|
|
|
|
|
),
|
|
|
|
|
)
|
|
|
|
|
|
2013-11-03 06:50:35 +08:00
|
|
|
|
|
2013-02-24 01:57:48 +08:00
|
|
|
|
class EmptyModelHiddenAdmin(admin.ModelAdmin):
|
|
|
|
|
form = FormWithoutVisibleField
|
|
|
|
|
fieldsets = EmptyModelVisibleAdmin.fieldsets
|
|
|
|
|
|
2013-11-03 06:50:35 +08:00
|
|
|
|
|
2013-02-24 01:57:48 +08:00
|
|
|
|
class EmptyModelMixinAdmin(admin.ModelAdmin):
|
|
|
|
|
form = FormWithVisibleAndHiddenField
|
|
|
|
|
fieldsets = EmptyModelVisibleAdmin.fieldsets
|
|
|
|
|
|
2013-11-03 06:50:35 +08:00
|
|
|
|
|
2013-10-24 23:28:09 +08:00
|
|
|
|
class CityInlineAdmin(admin.TabularInline):
|
|
|
|
|
model = City
|
|
|
|
|
view_on_site = False
|
|
|
|
|
|
2013-11-03 06:50:35 +08:00
|
|
|
|
|
2019-06-15 00:20:29 +08:00
|
|
|
|
class StateAdminForm(forms.ModelForm):
|
|
|
|
|
nolabel_form_field = forms.BooleanField(required=False)
|
|
|
|
|
|
|
|
|
|
class Meta:
|
|
|
|
|
model = State
|
|
|
|
|
fields = "__all__"
|
2019-06-28 00:39:47 +08:00
|
|
|
|
labels = {"name": "State name (from form’s Meta.labels)"}
|
2019-06-15 00:20:29 +08:00
|
|
|
|
|
|
|
|
|
@property
|
|
|
|
|
def changed_data(self):
|
|
|
|
|
data = super().changed_data
|
|
|
|
|
if data:
|
|
|
|
|
# Add arbitrary name to changed_data to test
|
|
|
|
|
# change message construction.
|
|
|
|
|
return data + ["not_a_form_field"]
|
|
|
|
|
return data
|
|
|
|
|
|
|
|
|
|
|
2013-10-24 23:28:09 +08:00
|
|
|
|
class StateAdmin(admin.ModelAdmin):
|
|
|
|
|
inlines = [CityInlineAdmin]
|
2019-06-15 00:20:29 +08:00
|
|
|
|
form = StateAdminForm
|
2013-10-24 23:28:09 +08:00
|
|
|
|
|
2013-11-03 06:50:35 +08:00
|
|
|
|
|
2013-10-24 23:28:09 +08:00
|
|
|
|
class RestaurantInlineAdmin(admin.TabularInline):
|
|
|
|
|
model = Restaurant
|
|
|
|
|
view_on_site = True
|
|
|
|
|
|
2013-11-03 06:50:35 +08:00
|
|
|
|
|
2013-10-24 23:28:09 +08:00
|
|
|
|
class CityAdmin(admin.ModelAdmin):
|
|
|
|
|
inlines = [RestaurantInlineAdmin]
|
|
|
|
|
view_on_site = True
|
|
|
|
|
|
2020-11-27 04:51:35 +08:00
|
|
|
|
def get_formset_kwargs(self, request, obj, inline, prefix):
|
|
|
|
|
return {
|
|
|
|
|
**super().get_formset_kwargs(request, obj, inline, prefix),
|
|
|
|
|
"form_kwargs": {"initial": {"name": "overridden_name"}},
|
|
|
|
|
}
|
|
|
|
|
|
2013-11-03 06:50:35 +08:00
|
|
|
|
|
2013-10-24 23:28:09 +08:00
|
|
|
|
class WorkerAdmin(admin.ModelAdmin):
|
|
|
|
|
def view_on_site(self, obj):
|
|
|
|
|
return "/worker/%s/%s/" % (obj.surname, obj.name)
|
|
|
|
|
|
2013-11-03 06:50:35 +08:00
|
|
|
|
|
2013-10-24 23:28:09 +08:00
|
|
|
|
class WorkerInlineAdmin(admin.TabularInline):
|
|
|
|
|
model = Worker
|
|
|
|
|
|
|
|
|
|
def view_on_site(self, obj):
|
|
|
|
|
return "/worker_inline/%s/%s/" % (obj.surname, obj.name)
|
|
|
|
|
|
2013-11-03 06:50:35 +08:00
|
|
|
|
|
2013-10-24 23:28:09 +08:00
|
|
|
|
class RestaurantAdmin(admin.ModelAdmin):
|
|
|
|
|
inlines = [WorkerInlineAdmin]
|
|
|
|
|
view_on_site = False
|
|
|
|
|
|
2014-02-27 06:34:19 +08:00
|
|
|
|
def get_changeform_initial_data(self, request):
|
|
|
|
|
return {"name": "overridden_value"}
|
|
|
|
|
|
|
|
|
|
|
2014-07-14 19:23:34 +08:00
|
|
|
|
class FunkyTagAdmin(admin.ModelAdmin):
|
|
|
|
|
list_display = ("name", "content_object")
|
|
|
|
|
|
|
|
|
|
|
2014-09-05 05:04:53 +08:00
|
|
|
|
class InlineReferenceInline(admin.TabularInline):
|
|
|
|
|
model = InlineReference
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class InlineRefererAdmin(admin.ModelAdmin):
|
|
|
|
|
inlines = [InlineReferenceInline]
|
|
|
|
|
|
|
|
|
|
|
2016-01-10 04:15:21 +08:00
|
|
|
|
class PlotReadonlyAdmin(admin.ModelAdmin):
|
|
|
|
|
readonly_fields = ("plotdetails",)
|
|
|
|
|
|
|
|
|
|
|
2014-11-28 02:34:14 +08:00
|
|
|
|
class GetFormsetsArgumentCheckingAdmin(admin.ModelAdmin):
|
|
|
|
|
fields = ["name"]
|
|
|
|
|
|
|
|
|
|
def add_view(self, request, *args, **kwargs):
|
|
|
|
|
request.is_add_view = True
|
2017-01-21 21:13:44 +08:00
|
|
|
|
return super().add_view(request, *args, **kwargs)
|
2014-11-28 02:34:14 +08:00
|
|
|
|
|
|
|
|
|
def change_view(self, request, *args, **kwargs):
|
|
|
|
|
request.is_add_view = False
|
2017-01-21 21:13:44 +08:00
|
|
|
|
return super().change_view(request, *args, **kwargs)
|
2014-11-28 02:34:14 +08:00
|
|
|
|
|
|
|
|
|
def get_formsets_with_inlines(self, request, obj=None):
|
|
|
|
|
if request.is_add_view and obj is not None:
|
|
|
|
|
raise Exception(
|
|
|
|
|
"'obj' passed to get_formsets_with_inlines wasn't None during add_view"
|
|
|
|
|
)
|
|
|
|
|
if not request.is_add_view and obj is None:
|
|
|
|
|
raise Exception(
|
|
|
|
|
"'obj' passed to get_formsets_with_inlines was None during change_view"
|
|
|
|
|
)
|
2017-01-21 21:13:44 +08:00
|
|
|
|
return super().get_formsets_with_inlines(request, obj)
|
2014-11-28 02:34:14 +08:00
|
|
|
|
|
|
|
|
|
|
2011-09-21 02:16:49 +08:00
|
|
|
|
site = admin.AdminSite(name="admin")
|
2014-08-26 19:10:30 +08:00
|
|
|
|
site.site_url = "/my-site-url/"
|
2011-09-21 02:16:49 +08:00
|
|
|
|
site.register(Article, ArticleAdmin)
|
|
|
|
|
site.register(CustomArticle, CustomArticleAdmin)
|
2017-05-10 20:48:57 +08:00
|
|
|
|
site.register(
|
|
|
|
|
Section,
|
|
|
|
|
save_as=True,
|
|
|
|
|
inlines=[ArticleInline],
|
|
|
|
|
readonly_fields=["name_property"],
|
|
|
|
|
search_fields=["name"],
|
|
|
|
|
)
|
2011-09-21 02:16:49 +08:00
|
|
|
|
site.register(ModelWithStringPrimaryKey)
|
|
|
|
|
site.register(Color)
|
|
|
|
|
site.register(Thing, ThingAdmin)
|
|
|
|
|
site.register(Actor)
|
|
|
|
|
site.register(Inquisition, InquisitionAdmin)
|
|
|
|
|
site.register(Sketch, SketchAdmin)
|
|
|
|
|
site.register(Person, PersonAdmin)
|
|
|
|
|
site.register(Persona, PersonaAdmin)
|
|
|
|
|
site.register(Subscriber, SubscriberAdmin)
|
|
|
|
|
site.register(ExternalSubscriber, ExternalSubscriberAdmin)
|
|
|
|
|
site.register(OldSubscriber, OldSubscriberAdmin)
|
|
|
|
|
site.register(Podcast, PodcastAdmin)
|
|
|
|
|
site.register(Vodcast, VodcastAdmin)
|
|
|
|
|
site.register(Parent, ParentAdmin)
|
|
|
|
|
site.register(EmptyModel, EmptyModelAdmin)
|
|
|
|
|
site.register(Fabric, FabricAdmin)
|
|
|
|
|
site.register(Gallery, GalleryAdmin)
|
|
|
|
|
site.register(Picture, PictureAdmin)
|
|
|
|
|
site.register(Language, LanguageAdmin)
|
|
|
|
|
site.register(Recommendation, RecommendationAdmin)
|
|
|
|
|
site.register(Recommender)
|
|
|
|
|
site.register(Collector, CollectorAdmin)
|
|
|
|
|
site.register(Category, CategoryAdmin)
|
|
|
|
|
site.register(Post, PostAdmin)
|
2014-02-19 06:44:33 +08:00
|
|
|
|
site.register(FieldOverridePost, FieldOverridePostAdmin)
|
2011-09-21 02:16:49 +08:00
|
|
|
|
site.register(Gadget, GadgetAdmin)
|
|
|
|
|
site.register(Villain)
|
|
|
|
|
site.register(SuperVillain)
|
|
|
|
|
site.register(Plot)
|
|
|
|
|
site.register(PlotDetails)
|
2016-01-10 04:15:21 +08:00
|
|
|
|
site.register(PlotProxy, PlotReadonlyAdmin)
|
2015-08-28 04:13:24 +08:00
|
|
|
|
site.register(Bookmark)
|
2011-09-21 02:16:49 +08:00
|
|
|
|
site.register(CyclicOne)
|
|
|
|
|
site.register(CyclicTwo)
|
|
|
|
|
site.register(WorkHour, WorkHourAdmin)
|
|
|
|
|
site.register(Reservation)
|
|
|
|
|
site.register(FoodDelivery, FoodDeliveryAdmin)
|
|
|
|
|
site.register(RowLevelChangePermissionModel, RowLevelChangePermissionModelAdmin)
|
|
|
|
|
site.register(Paper, PaperAdmin)
|
|
|
|
|
site.register(CoverLetter, CoverLetterAdmin)
|
2012-12-25 03:17:16 +08:00
|
|
|
|
site.register(ShortMessage, ShortMessageAdmin)
|
|
|
|
|
site.register(Telegram, TelegramAdmin)
|
2011-09-21 02:16:49 +08:00
|
|
|
|
site.register(Story, StoryAdmin)
|
|
|
|
|
site.register(OtherStory, OtherStoryAdmin)
|
2011-12-19 22:59:14 +08:00
|
|
|
|
site.register(Report, ReportAdmin)
|
2012-02-20 00:42:12 +08:00
|
|
|
|
site.register(MainPrepopulated, MainPrepopulatedAdmin)
|
2012-03-03 10:13:35 +08:00
|
|
|
|
site.register(UnorderedObject, UnorderedObjectAdmin)
|
2012-07-22 09:10:24 +08:00
|
|
|
|
site.register(UndeletableObject, UndeletableObjectAdmin)
|
2013-08-18 06:05:13 +08:00
|
|
|
|
site.register(UnchangeableObject, UnchangeableObjectAdmin)
|
2013-10-24 23:28:09 +08:00
|
|
|
|
site.register(State, StateAdmin)
|
|
|
|
|
site.register(City, CityAdmin)
|
|
|
|
|
site.register(Restaurant, RestaurantAdmin)
|
|
|
|
|
site.register(Worker, WorkerAdmin)
|
2014-07-14 19:23:34 +08:00
|
|
|
|
site.register(FunkyTag, FunkyTagAdmin)
|
2014-08-21 23:55:23 +08:00
|
|
|
|
site.register(ReferencedByParent)
|
|
|
|
|
site.register(ChildOfReferer)
|
2014-09-05 05:04:53 +08:00
|
|
|
|
site.register(ReferencedByInline)
|
|
|
|
|
site.register(InlineReferer, InlineRefererAdmin)
|
2015-10-28 23:25:25 +08:00
|
|
|
|
site.register(ReferencedByGenRel)
|
|
|
|
|
site.register(GenRelReference)
|
2016-01-07 17:07:15 +08:00
|
|
|
|
site.register(ParentWithUUIDPK)
|
2017-05-10 20:48:57 +08:00
|
|
|
|
site.register(RelatedPrepopulated, search_fields=["name"])
|
2016-01-07 17:07:15 +08:00
|
|
|
|
site.register(RelatedWithUUIDPKModel)
|
2020-01-19 02:03:03 +08:00
|
|
|
|
site.register(ReadOnlyRelatedField, ReadOnlyRelatedFieldAdmin)
|
2011-09-21 02:16:49 +08:00
|
|
|
|
|
|
|
|
|
# We intentionally register Promo and ChapterXtra1 but not Chapter nor ChapterXtra2.
|
|
|
|
|
# That way we cover all four cases:
|
|
|
|
|
# related ForeignKey object registered in admin
|
|
|
|
|
# related ForeignKey object not registered in admin
|
|
|
|
|
# related OneToOne object registered in admin
|
|
|
|
|
# related OneToOne object not registered in admin
|
2017-01-22 09:02:00 +08:00
|
|
|
|
# when deleting Book so as exercise all four paths through
|
2013-09-17 00:52:05 +08:00
|
|
|
|
# contrib.admin.utils's get_deleted_objects function.
|
2011-09-21 02:16:49 +08:00
|
|
|
|
site.register(Book, inlines=[ChapterInline])
|
|
|
|
|
site.register(Promo)
|
|
|
|
|
site.register(ChapterXtra1, ChapterXtra1Admin)
|
|
|
|
|
site.register(Pizza, PizzaAdmin)
|
2017-08-23 07:48:55 +08:00
|
|
|
|
site.register(ReadOnlyPizza, ReadOnlyPizzaAdmin)
|
2017-04-05 11:54:46 +08:00
|
|
|
|
site.register(ReadablePizza)
|
2013-08-29 21:39:31 +08:00
|
|
|
|
site.register(Topping, ToppingAdmin)
|
2011-09-21 02:16:49 +08:00
|
|
|
|
site.register(Album, AlbumAdmin)
|
2016-10-10 15:23:35 +08:00
|
|
|
|
site.register(Song)
|
2017-05-10 20:48:57 +08:00
|
|
|
|
site.register(Question, QuestionAdmin)
|
|
|
|
|
site.register(Answer, AnswerAdmin, date_hierarchy="question__posted")
|
2017-02-24 23:22:25 +08:00
|
|
|
|
site.register(Answer2, date_hierarchy="question__expires")
|
2011-09-21 02:16:49 +08:00
|
|
|
|
site.register(PrePopulatedPost, PrePopulatedPostAdmin)
|
|
|
|
|
site.register(ComplexSortedPerson, ComplexSortedPersonAdmin)
|
2013-09-07 04:28:48 +08:00
|
|
|
|
site.register(FilteredManager, CustomManagerAdmin)
|
2013-05-19 16:52:29 +08:00
|
|
|
|
site.register(PluggableSearchPerson, PluggableSearchPersonAdmin)
|
2011-11-22 17:14:09 +08:00
|
|
|
|
site.register(PrePopulatedPostLargeSlug, PrePopulatedPostLargeSlugAdmin)
|
|
|
|
|
site.register(AdminOrderedField, AdminOrderedFieldAdmin)
|
|
|
|
|
site.register(AdminOrderedModelMethod, AdminOrderedModelMethodAdmin)
|
|
|
|
|
site.register(AdminOrderedAdminMethod, AdminOrderedAdminMethodAdmin)
|
|
|
|
|
site.register(AdminOrderedCallable, AdminOrderedCallableAdmin)
|
2012-02-10 02:59:05 +08:00
|
|
|
|
site.register(Color2, CustomTemplateFilterColorAdmin)
|
2012-09-08 23:18:08 +08:00
|
|
|
|
site.register(Simple, AttributeErrorRaisingAdmin)
|
2012-11-18 05:53:31 +08:00
|
|
|
|
site.register(UserMessenger, MessageTestingAdmin)
|
2012-11-26 06:13:22 +08:00
|
|
|
|
site.register(Choice, ChoiceList)
|
2013-11-15 10:26:19 +08:00
|
|
|
|
site.register(ParentWithDependentChildren, ParentWithDependentChildrenAdmin)
|
2013-02-24 01:57:48 +08:00
|
|
|
|
site.register(EmptyModelHidden, EmptyModelHiddenAdmin)
|
|
|
|
|
site.register(EmptyModelVisible, EmptyModelVisibleAdmin)
|
|
|
|
|
site.register(EmptyModelMixin, EmptyModelMixinAdmin)
|
2014-02-02 03:23:31 +08:00
|
|
|
|
site.register(StumpJoke)
|
2014-11-16 23:42:09 +08:00
|
|
|
|
site.register(Recipe)
|
2014-10-06 02:06:51 +08:00
|
|
|
|
site.register(Ingredient)
|
2014-11-16 23:42:09 +08:00
|
|
|
|
site.register(NotReferenced)
|
2014-11-28 02:34:14 +08:00
|
|
|
|
site.register(ExplicitlyProvidedPK, GetFormsetsArgumentCheckingAdmin)
|
|
|
|
|
site.register(ImplicitlyGeneratedPK, GetFormsetsArgumentCheckingAdmin)
|
2019-01-16 23:07:28 +08:00
|
|
|
|
site.register(UserProxy)
|
2021-09-01 20:01:40 +08:00
|
|
|
|
site.register(Box)
|
2011-09-21 02:16:49 +08:00
|
|
|
|
|
|
|
|
|
# Register core models we need in our tests
|
|
|
|
|
site.register(User, UserAdmin)
|
|
|
|
|
site.register(Group, GroupAdmin)
|
2013-07-19 03:17:40 +08:00
|
|
|
|
|
|
|
|
|
# Used to test URL namespaces
|
|
|
|
|
site2 = admin.AdminSite(name="namespaced_admin")
|
|
|
|
|
site2.register(User, UserAdmin)
|
|
|
|
|
site2.register(Group, GroupAdmin)
|
2016-03-25 04:22:35 +08:00
|
|
|
|
site2.register(ParentWithUUIDPK)
|
|
|
|
|
site2.register(
|
|
|
|
|
RelatedWithUUIDPKModel,
|
|
|
|
|
list_display=["pk", "parent"],
|
|
|
|
|
list_editable=["parent"],
|
|
|
|
|
raw_id_fields=["parent"],
|
|
|
|
|
)
|
2016-04-03 22:50:01 +08:00
|
|
|
|
site2.register(Person, save_as_continue=False)
|
2021-09-14 09:10:38 +08:00
|
|
|
|
site2.register(ReadOnlyRelatedField, ReadOnlyRelatedFieldAdmin)
|
|
|
|
|
site2.register(Language)
|
2016-03-25 04:22:35 +08:00
|
|
|
|
|
2014-05-29 00:07:27 +08:00
|
|
|
|
site7 = admin.AdminSite(name="admin7")
|
|
|
|
|
site7.register(Article, ArticleAdmin2)
|
2016-08-02 06:07:50 +08:00
|
|
|
|
site7.register(Section)
|
2018-11-10 04:41:55 +08:00
|
|
|
|
site7.register(PrePopulatedPost, PrePopulatedPostReadOnlyAdmin)
|
2021-11-15 22:27:11 +08:00
|
|
|
|
site7.register(
|
|
|
|
|
Pizza,
|
|
|
|
|
filter_horizontal=["toppings"],
|
|
|
|
|
fieldsets=(
|
|
|
|
|
(
|
|
|
|
|
"Collapsible",
|
|
|
|
|
{
|
|
|
|
|
"classes": ["collapse"],
|
|
|
|
|
"fields": ["toppings"],
|
|
|
|
|
},
|
|
|
|
|
),
|
|
|
|
|
),
|
|
|
|
|
)
|
|
|
|
|
site7.register(
|
|
|
|
|
Question,
|
|
|
|
|
filter_horizontal=["related_questions"],
|
|
|
|
|
fieldsets=(
|
|
|
|
|
(
|
|
|
|
|
"Not collapsible",
|
|
|
|
|
{
|
|
|
|
|
"fields": ["related_questions"],
|
|
|
|
|
},
|
|
|
|
|
),
|
|
|
|
|
),
|
|
|
|
|
)
|
2016-02-09 08:35:03 +08:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# Used to test ModelAdmin.sortable_by and get_sortable_by().
|
|
|
|
|
class ArticleAdmin6(admin.ModelAdmin):
|
|
|
|
|
list_display = (
|
|
|
|
|
"content",
|
|
|
|
|
"date",
|
|
|
|
|
callable_year,
|
|
|
|
|
"model_year",
|
|
|
|
|
"modeladmin_year",
|
|
|
|
|
"model_year_reversed",
|
|
|
|
|
"section",
|
|
|
|
|
)
|
|
|
|
|
sortable_by = ("date", callable_year)
|
|
|
|
|
|
2021-01-14 00:19:22 +08:00
|
|
|
|
@admin.display(ordering="date")
|
2016-02-09 08:35:03 +08:00
|
|
|
|
def modeladmin_year(self, obj):
|
|
|
|
|
return obj.date.year
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class ActorAdmin6(admin.ModelAdmin):
|
|
|
|
|
list_display = ("name", "age")
|
|
|
|
|
sortable_by = ("name",)
|
|
|
|
|
|
|
|
|
|
def get_sortable_by(self, request):
|
|
|
|
|
return ("age",)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class ChapterAdmin6(admin.ModelAdmin):
|
|
|
|
|
list_display = ("title", "book")
|
|
|
|
|
sortable_by = ()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class ColorAdmin6(admin.ModelAdmin):
|
|
|
|
|
list_display = ("value",)
|
|
|
|
|
|
|
|
|
|
def get_sortable_by(self, request):
|
|
|
|
|
return ()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
site6 = admin.AdminSite(name="admin6")
|
|
|
|
|
site6.register(Article, ArticleAdmin6)
|
|
|
|
|
site6.register(Actor, ActorAdmin6)
|
|
|
|
|
site6.register(Chapter, ChapterAdmin6)
|
|
|
|
|
site6.register(Color, ColorAdmin6)
|
2018-06-16 05:05:44 +08:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class ArticleAdmin9(admin.ModelAdmin):
|
|
|
|
|
def has_change_permission(self, request, obj=None):
|
|
|
|
|
# Simulate that the user can't change a specific object.
|
|
|
|
|
return obj is None
|
|
|
|
|
|
|
|
|
|
|
2021-01-12 21:37:56 +08:00
|
|
|
|
class ActorAdmin9(admin.ModelAdmin):
|
|
|
|
|
def get_urls(self):
|
|
|
|
|
# Opt-out of append slash for single model.
|
|
|
|
|
urls = super().get_urls()
|
|
|
|
|
for pattern in urls:
|
|
|
|
|
pattern.callback = no_append_slash(pattern.callback)
|
|
|
|
|
return urls
|
|
|
|
|
|
|
|
|
|
|
2018-06-16 05:05:44 +08:00
|
|
|
|
site9 = admin.AdminSite(name="admin9")
|
|
|
|
|
site9.register(Article, ArticleAdmin9)
|
2021-01-12 21:37:56 +08:00
|
|
|
|
site9.register(Actor, ActorAdmin9)
|
|
|
|
|
|
|
|
|
|
site10 = admin.AdminSite(name="admin10")
|
|
|
|
|
site10.final_catch_all_view = False
|
|
|
|
|
site10.register(Article, ArticleAdminWithExtraUrl)
|