Admin interface greatly improved. Support for editing Attributes added.
Resolves #503. Resolves #201.
This commit is contained in:
parent
fa20190467
commit
ca3f92acd0
6 changed files with 268 additions and 110 deletions
|
|
@ -5,6 +5,15 @@
|
||||||
|
|
||||||
from django.contrib import admin
|
from django.contrib import admin
|
||||||
from src.comms.models import ChannelDB
|
from src.comms.models import ChannelDB
|
||||||
|
from src.typeclasses.admin import AttributeInline, TagInline
|
||||||
|
|
||||||
|
|
||||||
|
class ChannelAttributeInline(AttributeInline):
|
||||||
|
model = ChannelDB.db_attributes.through
|
||||||
|
|
||||||
|
|
||||||
|
class ChannelTagInline(TagInline):
|
||||||
|
model = ChannelDB.db_tags.through
|
||||||
|
|
||||||
|
|
||||||
class MsgAdmin(admin.ModelAdmin):
|
class MsgAdmin(admin.ModelAdmin):
|
||||||
|
|
@ -21,6 +30,7 @@ class MsgAdmin(admin.ModelAdmin):
|
||||||
|
|
||||||
|
|
||||||
class ChannelAdmin(admin.ModelAdmin):
|
class ChannelAdmin(admin.ModelAdmin):
|
||||||
|
inlines = [ChannelTagInline, ChannelAttributeInline]
|
||||||
list_display = ('id', 'db_key', 'db_lock_storage', "subscriptions")
|
list_display = ('id', 'db_key', 'db_lock_storage', "subscriptions")
|
||||||
list_display_links = ("id", 'db_key')
|
list_display_links = ("id", 'db_key')
|
||||||
ordering = ["db_key"]
|
ordering = ["db_key"]
|
||||||
|
|
|
||||||
|
|
@ -6,27 +6,16 @@
|
||||||
from django import forms
|
from django import forms
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.contrib import admin
|
from django.contrib import admin
|
||||||
from src.typeclasses.models import Attribute, Tag
|
from src.typeclasses.admin import AttributeInline, TagInline
|
||||||
from src.objects.models import ObjectDB
|
from src.objects.models import ObjectDB
|
||||||
|
|
||||||
|
|
||||||
class AttributeInline(admin.TabularInline):
|
class ObjectAttributeInline(AttributeInline):
|
||||||
# This class is currently not used, because PickleField objects are
|
model = ObjectDB.db_attributes.through
|
||||||
# not editable. It's here for us to ponder making a way that allows
|
|
||||||
# them to be edited.
|
|
||||||
model = Attribute
|
|
||||||
fields = ('db_key', 'db_value')
|
|
||||||
extra = 0
|
|
||||||
|
|
||||||
|
|
||||||
class TagInline(admin.TabularInline):
|
class ObjectTagInline(TagInline):
|
||||||
model = ObjectDB.db_tags.through
|
model = ObjectDB.db_tags.through
|
||||||
raw_id_fields = ('tag',)
|
|
||||||
extra = 0
|
|
||||||
|
|
||||||
|
|
||||||
class TagAdmin(admin.ModelAdmin):
|
|
||||||
fields = ('db_key', 'db_category', 'db_data')
|
|
||||||
|
|
||||||
|
|
||||||
class ObjectCreateForm(forms.ModelForm):
|
class ObjectCreateForm(forms.ModelForm):
|
||||||
|
|
@ -59,6 +48,7 @@ class ObjectEditForm(ObjectCreateForm):
|
||||||
|
|
||||||
class ObjectDBAdmin(admin.ModelAdmin):
|
class ObjectDBAdmin(admin.ModelAdmin):
|
||||||
|
|
||||||
|
inlines = [ObjectTagInline, ObjectAttributeInline]
|
||||||
list_display = ('id', 'db_key', 'db_player', 'db_typeclass_path')
|
list_display = ('id', 'db_key', 'db_player', 'db_typeclass_path')
|
||||||
list_display_links = ('id', 'db_key')
|
list_display_links = ('id', 'db_key')
|
||||||
ordering = ['db_player', 'db_typeclass_path', 'id']
|
ordering = ['db_player', 'db_typeclass_path', 'id']
|
||||||
|
|
@ -88,7 +78,6 @@ class ObjectDBAdmin(admin.ModelAdmin):
|
||||||
# )
|
# )
|
||||||
|
|
||||||
#deactivated temporarily, they cause empty objects to be created in admin
|
#deactivated temporarily, they cause empty objects to be created in admin
|
||||||
inlines = [TagInline]
|
|
||||||
|
|
||||||
# Custom modification to give two different forms wether adding or not.
|
# Custom modification to give two different forms wether adding or not.
|
||||||
add_form = ObjectCreateForm
|
add_form = ObjectCreateForm
|
||||||
|
|
@ -135,4 +124,3 @@ class ObjectDBAdmin(admin.ModelAdmin):
|
||||||
|
|
||||||
|
|
||||||
admin.site.register(ObjectDB, ObjectDBAdmin)
|
admin.site.register(ObjectDB, ObjectDBAdmin)
|
||||||
admin.site.register(Tag, TagAdmin)
|
|
||||||
|
|
|
||||||
|
|
@ -4,15 +4,12 @@
|
||||||
#
|
#
|
||||||
|
|
||||||
from django import forms
|
from django import forms
|
||||||
#from django.db import models
|
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.contrib import admin
|
from django.contrib import admin
|
||||||
from django.contrib.auth.admin import UserAdmin as BaseUserAdmin
|
from django.contrib.auth.admin import UserAdmin as BaseUserAdmin
|
||||||
#from django.contrib.admin import widgets
|
|
||||||
from django.contrib.auth.forms import UserChangeForm, UserCreationForm
|
from django.contrib.auth.forms import UserChangeForm, UserCreationForm
|
||||||
#from django.contrib.auth.models import User
|
|
||||||
from src.players.models import PlayerDB
|
from src.players.models import PlayerDB
|
||||||
#from src.typeclasses.models import Attribute
|
from src.typeclasses.admin import AttributeInline, TagInline
|
||||||
from src.utils import create
|
from src.utils import create
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -22,19 +19,25 @@ class PlayerDBChangeForm(UserChangeForm):
|
||||||
class Meta:
|
class Meta:
|
||||||
model = PlayerDB
|
model = PlayerDB
|
||||||
|
|
||||||
username = forms.RegexField(label="Username",
|
username = forms.RegexField(
|
||||||
max_length=30,
|
label="Username",
|
||||||
regex=r'^[\w. @+-]+$',
|
max_length=30,
|
||||||
widget=forms.TextInput(attrs={'size':'30'}),
|
regex=r'^[\w. @+-]+$',
|
||||||
error_messages = {'invalid': "This value may contain only letters, spaces, numbers and @/./+/-/_ characters."},
|
widget=forms.TextInput(
|
||||||
help_text = "30 characters or fewer. Letters, spaces, digits and @/./+/-/_ only.")
|
attrs={'size': '30'}),
|
||||||
|
error_messages={
|
||||||
|
'invalid': "This value may contain only letters, spaces, numbers "
|
||||||
|
"and @/./+/-/_ characters."},
|
||||||
|
help_text="30 characters or fewer. Letters, spaces, digits and "
|
||||||
|
"@/./+/-/_ only.")
|
||||||
|
|
||||||
def clean_username(self):
|
def clean_username(self):
|
||||||
username = self.cleaned_data['username']
|
username = self.cleaned_data['username']
|
||||||
if username.upper() == self.instance.username.upper():
|
if username.upper() == self.instance.username.upper():
|
||||||
return username
|
return username
|
||||||
elif PlayerDB.objects.filter(username__iexact=username):
|
elif PlayerDB.objects.filter(username__iexact=username):
|
||||||
raise forms.ValidationError('A player with that name already exists.')
|
raise forms.ValidationError('A player with that name '
|
||||||
|
'already exists.')
|
||||||
return self.cleaned_data['username']
|
return self.cleaned_data['username']
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -43,75 +46,90 @@ class PlayerDBCreationForm(UserCreationForm):
|
||||||
class Meta:
|
class Meta:
|
||||||
model = PlayerDB
|
model = PlayerDB
|
||||||
|
|
||||||
username = forms.RegexField(label="Username",
|
username = forms.RegexField(
|
||||||
max_length=30,
|
label="Username",
|
||||||
regex=r'^[\w. @+-]+$',
|
max_length=30,
|
||||||
widget=forms.TextInput(attrs={'size':'30'}),
|
regex=r'^[\w. @+-]+$',
|
||||||
error_messages = {'invalid': "This value may contain only letters, spaces, numbers and @/./+/-/_ characters."},
|
widget=forms.TextInput(
|
||||||
help_text = "30 characters or fewer. Letters, spaces, digits and @/./+/-/_ only.")
|
attrs={'size': '30'}),
|
||||||
|
error_messages={
|
||||||
|
'invalid': "This value may contain only letters, spaces, numbers "
|
||||||
|
"and @/./+/-/_ characters."},
|
||||||
|
help_text="30 characters or fewer. Letters, spaces, digits and "
|
||||||
|
"@/./+/-/_ only.")
|
||||||
|
|
||||||
def clean_username(self):
|
def clean_username(self):
|
||||||
username = self.cleaned_data['username']
|
username = self.cleaned_data['username']
|
||||||
if PlayerDB.objects.filter(username__iexact=username):
|
if PlayerDB.objects.filter(username__iexact=username):
|
||||||
raise forms.ValidationError('A player with that name already exists.')
|
raise forms.ValidationError('A player with that name already '
|
||||||
|
'exists.')
|
||||||
return username
|
return username
|
||||||
|
|
||||||
|
|
||||||
# # The Player editor
|
|
||||||
# class AttributeForm(forms.ModelForm):
|
|
||||||
# "Defines how to display the atttributes"
|
|
||||||
# class Meta:
|
|
||||||
# model = Attribute
|
|
||||||
# db_key = forms.CharField(label="Key",
|
|
||||||
# widget=forms.TextInput(attrs={'size':'15'}))
|
|
||||||
# db_value = forms.CharField(label="Value",
|
|
||||||
# widget=forms.Textarea(attrs={'rows':'2'}))
|
|
||||||
|
|
||||||
# class AttributeInline(admin.TabularInline):
|
|
||||||
# "Inline creation of player attributes"
|
|
||||||
# model = Attribute
|
|
||||||
# extra = 0
|
|
||||||
# form = AttributeForm
|
|
||||||
# fieldsets = (
|
|
||||||
# (None, {'fields' : (('db_key', 'db_value'))}),)
|
|
||||||
|
|
||||||
class PlayerForm(forms.ModelForm):
|
class PlayerForm(forms.ModelForm):
|
||||||
"Defines how to display Players"
|
"""
|
||||||
|
Defines how to display Players
|
||||||
|
"""
|
||||||
class Meta:
|
class Meta:
|
||||||
model = PlayerDB
|
model = PlayerDB
|
||||||
|
|
||||||
db_key = forms.RegexField(label="Username",
|
db_key = forms.RegexField(
|
||||||
initial="PlayerDummy",
|
label="Username",
|
||||||
max_length=30,
|
initial="PlayerDummy",
|
||||||
regex=r'^[\w. @+-]+$',
|
max_length=30,
|
||||||
required=False,
|
regex=r'^[\w. @+-]+$',
|
||||||
widget=forms.TextInput(attrs={'size':'30'}),
|
required=False,
|
||||||
error_messages = {'invalid': "This value may contain only letters, spaces, numbers and @/./+/-/_ characters."},
|
widget=forms.TextInput(attrs={'size': '30'}),
|
||||||
help_text = "This should be the same as the connected Player's key name. 30 characters or fewer. Letters, spaces, digits and @/./+/-/_ only.")
|
error_messages={
|
||||||
|
'invalid': "This value may contain only letters, spaces, numbers"
|
||||||
|
" and @/./+/-/_ characters."},
|
||||||
|
help_text="This should be the same as the connected Player's key "
|
||||||
|
"name. 30 characters or fewer. Letters, spaces, digits and "
|
||||||
|
"@/./+/-/_ only.")
|
||||||
|
|
||||||
db_typeclass_path = forms.CharField(label="Typeclass",
|
db_typeclass_path = forms.CharField(
|
||||||
initial=settings.BASE_PLAYER_TYPECLASS,
|
label="Typeclass",
|
||||||
widget=forms.TextInput(attrs={'size':'78'}),
|
initial=settings.BASE_PLAYER_TYPECLASS,
|
||||||
help_text="Required. Defines what 'type' of entity this is. This variable holds a Python path to a module with a valid Evennia Typeclass. Defaults to settings.BASE_PLAYER_TYPECLASS.")
|
widget=forms.TextInput(
|
||||||
#db_permissions = forms.CharField(label="Permissions",
|
attrs={'size': '78'}),
|
||||||
# initial=settings.PERMISSION_PLAYER_DEFAULT,
|
help_text="Required. Defines what 'type' of entity this is. This "
|
||||||
# required=False,
|
"variable holds a Python path to a module with a valid "
|
||||||
# widget=forms.TextInput(attrs={'size':'78'}),
|
"Evennia Typeclass. Defaults to "
|
||||||
# help_text="In-game permissions. A comma-separated list of text strings checked by certain locks. They are often used for hierarchies, such as letting a Player have permission 'Wizards', 'Builders' etc. A Player permission can be overloaded by the permissions of a controlled Character. Normal players use 'Players' by default.")
|
"settings.BASE_PLAYER_TYPECLASS.")
|
||||||
db_lock_storage = forms.CharField(label="Locks",
|
|
||||||
widget=forms.Textarea(attrs={'cols':'100', 'rows':'2'}),
|
db_permissions = forms.CharField(
|
||||||
required=False,
|
label="Permissions",
|
||||||
help_text="In-game lock definition string. If not given, defaults will be used. This string should be on the form <i>type:lockfunction(args);type2:lockfunction2(args);...")
|
initial=settings.PERMISSION_PLAYER_DEFAULT,
|
||||||
db_cmdset_storage = forms.CharField(label="cmdset",
|
required=False,
|
||||||
initial=settings.CMDSET_PLAYER,
|
widget=forms.TextInput(
|
||||||
widget=forms.TextInput(attrs={'size':'78'}),
|
attrs={'size': '78'}),
|
||||||
required=False,
|
help_text="In-game permissions. A comma-separated list of text "
|
||||||
help_text="python path to player cmdset class (set in settings.CMDSET_PLAYER by default)")
|
"strings checked by certain locks. They are often used for "
|
||||||
|
"hierarchies, such as letting a Player have permission "
|
||||||
|
"'Wizards', 'Builders' etc. A Player permission can be "
|
||||||
|
"overloaded by the permissions of a controlled Character. "
|
||||||
|
"Normal players use 'Players' by default.")
|
||||||
|
|
||||||
|
db_lock_storage = forms.CharField(
|
||||||
|
label="Locks",
|
||||||
|
widget=forms.Textarea(attrs={'cols': '100', 'rows': '2'}),
|
||||||
|
required=False,
|
||||||
|
help_text="In-game lock definition string. If not given, defaults "
|
||||||
|
"will be used. This string should be on the form "
|
||||||
|
"<i>type:lockfunction(args);type2:lockfunction2(args);...")
|
||||||
|
db_cmdset_storage = forms.CharField(
|
||||||
|
label="cmdset",
|
||||||
|
initial=settings.CMDSET_PLAYER,
|
||||||
|
widget=forms.TextInput(attrs={'size': '78'}),
|
||||||
|
required=False,
|
||||||
|
help_text="python path to player cmdset class (set in "
|
||||||
|
"settings.CMDSET_PLAYER by default)")
|
||||||
|
|
||||||
|
|
||||||
class PlayerInline(admin.StackedInline):
|
class PlayerInline(admin.StackedInline):
|
||||||
"Inline creation of Player"
|
"""
|
||||||
|
Inline creation of Player
|
||||||
|
"""
|
||||||
model = PlayerDB
|
model = PlayerDB
|
||||||
template = "admin/players/stacked.html"
|
template = "admin/players/stacked.html"
|
||||||
form = PlayerForm
|
form = PlayerForm
|
||||||
|
|
@ -119,51 +137,80 @@ class PlayerInline(admin.StackedInline):
|
||||||
("In-game Permissions and Locks",
|
("In-game Permissions and Locks",
|
||||||
{'fields': ('db_lock_storage',),
|
{'fields': ('db_lock_storage',),
|
||||||
#{'fields': ('db_permissions', 'db_lock_storage'),
|
#{'fields': ('db_permissions', 'db_lock_storage'),
|
||||||
'description':"<i>These are permissions/locks for in-game use. They are unrelated to website access rights.</i>"}),
|
'description': "<i>These are permissions/locks for in-game use. "
|
||||||
|
"They are unrelated to website access rights.</i>"}),
|
||||||
("In-game Player data",
|
("In-game Player data",
|
||||||
{'fields':('db_typeclass_path', 'db_cmdset_storage'),
|
{'fields': ('db_typeclass_path', 'db_cmdset_storage'),
|
||||||
'description':"<i>These fields define in-game-specific properties for the Player object in-game.</i>"}),
|
'description': "<i>These fields define in-game-specific properties "
|
||||||
)
|
"for the Player object in-game.</i>"}))
|
||||||
|
|
||||||
extra = 1
|
extra = 1
|
||||||
max_num = 1
|
max_num = 1
|
||||||
|
|
||||||
|
|
||||||
|
class PlayerTagInline(TagInline):
|
||||||
|
model = PlayerDB.db_tags.through
|
||||||
|
|
||||||
|
|
||||||
|
class PlayerAttributeInline(AttributeInline):
|
||||||
|
model = PlayerDB.db_attributes.through
|
||||||
|
|
||||||
|
|
||||||
class PlayerDBAdmin(BaseUserAdmin):
|
class PlayerDBAdmin(BaseUserAdmin):
|
||||||
"This is the main creation screen for Users/players"
|
"""
|
||||||
|
This is the main creation screen for Users/players
|
||||||
|
"""
|
||||||
|
|
||||||
list_display = ('username', 'email', 'is_staff', 'is_superuser')
|
list_display = ('username', 'email', 'is_staff', 'is_superuser')
|
||||||
form = PlayerDBChangeForm
|
form = PlayerDBChangeForm
|
||||||
add_form = PlayerDBCreationForm
|
add_form = PlayerDBCreationForm
|
||||||
|
inlines = [PlayerTagInline, PlayerAttributeInline]
|
||||||
fieldsets = (
|
fieldsets = (
|
||||||
(None, {'fields': ('username', 'password', 'email')}),
|
(None, {'fields': ('username', 'password', 'email')}),
|
||||||
('Website profile', {'fields': ('first_name', 'last_name'),
|
('Website profile', {
|
||||||
'description': "<i>These are not used in the default system.</i>"}),
|
'fields': ('first_name', 'last_name'),
|
||||||
('Website dates', {'fields': ('last_login', 'date_joined'),
|
'description': "<i>These are not used "
|
||||||
'description': '<i>Relevant only to the website.</i>'}),
|
"in the default system.</i>"}),
|
||||||
('Website Permissions', {'fields': ('is_active', 'is_staff', 'is_superuser',
|
('Website dates', {
|
||||||
'user_permissions', 'groups'),
|
'fields': ('last_login', 'date_joined'),
|
||||||
'description': "<i>These are permissions/permission groups for accessing the admin site. They are unrelated to in-game access rights.</i>"}),
|
'description': '<i>Relevant only to the website.</i>'}),
|
||||||
('Game Options', {'fields': ('db_typeclass_path', 'db_cmdset_storage', 'db_lock_storage'),
|
('Website Permissions', {
|
||||||
'description': '<i>These are attributes that are more relevant to gameplay.</i>'}))
|
'fields': ('is_active', 'is_staff', 'is_superuser',
|
||||||
#('Game Options', {'fields': ('db_typeclass_path', 'db_cmdset_storage', 'db_permissions', 'db_lock_storage'),
|
'user_permissions', 'groups'),
|
||||||
# 'description': '<i>These are attributes that are more relevant to gameplay.</i>'}))
|
'description': "<i>These are permissions/permission groups for "
|
||||||
|
"accessing the admin site. They are unrelated to "
|
||||||
|
"in-game access rights.</i>"}),
|
||||||
|
('Game Options', {
|
||||||
|
'fields': ('db_typeclass_path', 'db_cmdset_storage',
|
||||||
|
'db_lock_storage'),
|
||||||
|
'description': '<i>These are attributes that are more relevant '
|
||||||
|
'to gameplay.</i>'}))
|
||||||
|
# ('Game Options', {'fields': (
|
||||||
|
# 'db_typeclass_path', 'db_cmdset_storage',
|
||||||
|
# 'db_permissions', 'db_lock_storage'),
|
||||||
|
# 'description': '<i>These are attributes that are '
|
||||||
|
# 'more relevant to gameplay.</i>'}))
|
||||||
|
|
||||||
add_fieldsets = (
|
add_fieldsets = (
|
||||||
(None,
|
(None,
|
||||||
{'fields': ('username', 'password1', 'password2', 'email'),
|
{'fields': ('username', 'password1', 'password2', 'email'),
|
||||||
'description':"<i>These account details are shared by the admin system and the game.</i>"},),)
|
'description': "<i>These account details are shared by the admin "
|
||||||
|
"system and the game.</i>"},),)
|
||||||
|
|
||||||
# TODO! Remove User reference!
|
# TODO! Remove User reference!
|
||||||
def save_formset(self, request, form, formset, change):
|
def save_formset(self, request, form, formset, change):
|
||||||
"Run all hooks on the player object"
|
"""
|
||||||
|
Run all hooks on the player object
|
||||||
|
"""
|
||||||
super(PlayerDBAdmin, self).save_formset(request, form, formset, change)
|
super(PlayerDBAdmin, self).save_formset(request, form, formset, change)
|
||||||
userobj = form.instance
|
userobj = form.instance
|
||||||
userobj.name = userobj.username
|
userobj.name = userobj.username
|
||||||
if not change:
|
if not change:
|
||||||
#uname, passwd, email = str(request.POST.get(u"username")), \
|
# uname, passwd, email = str(request.POST.get(u"username")), \
|
||||||
# str(request.POST.get(u"password1")), str(request.POST.get(u"email"))
|
# str(request.POST.get(u"password1")), \
|
||||||
typeclass = str(request.POST.get(u"playerdb_set-0-db_typeclass_path"))
|
# str(request.POST.get(u"email"))
|
||||||
|
typeclass = str(request.POST.get(
|
||||||
|
u"playerdb_set-0-db_typeclass_path"))
|
||||||
create.create_player("", "", "",
|
create.create_player("", "", "",
|
||||||
user=userobj,
|
user=userobj,
|
||||||
typeclass=typeclass,
|
typeclass=typeclass,
|
||||||
|
|
|
||||||
|
|
@ -2,16 +2,18 @@
|
||||||
# This sets up how models are displayed
|
# This sets up how models are displayed
|
||||||
# in the web admin interface.
|
# in the web admin interface.
|
||||||
#
|
#
|
||||||
|
from src.typeclasses.admin import AttributeInline, TagInline
|
||||||
|
|
||||||
from src.typeclasses.models import Attribute
|
|
||||||
from src.scripts.models import ScriptDB
|
from src.scripts.models import ScriptDB
|
||||||
from django.contrib import admin
|
from django.contrib import admin
|
||||||
|
|
||||||
|
|
||||||
class AttributeInline(admin.TabularInline):
|
class ScriptTagInline(TagInline):
|
||||||
model = Attribute
|
model = ScriptDB.db_tags.through
|
||||||
fields = ('db_key', 'db_value')
|
|
||||||
max_num = 1
|
|
||||||
|
class ScriptAttributeInline(AttributeInline):
|
||||||
|
model = ScriptDB.db_attributes.through
|
||||||
|
|
||||||
|
|
||||||
class ScriptDBAdmin(admin.ModelAdmin):
|
class ScriptDBAdmin(admin.ModelAdmin):
|
||||||
|
|
@ -32,7 +34,7 @@ class ScriptDBAdmin(admin.ModelAdmin):
|
||||||
'db_repeats', 'db_start_delay', 'db_persistent',
|
'db_repeats', 'db_start_delay', 'db_persistent',
|
||||||
'db_obj')}),
|
'db_obj')}),
|
||||||
)
|
)
|
||||||
#inlines = [AttributeInline]
|
inlines = [ScriptTagInline, ScriptAttributeInline]
|
||||||
|
|
||||||
|
|
||||||
admin.site.register(ScriptDB, ScriptDBAdmin)
|
admin.site.register(ScriptDB, ScriptDBAdmin)
|
||||||
|
|
|
||||||
64
src/typeclasses/admin.py
Normal file
64
src/typeclasses/admin.py
Normal file
|
|
@ -0,0 +1,64 @@
|
||||||
|
from django.contrib import admin
|
||||||
|
from django.contrib.admin import ModelAdmin
|
||||||
|
from django.core.urlresolvers import reverse
|
||||||
|
from django.forms import Textarea
|
||||||
|
from src.typeclasses.models import Attribute, Tag
|
||||||
|
|
||||||
|
|
||||||
|
class PickledWidget(Textarea):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class TagAdmin(admin.ModelAdmin):
|
||||||
|
fields = ('db_key', 'db_category', 'db_data')
|
||||||
|
|
||||||
|
|
||||||
|
class TagInline(admin.TabularInline):
|
||||||
|
# Set this to the through model of your desired M2M when subclassing.
|
||||||
|
model = None
|
||||||
|
raw_id_fields = ('tag',)
|
||||||
|
extra = 0
|
||||||
|
|
||||||
|
|
||||||
|
class AttributeInline(admin.TabularInline):
|
||||||
|
"""
|
||||||
|
Inline creation of player attributes
|
||||||
|
"""
|
||||||
|
# Set this to the through model of your desired M2M when subclassing.
|
||||||
|
model = None
|
||||||
|
extra = 3
|
||||||
|
#form = AttributeForm
|
||||||
|
fields = ('attribute', 'key', 'value', 'strvalue')
|
||||||
|
raw_id_fields = ('attribute',)
|
||||||
|
readonly_fields = ('key', 'value', 'strvalue')
|
||||||
|
|
||||||
|
def key(self, instance):
|
||||||
|
if not instance.id:
|
||||||
|
return "Not yet set or saved."
|
||||||
|
return '<strong><a href="%s">%s</a></strong>' % (
|
||||||
|
reverse("admin:typeclasses_attribute_change",
|
||||||
|
args=[instance.attribute.id]),
|
||||||
|
instance.attribute.db_key)
|
||||||
|
|
||||||
|
key.allow_tags = True
|
||||||
|
|
||||||
|
def value(self, instance):
|
||||||
|
if not instance.id:
|
||||||
|
return "Not yet set or saved."
|
||||||
|
return instance.attribute.db_value
|
||||||
|
|
||||||
|
def strvalue(self, instance):
|
||||||
|
if not instance.id:
|
||||||
|
return "Not yet set or saved."
|
||||||
|
return instance.attribute.db_strvalue
|
||||||
|
|
||||||
|
|
||||||
|
class AttributeAdmin(ModelAdmin):
|
||||||
|
"""
|
||||||
|
Defines how to display the attributes
|
||||||
|
"""
|
||||||
|
search_fields = ('db_key', 'db_strvalue', 'db_value')
|
||||||
|
list_display = ('db_key', 'db_strvalue', 'db_value')
|
||||||
|
|
||||||
|
admin.site.register(Attribute, AttributeAdmin)
|
||||||
|
admin.site.register(Tag, TagAdmin)
|
||||||
|
|
@ -28,15 +28,21 @@ Pickle field implementation for Django.
|
||||||
Modified for Evennia by Griatch.
|
Modified for Evennia by Griatch.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
from ast import literal_eval
|
||||||
|
|
||||||
from copy import deepcopy
|
from copy import deepcopy
|
||||||
from base64 import b64encode, b64decode
|
from base64 import b64encode, b64decode
|
||||||
from zlib import compress, decompress
|
from zlib import compress, decompress
|
||||||
#import six # this is actually a pypy component, not in default syslib
|
#import six # this is actually a pypy component, not in default syslib
|
||||||
import django
|
import django
|
||||||
|
from django.core.exceptions import ValidationError
|
||||||
from django.db import models
|
from django.db import models
|
||||||
|
|
||||||
# django 1.5 introduces force_text instead of force_unicode
|
# django 1.5 introduces force_text instead of force_unicode
|
||||||
|
from django.forms import CharField, Textarea
|
||||||
|
from django.forms.util import flatatt
|
||||||
|
from django.utils.html import format_html
|
||||||
|
|
||||||
try:
|
try:
|
||||||
from django.utils.encoding import force_text
|
from django.utils.encoding import force_text
|
||||||
except ImportError:
|
except ImportError:
|
||||||
|
|
@ -120,6 +126,45 @@ def _get_subfield_superclass():
|
||||||
#return six.with_metaclass(models.SubfieldBase, models.Field)
|
#return six.with_metaclass(models.SubfieldBase, models.Field)
|
||||||
|
|
||||||
|
|
||||||
|
class PickledWidget(Textarea):
|
||||||
|
def render(self, name, value, attrs=None):
|
||||||
|
value = repr(value)
|
||||||
|
try:
|
||||||
|
literal_eval(value)
|
||||||
|
except ValueError:
|
||||||
|
return value
|
||||||
|
|
||||||
|
final_attrs = self.build_attrs(attrs, name=name)
|
||||||
|
return format_html('<textarea{0}>\r\n{1}</textarea>',
|
||||||
|
flatatt(final_attrs),
|
||||||
|
force_text(value))
|
||||||
|
|
||||||
|
|
||||||
|
class PickledFormField(CharField):
|
||||||
|
widget = PickledWidget
|
||||||
|
default_error_messages = dict(CharField.default_error_messages)
|
||||||
|
default_error_messages['invalid'] = (
|
||||||
|
"This is not a Python Literal. You can store things like strings, "
|
||||||
|
"integers, or floats, but you must do it by typing them as you would "
|
||||||
|
"type them in the Python Interpreter. For instance, strings must be "
|
||||||
|
"surrounded by quote marks. We have converted it to a string for your "
|
||||||
|
"convenience. If it is acceptable, please hit save again.")
|
||||||
|
|
||||||
|
def __init__(self, *args, **kwargs):
|
||||||
|
# This needs to fall through to literal_eval.
|
||||||
|
kwargs['required'] = False
|
||||||
|
super(PickledFormField, self).__init__(*args, **kwargs)
|
||||||
|
|
||||||
|
def clean(self, value):
|
||||||
|
if value == '':
|
||||||
|
# Field was left blank. Make this None.
|
||||||
|
value = 'None'
|
||||||
|
try:
|
||||||
|
return literal_eval(value)
|
||||||
|
except ValueError:
|
||||||
|
raise ValidationError(self.error_messages['invalid'])
|
||||||
|
|
||||||
|
|
||||||
class PickledObjectField(_get_subfield_superclass()):
|
class PickledObjectField(_get_subfield_superclass()):
|
||||||
"""
|
"""
|
||||||
A field that will accept *any* python object and store it in the
|
A field that will accept *any* python object and store it in the
|
||||||
|
|
@ -135,7 +180,6 @@ class PickledObjectField(_get_subfield_superclass()):
|
||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, *args, **kwargs):
|
||||||
self.compress = kwargs.pop('compress', False)
|
self.compress = kwargs.pop('compress', False)
|
||||||
self.protocol = kwargs.pop('protocol', DEFAULT_PROTOCOL)
|
self.protocol = kwargs.pop('protocol', DEFAULT_PROTOCOL)
|
||||||
kwargs.setdefault('editable', False)
|
|
||||||
super(PickledObjectField, self).__init__(*args, **kwargs)
|
super(PickledObjectField, self).__init__(*args, **kwargs)
|
||||||
|
|
||||||
def get_default(self):
|
def get_default(self):
|
||||||
|
|
@ -180,6 +224,9 @@ class PickledObjectField(_get_subfield_superclass()):
|
||||||
return value._obj
|
return value._obj
|
||||||
return value
|
return value
|
||||||
|
|
||||||
|
def formfield(self, **kwargs):
|
||||||
|
return PickledFormField(**kwargs)
|
||||||
|
|
||||||
def pre_save(self, model_instance, add):
|
def pre_save(self, model_instance, add):
|
||||||
value = super(PickledObjectField, self).pre_save(model_instance, add)
|
value = super(PickledObjectField, self).pre_save(model_instance, add)
|
||||||
return wrap_conflictual_object(value)
|
return wrap_conflictual_object(value)
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue