본문으로 바로가기

Admin panel Customizing (further)

category Django, Flask/🔫 Django 2020. 5. 12. 09:44

전에 User app에서 사용할 어드민 패널을 기본 패널을 확장하는 방식으로 만들어보았는데, 이번에는 User가 아닌 일반적인 앱에서 어드민 패널을 구성하는 방식을 정리해보았습니다. 딱히 다르지는 않지만 값으로 줄 수 있는 속성을 더 많이 알아보려고 합니다.

 

admin.py에서 볼 수 있는 옵션들은 다음에서 찾아볼 수 있습니다.

 

The Django admin site | Django documentation | Django

Django The web framework for perfectionists with deadlines. Overview Download Documentation News Community Code Issues About ♥ Donate

docs.djangoproject.com

 

from django.contrib import admin
from . import models

@admin.register(models.Room)
class RoomAdmin(admin.ModelAdmin):

    """ Room Admin Definition """

    list_display = (
        "name",
        "country",
        "city",
        "price",
        "address",
    )

    list_filter = (
        "instant_book", "city", "country", "host__superhost",
    )

    search_fields = ["=city", "^host__username"]

 

 

search_fields

 

list_display나 list_filter는 앞 서 다룬 바가 있습니다. 여기서 처음 보는 건 search_fields입니다. 검색 창을 띄워줍니다.

 

각 검색어는 앞에 prefix를 붙임으로써 옵션을 줄 수 있습니다. 예를 들어 =를 붙이면 정확히 일치하는(대소문자 구별은 안 합니다) 것만 찾습니다.

 

Some (older) shortcuts for specifying a field lookup are also available. You can prefix a field in search_fields with the following characters and it’s equivalent to adding __<lookup> to the field:

^ startswith
= iexact
@ search
None (default) icontains

 

또, 모델 간의 연관관계를 타고 검색할 것을 지정할 수 도 있습니다.

host__username은, Room 모델에 있는(현재 코드가 작성된 경로가 rooms/admin.py이며 해당 admin에 연결된 model이 Room 모델임) host에 연결된 모델 내의 username을 의미합니다. 언더바 2개 인 것을 주의합시다. 이러한 방식은 serach 뿐만 아니라 모든 속성에서 사용할 수 있는 보편적인 것입니다.

 

예를 들어 list_filter에 "host__superhost" 항목을 추가할 수 있습니다. 그러면 Room 모델의 host와 연결된 다른 모델의 superhost 필드를 가져옵니다.

 

 

filter_horizontal

 

    filter_horizontal = (
        "amenity",
        "facility",
        "house_rules",
    )

 

manytomany(다대 다)로 연결된 값들을 보여주는 패널을 바꿔줍니다. 훨씬 편해서 manytomany 관계인 속성들은 적용해주는 것이 좋습니다.

 

 

(좌) 구 (우) 신

 

 

fieldsets

 

사실 이 필드도 전에 다뤄본 적이 있습니다. 여기서는 좀 더 자세하게 들어가봅시다.

 

상세 어드민 패널의 구조를 커스터마이징할 수 있습니다. 튜플이어야 하므로 값이 하나일 때도 ,(쉼표)를 잊지 말고 적어줍시다. 또, fields 외에 classes 속성을 통해서 필드셋을 디자인할 수도 있습니다.

 

classes

A list or tuple containing extra CSS classes to apply to the fieldset.

Example:

{ 'classes': ('wide', 'extrapretty'), }

자주 사용하는 건 collapse로, Hide & Show를 할 수 있습니다.

 

@admin.register(models.Room)
class RoomAdmin(admin.ModelAdmin):

    """ Room Admin Definition """

    fieldsets = (
        (
            "Basic Info",
            {"fields": ("name", "description", "country", "address", "price")}
        ),
        (
            "Times",
            {"fields": ("check_in", "check_out", "instant_book")}
        ),
        (
            "More About the Space",
            {'classes': ('collapse',),
             "fields": (
                "amenity",
                "facility",
                "house_rules",
            )}
        ),
        (
            "Spaces",
            {"fields": (
                "guests",
                "beds",
                "bedrooms",
                "baths",
            )}
        ),
        (
            "Last Detail",
            {"fields": (
                "host",
            )}
        )
    )

 

ordering

ordering = ("name", "price", "bedrooms")

 

조회할 때의 순서를 지정할 수 있습니다.

위 예시의 경우 먼저 name순으로 정렬한 다음 price, bedrooms 순서로 정렬합니다.

 

 

list_display에 ManyToMany 속성 넣는 법 (QuerySet 이용)

 

본래 list_display에 다대 다 관계인 것을 넣으면 오류를 냅니다.(list_display should not be many-to-mayn)

이 경우, 함수를 사용해서 넣을 수 있습니다.

 

    list_display = (
        "instant_book",
        # 함수를 살포시 넣어준다.
        "count_amenities",
    )
    
    # 함수를 하나 만들어준다.
    def count_amenities(self, obj):
        # self는 해당 어드민 클래스
        # obj는 현재 row이다.
        print(obj.amenity.all()) """<QuerySet [<Amenity: Shower>, <Amenity: Wifi>]>"""
        
        return obj.amenity.count()

	# count_amenities라는 이름이 리스트에 뜨는 게 마음에 안들면 바꿔줄 수도 있다.
    count_amenities.short_description = "amenities"

 

쿼리셋을 활용한 것입니다. Room과 amenity는 다대다 관계이므로 따로 related_name을 설정하지 않았어도 이름으로 그냥 가져올 수 있습니다.

 

FK 관계인 것은 xxx_set의 형태로 가져올 수 있겠지만, 가독성을 위해 related_name을 설정해주고 함수로 활용해 list_display에 넣어보았습니다.

 

class Photo(core_models.TimeStampedModel):

    """Photo Model Definition"""

    caption = models.CharField(max_length=80)
    file = models.FileField()
    room = models.ForeignKey(
        "Room", related_name="photos", on_delete=models.CASCADE)

    def __str__(self):
        return self.caption
    def count_photos(self, obj):
        return (obj.photos.count())

 

 

이와 관련된 내용은 아래 포스트를 참고하도록 합시다.

 

 

 

QuerySet, managers

Making queries | Django documentation | Django Django The web framework for perfectionists with deadlines. Overview Download Documentation News Community Code Issues About ♥ Donate docs.djang..

darrengwon.tistory.com

 


darren, dev blog
블로그 이미지 DarrenKwonDev 님의 블로그
VISITOR 오늘 / 전체