django.contrib의 admin.ModelAdmin을 상속 받아서 사용할 수 있는 변수들을 알아보자
admin 패널에 보여줄 변수 적기
필터링 기준이 될 변수 적기
admin 패널에 search 바를 만듦. 검색할 필드를 지정할 수 있음
필드 이름 앞에 prefix를 지정해줄 수 있는데 아무것도 없으면 대소문자 구분없이 검색어를 포함하는 내용으로 찾아줌
= : 완전히 같아야 함(대소문자 구분 안함)
^ : 이 단어로 시작해야 함
ManyToManyField 관계에 있는 것들을 검색할 수 있는 필터를 만듦
RoomAdmin 패널에서 Room을 추가할 때 amenities 등 ManyToManyField 관계인 것들은 filter가 추가됨
꿀팁) foreignkey변수를 타고 다른 모델의 변수를 가져오고 싶을 때 : foreignkey__변수이름
_를 두번 써주자
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",
"guest",
"beds",
"bedrooms",
"baths",
"check_in",
"check_out",
"instant_book",
)
list_filter = (
"instant_book", "city", "country"
)
search_fields = ("=city", "^host__username")
filter_horizontal = ("amenities", "facilities", "house_rules")
admin 패널의 add, change 페이지를 변경할 수 있음
two-tuple로 감싸주는데 (name, field_option) 이렇게 구성되어야 함.
- name : fieldset의 제목
- field_options : dictionary 타입으로 fieldset에 들어가는 field를 정의함
- fields : field 이름
- classes : CSS 스타일. collapse(페이지 접어두기), wide(수평으로 여분의 공간 더 주기)옵션 등을 줄 수 있다
fieldsets = (
(
"Basic Info",
{"fields": ("name", "description", "country", "address", "price")},
),
("Times", {"fields": ("check_in", "check_out", "instant_book")}),
("Spaces", {"fields": ("guests", "beds", "bedrooms", "baths")}),
(
"More About the Space",
{
"classes": ("collapse",),
"fields": ("amenities", "facilities", "house_rules"),
},
),
("Last Details", {"fields": ("host",)}),
)
* admin에서 함수 만들기
list_display에 ManyToManyField 변수를 넣으면 에러가 난다
django.core.management.base.SystemCheckError: SystemCheckError: System check identified some issues:
ERRORS:
<class 'rooms.admin.RoomAdmin'>: (admin.E109) The value of 'list_display[12]' must not be a ManyToManyField.
-> ManyToManyField를 다른 형식으로 만들어서 넣어주기!
-> admin에 함수를 만들어보자
list_display에 함수 이름을 적으면 된다. admin 패널은 얘가 함수인 걸 알아서 ordering을 지원하지 않음
<함수이름>.short_description 을 정의하면 admin 패널의 제목을 함수이름이 아니라 다른 걸로 변경 가능
class RoomAdmin(admin.ModelAdmin):
list_display = (
"count_amenities",
)
def count_amenities(self, obj):
return obj.amenities.count()
count_amenities.short_description = "amenities"
class ItemAdmin(admin.ModelAdmin):
""" Item Admin Definition """
list_display = (
"name",
"used_by",
)
def used_by(self, obj):
return obj.rooms.count()
- admin에서 함수를 만들면
첫번째 인자 : self : 이 함수가 있는 admin class
두번째 인자 : obj : 해당 admin class의 Model class
used_by에서 obj.rooms의 rooms는 room_set임
* QuerySet API : django.db.models.Model을 상속받았으면 QuerySet API들이 내장돼있다
- QuerySet : DB로부터 온 Object의 리스트.
- all() 함수 : 현재 QuerySet의 복사본을 리턴함
def count_amenities(self, obj):
print(obj)
# obj(room)의 __str__함수가 리턴됨
testaaa
test_ubuntu
def count_amenities(self, obj):
print(obj.amenities)
# amenities는 __str__가 없으니 이렇게 나옴
rooms.Amenity.None
rooms.Amenity.None
def count_amenities(self, obj):
print(obj.amenities.all())
# 현재 object의 값을 보여줌
<QuerySet [<Amenity: Shower>]>
<QuerySet [<Amenity: Wifi>]>
- Django의 설정을 갖고 python에서 이것저것 해보고 싶을 때
python manage.py shell
- dir() : 인자 없을 때는 현재 local scope의 이름 출력, 인자가 있으면 그 인자의 객체가 갖고 있는 변수와 메소드 확인
['CURRENCY_CHOICES', 'CURRENCY_KRW', 'CURRENCY_USD', 'DoesNotExist', 'EMAIL_FIELD', 'GENDER_CHOICES',
'GENDER_FEMALE', 'GENDER_MALE', 'GENDER_OTHER', 'LANGUAGE_CHOICES', 'LANGUAGE_ENGLISH',
'LANGUAGE_KOREAN', 'Meta', 'MultipleObjectsReturned', 'REQUIRED_FIELDS', 'USERNAME_FIELD',
'__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__',
'__getattribute__', '__getstate__', '__gt__', '__hash__', '__init__', '__init_subclass__',
'__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__',
'__setattr__', '__setstate__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__',
'_check_column_name_clashes', '_check_constraints', '_check_field_name_clashes', '_check_fields'
, '_check_id_field', '_check_index_together', '_check_indexes', '_check_local_fields',
'_check_long_column_names', '_check_m2m_through_same_relationship', '_check_managers',
'_check_model', '_check_model_name_db_lookup_clashes', '_check_ordering',
'_check_property_name_related_field_accessor_clashes', '_check_single_primary_key',
'_check_swappable', '_check_unique_together', '_do_insert', '_do_update', '_get_FIELD_display',
'_get_next_or_previous_by_FIELD', '_get_next_or_previous_in_order', '_get_pk_val',
'_get_unique_checks', '_meta', '_password', '_perform_date_checks', '_perform_unique_checks',
'_save_parents', '_save_table', '_set_pk_val', 'avatar', 'bio', 'birthdate', 'check',
'check_password', 'clean', 'clean_fields', 'conversation_set', 'currency', 'date_error_message',
'date_joined', 'delete', 'email', 'email_user', 'first_name', 'from_db', 'full_clean', 'gender',
'get_all_permissions', 'get_currency_display', 'get_deferred_fields', 'get_email_field_name',
'get_full_name', 'get_gender_display', 'get_group_permissions', 'get_language_display',
'get_next_by_date_joined', 'get_previous_by_date_joined', 'get_session_auth_hash',
'get_short_name', 'get_username', 'groups', 'has_module_perms', 'has_perm', 'has_perms',
'has_usable_password', 'id', 'is_active', 'is_anonymous', 'is_authenticated', 'is_staff',
'is_superuser', 'language', 'last_login', 'last_name', 'list_set', 'logentry_set', 'message_set'
, 'natural_key', 'normalize_username', 'objects', 'password', 'pk', 'prepare_database_save',
'refresh_from_db', 'reservation_set', 'review_set', 'room_set', 'save', 'save_base',
'serializable_value', 'set_password', 'set_unusable_password', 'superhost',
'unique_error_message', 'user_permissions', 'username', 'username_validator', 'validate_unique']
- vars() : __dict__ 를 리턴. dict타입으로 변수 이름과 변수에 할당된 값을 확인할 수 있음
짱 많당...
mappingproxy(
{'__module__': 'users.models', '__doc__': ' Custom User Model ',
'GENDER_MALE': 'male', 'GENDER_FEMALE': 'female', 'GENDER_OTHER': 'other',
'GENDER_CHOICES': (('male', 'Male'), ('female', 'Female'), ('other', 'Other')),
'LANGUAGE_ENGLISH': 'en', 'LANGUAGE_KOREAN': 'ko',
'LANGUAGE_CHOICES': (('en', 'English'), ('ko', 'Korean')),
'CURRENCY_USD': 'usd', 'CURRENCY_KRW': 'krw',
'CURRENCY_CHOICES': (('usd', 'USD'), ('krw', 'KRW')),
'_meta': <Options for User>, 'DoesNotExist': <class 'users.models.User.DoesNotExist'>,
'MultipleObjectsReturned': <class 'users.models.User.MultipleObjectsReturned'>,
'avatar': <django.db.models.fields.files.ImageFileDescriptor object at 0x7fe5fe439be0>,
'gender': <django.db.models.query_utils.DeferredAttribute object at 0x7fe5fe439d60>,
'get_gender_display':
functools.partialmethod(<function Model._get_FIELD_display at 0x7fe5fdd9eaf0>, , field=<django.db.models.fields.CharField: gender>),
'bio': <django.db.models.query_utils.DeferredAttribute object at 0x7fe5fe439a00>,
'birthdate': <django.db.models.query_utils.DeferredAttribute object at 0x7fe5fe4399a0>,
'language': <django.db.models.query_utils.DeferredAttribute object at 0x7fe5fe439940>,
'get_language_display':
functools.partialmethod(<function Model._get_FIELD_display at 0x7fe5fdd9eaf0>, , field=<django.db.models.fields.CharField: language>),
'currency': <django.db.models.query_utils.DeferredAttribute object at 0x7fe5fe439880>,
'get_currency_display':
functools.partialmethod(<function Model._get_FIELD_display at 0x7fe5fdd9eaf0>, , field=<django.db.models.fields.CharField: currency>),
'superhost': <django.db.models.query_utils.DeferredAttribute object at 0x7fe5fe4397c0>,
'get_next_by_date_joined':
functools.partialmethod(<function Model._get_next_or_previous_by_FIELD at 0x7fe5fdd9eb80>, , field=<django.db.models.fields.DateTimeField: date_joined>, is_next=True),
'get_previous_by_date_joined':
functools.partialmethod(<function Model._get_next_or_previous_by_FIELD at 0x7fe5fdd9eb80>, , field=<django.db.models.fields.DateTimeField: date_joined>, is_next=False),
'groups': <django.db.models.fields.related_descriptors.ManyToManyDescriptor object at 0x7fe5fe4349a0>,
'user_permissions': <django.db.models.fields.related_descriptors.ManyToManyDescriptor object at 0x7fe5fe434b50>,
'id': <django.db.models.query_utils.DeferredAttribute object at 0x7fe5fe443130>,
'logentry_set': <django.db.models.fields.related_descriptors.ReverseManyToOneDescriptor object at 0x7fe5fe443310>,
'room_set': <django.db.models.fields.related_descriptors.ReverseManyToOneDescriptor object at 0x7fe5fd324520>,
'review_set': <django.db.models.fields.related_descriptors.ReverseManyToOneDescriptor object at 0x7fe5fd31ed60>,
'reservation_set': <django.db.models.fields.related_descriptors.ReverseManyToOneDescriptor object at 0x7fe5fd324910>,
'list_set': <django.db.models.fields.related_descriptors.ReverseManyToOneDescriptor object at 0x7fe5fd31ef40>,
'conversation_set': <django.db.models.fields.related_descriptors.ManyToManyDescriptor object at 0x7fe5fd3245b0>,
'message_set': <django.db.models.fields.related_descriptors.ReverseManyToOneDescriptor object at 0x7fe5fd319280>})
이중에 User.objects를 찍어보면 UserManager 타입인 것을 알 수 있다
-> DB에 서 데이터를 가져올 수 있음.
data model을 만들면 DB에서 CURD를 할 수 있게 Django가 자동으로 database-abstraction API를 준다!
-> 그 API가 QuerySet인듯. python에서 object를 다루는 방법을 위 링크에서 알려줌
- all()에서 리턴한 QuerySet을 저장해두고 filter 등 함수를 사용해서 가공할 수 있다
>>> User.objects
<django.contrib.auth.models.UserManager object at 0x7fe5fe443250>
>>> all_user = User.objects.all()
>>> all_user
<QuerySet [<User: ubuntu>, <User: test111>]>
>>> all_user.filter(superhost=True)
<QuerySet [<User: ubuntu>]>
dir(all_user)를 해보면 _set이라고 붙은 게 있다
review_set, list_set, message_set
-> user를 foreignkey, ManyToManyFields 로 지정해둔 model이 있으면
user도 이 key들을 통해서 model(review, list, message)에 접근 가능
>>> ubu = User.objects.get(username="ubuntu")
>>> ubu.room_set.all()
<QuerySet [<Room: test_ubuntu>]>
-> 기본으로 class이름_set으로 되는데 변경하고 싶으면 foreignkey 등록한 변수에 related_name으로 지정가능
host = models.ForeignKey(
"users.User", related_name="rooms", on_delete=models.CASCADE)
>>> ubu.rooms
<django.db.models.fields.related_descriptors.create_reverse_many_to_one_manager.<locals>.RelatedManager object at 0x7fc100100850>
이렇게 하면 user가 room_set으로 찾지 않고 rooms로 찾게 됨
- models.py가 변경 되었으니 migrate 해주고 python 다시 시작하면 검색 됨.
object에서 필드 변수값으로 찾을 수 있지만 id나 pk(primary key)로 찾을 수 있다
Django에서는 id와 pk가 같음
filter로 데이터를 찾을 수 있고 변수 옵션으로 startswith, ~로 시작하는 변수를 찾을 수 있음
>>> from rooms.models import Room
>>> room = Room.objects.get(id=1)
>>> room = Room.objects.get(pk=1)
>>> room.review_set.all()
<QuerySet [<Review: tttt - test_ubuntu>]>
>>> room.amenities.all()
<QuerySet [<Amenity: Wifi>]>
>>> startswith=User.objects.filter(username__startswith="ubu")
>>> startswith
<QuerySet [<User: ubuntu>]>
더 알아보기
Django ORM : Object Relational Mapping
django-orm-cookbook-ko.readthedocs.io/en/latest/
'개발 > AWS' 카테고리의 다른 글
Django 앱 만들기 - model의 save와 admin의 save_model을 오버라이딩 하기 (0) | 2021.02.02 |
---|---|
Django 앱 만들기 - Models method, upload image (0) | 2021.01.21 |
AWS 솔루션 (0) | 2021.01.20 |
Django 앱 만들기 - abstract class, ForeignKey, __str__, ManyToManyField (0) | 2021.01.19 |
Django 앱 만들기 - startapp으로 만든 앱 수정하기 (0) | 2021.01.18 |
댓글