Upgrade to Pro — share decks privately, control downloads, hide ads and more …

날로 먹는 Django Admin 활용

Avatar for Kay Cha Kay Cha
November 05, 2017

날로 먹는 Django Admin 활용

DjangoGirls Seoul 2017 11월 세미나에서 발표한 문서입니다.

Avatar for Kay Cha

Kay Cha

November 05, 2017
Tweet

More Decks by Kay Cha

Other Decks in Programming

Transcript

  1. ߊ಴੗ࣗѐ • 차경묵 (한날) • 프리랜서 개발자 • 날로 먹는

    Django 웹 프로그래밍 (2008) • 날로 먹는 Django 웹 프레임워크 (2014) • http://blog.hannal.com
  2. ProfileNPEFM class Profile(models.Model): registration_routes = ( ('direct', _('૒੽ ߑޙ оੑ'),

    ), ('guestbook', _('ѱझ౟࠘'), ), ('cocoa', _('௏௏ইస'), ), ('goggle', _('ҊӖ'), ), ('navar', _('ա߄'), ), ) user = models.OneToOneField(settings.AUTH_USER_MODEL) registration_route = models.CharField(_('оੑ ҃۽'), max_length=40, choices=registration_routes, default='direct')
  3. ProductNPEFM class Product(models.Model): statuses = ( ('active', _('੿࢚'), ), ('sold_out',

    _('ಿ੺'), ), ('obsolete', _('ױઙ'), ), ('deactive', _('࠺ഝࢿച'), ), ) categories = ( ('decoration', _('੢ध'), ), ('pan', _('ಃ'), ), ('roll', _('܀'), ), ) category = models.CharField(_('࢚ಿ тې'), max_length=20, choices=categories) name = models.CharField(_('࢚ಿݺ'), max_length=100) content = models.TextField(_('ࢸݺ')) regular_price = models.PositiveIntegerField(_('੿о')) selling_price = models.PositiveIntegerField(_('౸ݒо')) status = models.CharField(_('࢚క'), max_length=20, choices=statuses) created_at = models.DateTimeField(auto_now_add=True) updated_at = models.DateTimeField(auto_now=True)
  4. ProductImageNPEFM class ProductImage(models.Model): product = models.ForeignKey(Product) content = models.ImageField() created_at

    = models.DateTimeField(auto_now_add=True) updated_at = models.DateTimeField(auto_now=True)
  5. OrderNPEFM from uuid import uuid4 class Order(models.Model): progresses = (

    ('requested', _('઱ޙ ਃ୒'), ), ('checkout_payment', _('Ѿઁ ഛੋ ઺'), ), ('paid', _('Ѿઁ ৮ܐ'), ), ('failed_payment', _('Ѿઁ पಁ'), ), ('prepared_product', _('࢚ಿ ળ࠺'), ), ('prepared_delivery', _('୹Ҋ ળ࠺'), ), ('ongoing_delivery', _('ߓ࣠ ઺'), ), ('done', _('Ѣې ৮ܐ'), ), ) sn = models.UUIDField(_('ੌ۲ߣഐ'), unique=True, editable=False, default=uuid4) user = models.ForeignKey(settings.AUTH_USER_MODEL, null=True, blank=True) items = models.ManyToManyField(Product) product_cost = models.IntegerField(_('઱ޙ ୨ঘ')) progress = models.CharField(_('૓೯࢚క'), max_length=20, choices=progresses, default='requested') comment = models.TextField(_('ӝఋ ਃ୒ࢎ೦'), null=True, blank=True) created_at = models.DateTimeField(auto_now_add=True) updated_at = models.DateTimeField(auto_now=True)
  6. ݾ۾ചݶী୹۱ղਊ૑੿ ↟ݽ؛߹"ENJOੋఠಕ੉झٜܳ݅"ENJO௿ېझٜܳ݅Ҋ%KBOHP"ENJOী١ ۾ ↟list_displayݯߡ߸ࣻݾ۾ചݶী಴दೡݽ؛੉աݽ؛੄"ENJOࣘࢿ BUUSJCVUFT  @admin.register(models.Product) class ProductAdmin(admin.ModelAdmin): list_display

    = ( 'pk', 'name', 'category', 'regular_price', 'selling_price', 'status', 'created_at', 'updated_at', ) ژח admin.site.register(models.Product, ProductAdmin) ੢ध੗ܳॳחߑߨҗ૒੽ ݽ؛җ"ENJO௿ېझܳ૟ ૑য١۾ೞחߑߨ਷زੌೠ ز੘ੑפ׮
  7. ݽ؛೙٘ীহחղਊਸݾ۾ী಴दೞӝ ↟"ENJO੄ࣘࢿ ઱۽ݫࢲ٘ ૑੿ ↟೧׼ݫࢲ٘ীAshort_descriptionAחৌ੉ܴਵ۽ࢎਊؽ from django.utils.translation import ugettext as

    _ from django.utils.safestring import mark_safe @admin.register(models.Product) class ProductAdmin(admin.ModelAdmin): list_display = ( 'get_title_image', 'pk', 'name', 'category', 'regular_price', 'selling_price', 'status', 'created_at', 'updated_at', ) list_display_links = ( 'get_title_image', 'pk', 'name', 'category', 'regular_price', 'selling_price', 'status', 'created_at', 'updated_at', ) # ࢤۚ def get_title_image(self, obj): image = obj.productimage_set.order_by('pk').first() if not image: return '' return mark_safe(f'<img src="{image.content.url}" style="width: 50px;">') get_title_image.short_description = _('ઁಿ ੉޷૑')
  8. %KBOHP6TFS"ENJOࣻ੿ ↟%KBOHPղ੢6TFSݽ؛ਸࢎਊೞח҃਋ %KBOHP"ENJOী١۾ػUser ݽ؛ਸ١۾೧ઁ೧ঠೣ ↟Userݽ؛ী؀ೠ"ENJOਸ١۾೧ઁೞחѱইפۄݽ؛ਸ೧ઁೞחѪী ઱੄ from django.contrib.auth.models import User

    admin.site.unregister(User) ژח from django.contrib.auth import get_user_model user_model = get_user_model() admin.site.unregister(user_model) ੉҃਋ח%KBOHPীࢲઁҕೞח Userݽ؛ਸ١۾೧ઁೞחѪ੉ ޲۽ݺഛೞѱ؀࢚ݽ؛ੋUser ܳ߄۽JNQPSUೞחѱա਺
  9. %KBOHP6TFS"ENJOࣻ੿ ↟Userݽ؛ী؀ೠ"ENJO௿ېझܳ࢜۽ٜ݅যبغҊ  ↟%KBOHPীղ੢ػUserAdmin௿ېझ࢚ܳࣘ߉ইࣻ੿೧بغҊ from django.contrib.auth.admin import UserAdmin @admin.register(user_model) class

    CustomUserAdmin(UserAdmin): list_display = UserAdmin.list_display + ('get_registration_route', ) def get_registration_route(self, obj): try: return obj.profile.get_registration_route_display() except models.Profile.DoesNotExist: return '?' get_registration_route.short_description = _('оੑ҃۽')
  10. оੑ҃۽۽୶۰ղӝ ↟.PEFMNBOBHFS۽ؘ੉ఠఐ࢝दࢎਊೞחݽ؛ҙ҅ఐ࢝ޙߨࢎਊ оמ • User.objects.filter(profile__registration_route='direct') @admin.register(user_model) class CustomUserAdmin(UserAdmin): list_display =

    UserAdmin.list_display + ('get_registration_route', ) list_filter = UserAdmin.list_filter + ('profile__registration_route', ) def get_registration_route(self, obj): try: return obj.profile.get_registration_route_display() except models.Profile.DoesNotExist: return '?' get_registration_route.short_description = _('оੑ҃۽')
  11. ઱ޙപࣻ೙ఠ ↟admin.SimpleListFilter௿ېझ࢚ܳࣘ߉ই૒੽-JTUGJMUFSܳ੘ࢿ೧ঠೞח࢚ട ↟lookups()೙ఠ6*ী಴दೡఐ࢝чҗఐ࢝಴दݺਸtuple۽ޘযࢲ߈ജ ↟queryset()೙ఠী؀೧ࢤࢿೡQuerySetё୓ܳ߈ജ೙ఠחࢲ۽׮ܲ೙ఠ৬઺୏غয૕ ੄૘೤ਸٜ݅ࣻ੓ਵ޲۽߈٘दQuerySetё୓ܳ߈ജ೧ঠೣ from django.db.models import Count, Case,

    When, IntegerField class UserOrderCountFilter(admin.SimpleListFilter): title = _('ҳݒപࣻ') parameter_name = 'order_count' def lookups(self, request, model_admin): return ( ('exact-0', _('হ਺'), ), ('exact-1', _('1ഥ'), ), ('exact-2', _('2ഥ'), ), ('exact-3', _('3ഥ'), ), ('gt-3', _('3ഥ ୡҗ'), ), ) # ׮਺ ੢ীࢲ ҅ࣘ
  12. ઱ޙപࣻ೙ఠ # ੉যࢲ def queryset(self, request, queryset): value = self.value()

    if not value: return queryset try: lookup_keyword, count = value.split('-') count = int(count) if count == 0: users = models.Order.objects \ .filter(progress='done') \ .values_list('user__id') return queryset.exclude(pk__in=users) else: return queryset \ .annotate(cnt=Count(Case( When(order__progress='done', then=0), output_field=IntegerField() ))).filter(** {f'cnt__{lookup_keyword}': count}) except Exception: return queryset.none()
  13. ־੸઱ޙ୨ঘ೙ఠ ↟઱ޙപࣻ೙ఠ৬Ѣ੄زੌ from django.db.models import Sum class SumOrderCostFilter(admin.SimpleListFilter): title =

    _('־੸ ҳݒ୨ঘ') parameter_name = 'order_cost' def lookups(self, request, model_admin): return ( ('lt-50000', _('5݅ਗ ޷݅'), ), ('gte-50000--lt-100000', _('5݅ਗ ੉࢚ 10݅ਗ ޷݅'), ), ('gte-100000--lt-200000', _('10݅ਗ ੉࢚ 20݅ਗ ޷݅'), ), ('gte-200000--lt-500000', _('20݅ਗ ੉࢚ 50݅ਗ ޷݅'), ), ('gte-500000', _('50݅ਗ ੉࢚'), ), )
  14. ־੸઱ޙ୨ঘ೙ఠ # ੉যࢲ def queryset(self, request, queryset): value = self.value()

    if not value: return queryset try: l1, l2 = value.split('--') except ValueError: l1, l2 = value, None lookups = {} for l in (l1, l2): if not l: continue try: lookup_keyword, amount = l.split('-') lookups[f'cost__{lookup_keyword}'] = int(amount) except ValueError: continue # ׮਺ ੢ী ҅ࣘ
  15. ־੸઱ޙ୨ঘ೙ఠ def queryset(self, request, queryset): # ࢤۚ # ੉যࢲ if

    not lookups: return queryset.none() try: return queryset.filter(order__progress='done') \ .annotate(cost=Sum('order__product_cost')) \ .filter(**lookups) except Exception: return queryset.none()
  16. $VTUPN"ENJO"DUJPO ↟"ENJO௿ېझ੄actionsࣘࢿীഐ୹оמೠё୓ܳ١۾ ↟ݾ۾ചݶীࢎਊ੗о୶оೠ"DUJPO੉"DUJPO%SPQEPXO6*ী୶оؽ ↟ੋ੗۽ֈযয়חquerysetё୓ূ੉ਊ੗оࢶఖೠ೦ݾ੉׸ѹ੓਺ from django.contrib import messages def change_progress_to_ongoing_delivery(modeladmin,

    request, queryset): queryset.update(progress='ongoing_delivery') messages.success(request, _('ߓ࣠ ࢚క۽ ߸҃೮णפ׮.')) change_progress_to_ongoing_delivery.short_description = _('ߓ࣠ ࢚క۽ ߸҃') @admin.register(models.Order) class OrderAdmin(admin.ModelAdmin): # ࢤۚ actions = (change_progress_to_ongoing_delivery, )
  17. ࢚ࣁࠁӝಕ੉૑ীࢲౠ੿੗ܐী݅ز੘ೞח"DUJPO୶оߑߨ from django_object_actions import DjangoObjectActions @admin.register(user_model) class CustomUserAdmin(DjangoObjectActions, UserAdmin): #

    ࢤۚ change_actions = ('make_user_happy', ) def make_user_happy(self, request, obj): messages.info(request, f'{obj}שਸ ೯ࠂೞѱ ೮णפ׮.') # do something make_user_happy.label = _('੉ਊ੗ ೯ࠂೞѱ ೞӝ') make_user_happy.short_description = _('੉ਊ੗ ೯ࠂೞѱ ೞӝ')