mirror of
https://github.com/kennethreitz/photos.kennethreitz.org.git
synced 2026-06-17 21:31:00 +00:00
e295037c4e
- City model with continent/country/name, auto-created from GPS coords - Offline reverse geocoding via reverse_geocoder (no API limits) - geocode management command to backfill existing images - Cities page grouped by continent > country with image counts - City detail page with shuffled infinite scroll - Cities link in nav Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
79 lines
2.4 KiB
Python
79 lines
2.4 KiB
Python
from django.contrib import admin
|
|
from django.contrib.auth.admin import UserAdmin as BaseUserAdmin
|
|
|
|
from core.models import Camera, City, ExifData, Image, Lens, SiteConfig, Tag, User
|
|
|
|
|
|
@admin.register(SiteConfig)
|
|
class SiteConfigAdmin(admin.ModelAdmin):
|
|
list_display = ['site_title', 'tagline']
|
|
fieldsets = [
|
|
("Site", {'fields': ('site_title', 'tagline', 'analytics_code')}),
|
|
("AI", {'fields': ('openai_api_key', 'ai_prompt')}),
|
|
]
|
|
|
|
def has_add_permission(self, request):
|
|
return not SiteConfig.objects.exists()
|
|
|
|
def has_delete_permission(self, request, obj=None):
|
|
return False
|
|
|
|
|
|
@admin.register(City)
|
|
class CityAdmin(admin.ModelAdmin):
|
|
list_display = ['name', 'country', 'continent']
|
|
list_filter = ['continent', 'country']
|
|
search_fields = ['name', 'country']
|
|
|
|
|
|
@admin.register(Tag)
|
|
class TagAdmin(admin.ModelAdmin):
|
|
list_display = ['name', 'slug']
|
|
search_fields = ['name']
|
|
prepopulated_fields = {'slug': ('name',)}
|
|
|
|
|
|
@admin.register(User)
|
|
class UserAdmin(BaseUserAdmin):
|
|
list_display = ['username', 'email', 'date_joined', 'is_staff']
|
|
fieldsets = BaseUserAdmin.fieldsets + (
|
|
("Profile", {'fields': ('bio', 'avatar', 'website')}),
|
|
)
|
|
|
|
|
|
@admin.register(Camera)
|
|
class CameraAdmin(admin.ModelAdmin):
|
|
list_display = ['display_name', 'manufacturer', 'model', 'slug']
|
|
list_filter = ['manufacturer']
|
|
search_fields = ['manufacturer', 'model', 'display_name']
|
|
prepopulated_fields = {'slug': ('manufacturer', 'model')}
|
|
|
|
|
|
@admin.register(Lens)
|
|
class LensAdmin(admin.ModelAdmin):
|
|
list_display = ['display_name', 'manufacturer', 'model', 'max_aperture', 'slug']
|
|
list_filter = ['manufacturer']
|
|
search_fields = ['manufacturer', 'model', 'display_name']
|
|
prepopulated_fields = {'slug': ('manufacturer', 'model')}
|
|
|
|
|
|
class ExifDataInline(admin.StackedInline):
|
|
model = ExifData
|
|
extra = 0
|
|
readonly_fields = ['raw_data']
|
|
|
|
|
|
@admin.register(Image)
|
|
class ImageAdmin(admin.ModelAdmin):
|
|
list_display = ['title', 'user', 'visibility', 'is_processing', 'upload_date']
|
|
list_filter = ['visibility', 'is_processing']
|
|
search_fields = ['title', 'description', 'user__username']
|
|
inlines = [ExifDataInline]
|
|
|
|
|
|
@admin.register(ExifData)
|
|
class ExifDataAdmin(admin.ModelAdmin):
|
|
list_display = ['image', 'camera', 'lens', 'focal_length', 'aperture', 'iso', 'date_taken']
|
|
list_filter = ['camera', 'lens']
|
|
search_fields = ['image__title', 'camera__display_name', 'lens__display_name']
|