4.1 Admin 사이트 꾸미기
4.1.1 데이터 입력 및 수정
장고에서 제공하는

우리가 만든



Models.py
# Create your models here.
class Question(models.Model):
question_text = models.CharField(max_length=200)
pub_date = models.DateTimeField('date published')
def __str__(self):
return self.question_text



4.1.2 필드 순서 변경하기
테이블의 데이터를 변경하는 것이 아니라 , 테이블을 보여 주는 UI양식을 변경하려면 POLLS/ADMIN.PY파일을 변경하면 됩니다.
from django.contrib import admin
from polls.models import Question, Choice
# Register your models here.
class QuestionAdmin(admin.ModelAdmin):
fields = ['pub_date','question_text'] #필드 순서 변경
admin.site.register(Question)
admin.site.register(Choice)
from django.contrib import admin
from polls.models import Question, Choice
# Register your models here.
class QuestionAdmin(admin.ModelAdmin):
fields = ['pub_date','question_text'] #필드 순서 변경
admin.site.register(Question,QuestionAdmin)
admin.site.register(Choice)

class QuestionAdmin(admin.ModelAdmin):
filedsets = [
('Question Statement',{'fields' :['question_text']}),
('Date Information',{'fields':['pub_date']})
]
admin.site.register(Question,QuestionAdmin)
admin.site.register(Choice)
4.1.4 필드 접기



4.1.5 외래키 관계 화면
Question과 Choice모델 클래스 는 1:N관계로 이루어져 있고 , 서로 외래키로 연결되어 있습니다.

4.1.6 Question및 Choice를 한 화면에서 변경하기
Model.py
from django.contrib import admin
from polls.models import Question, Choice
# Register your models here.
'''
class QuestionAdmin(admin.ModelAdmin):
fields = ['pub_date','question_text'] #필드 순서 변경
'''
class ChoiceInline(admin.StackedInline):
model = Choice
extra = 2
class QuestionAdmin(admin.ModelAdmin):
fieldsets = [
('None',{'fields':['question_text']}),
('Date information', {'fields': ['pub_date'], 'classes': ['collapse']}),
]
inlines = [ChoiceInline] #Choice 모델 클래스 같이 보기
admin.site.register(Question,QuestionAdmin)
admin.site.register(Choice)

우리의 예제에서는 Seoul 이라는 Choice text는 이미 들어있던 것이므로 , 그 외에 2개의 항목을 추가로 입력할 수 있습니다.
4.1.7 테이블 형식으로 보여주기
#class ChoiceInline(admin.StackedInline):
class ChoiceInline(admin.TabularInline):
model = Choice
extra = 2

4.1.8 레코드 리스트 컬럼 지정하기
Admin사이트의 첫 페이지에서 테이블명을 클릭하면 , 행당 테이블의 레코드 리스트가 나타납니다. 이때 각 레코드의 제목은 어디서 정하는 것일까요 ?

class QuestionAdmin(admin.ModelAdmin):
fields = ['pub_date','question_text'] #필드 순서 변경
'''
#class ChoiceInline(admin.StackedInline):
class ChoiceInline(admin.TabularInline):
model = Choice
extra = 2
class QuestionAdmin(admin.ModelAdmin):
fieldsets = [
('None',{'fields':['question_text']}),
('Date information', {'fields': ['pub_date'], 'classes': ['collapse']}),
]
inlines = [ChoiceInline] #Choice 모델 클래스 같이 보기
list_display = ('question_text','pub_date')#렠코드 리스트 컬럼 지정
admin.site.register(Question,QuestionAdmin)
admin.site.register(Choice)

4.1.9 list_filter필터
class ChoiceInline(admin.TabularInline):
model = Choice
extra = 2
class QuestionAdmin(admin.ModelAdmin):
fieldsets = [
('None',{'fields':['question_text']}),
('Date information', {'fields': ['pub_date'], 'classes': ['collapse']}),
]
inlines = [ChoiceInline] #Choice 모델 클래스 같이 보기
list_display = ('question_text','pub_date')#렠코드 리스트 컬럼 지정
list_filter = ['pub_date']
admin.site.register(Question,QuestionAdmin)
admin.site.register(Choice)

4.1.10 search_fields
class ChoiceInline(admin.TabularInline):
model = Choice
extra = 2
class QuestionAdmin(admin.ModelAdmin):
fieldsets = [
('None',{'fields':['question_text']}),
('Date information', {'fields': ['pub_date'], 'classes': ['collapse']}),
]
inlines = [ChoiceInline] #Choice 모델 클래스 같이 보기
list_display = ('question_text','pub_date')#렠코드 리스트 컬럼 지정
list_filter = ['pub_date']
search_fields = ['question_text']
admin.site.register(Question,QuestionAdmin)
admin.site.register(Choice)

4.1.11 polls/admin.py 변경 내역 정리
from django.contrib import admin
from polls.models import Question, Choice
# Register your models here.
'''
class QuestionAdmin(admin.ModelAdmin):
fields = ['pub_date','question_text'] #필드 순서 변경
'''
#class ChoiceInline(admin.StackedInline):
class ChoiceInline(admin.TabularInline):
model = Choice
extra = 2
class QuestionAdmin(admin.ModelAdmin):
fieldsets = [
('None',{'fields':['question_text']}),
('Date information', {'fields': ['pub_date'], 'classes': ['collapse']}),
]
inlines = [ChoiceInline] #Choice 모델 클래스 같이 보기
list_display = ('question_text','pub_date')#렠코드 리스트 컬럼 지정
list_filter = ['pub_date']
search_fields = ['question_text']
admin.site.register(Question,QuestionAdmin)
admin.site.register(Choice)
4.1.12 Admin사이트 템플릿 수정
C:\project\webprogram>django-admin startproject ch4
C:\project\webprogram>dir
C:\project\webprogram>rd /s ch4
ch4, 계속하시겠습니까(Y/N)? y
C:\project\webprogram>dir
C 드라이브의 볼륨에는 이름이 없습니다.
볼륨 일련 번호: FCA3-2376
C:\project\webprogram 디렉터리
2020-06-22 오후 01:26 <DIR> .
2020-06-22 오후 01:26 <DIR> ..
2020-06-22 오전 11:40 <DIR> ch3
2020-06-22 오후 01:24 <DIR> templates
0개 파일 0 바이트
4개 디렉터리 138,620,039,168 바이트 남음
C:\project\webprogram>rd /s templates
templates, 계속하시겠습니까(Y/N)? y
C:\project\webprogram>
C:\project\webprogram>django-admin startproject mysite
C:\project\webprogram>cd ch4
C:\project\webprogram\ch4>python manage.py startapp polls
C:\project\webprogram\ch4>
C:\project\webprogram>dir
C 드라이브의 볼륨에는 이름이 없습니다.
볼륨 일련 번호: FCA3-2376
C:\project\webprogram 디렉터리
2020-06-22 오후 01:27 <DIR> .
2020-06-22 오후 01:27 <DIR> ..
2020-06-22 오전 11:40 <DIR> ch3
2020-06-22 오후 01:27 <DIR> mysite
0개 파일 0 바이트
4개 디렉터리 138,620,768,256 바이트 남음
C:\project\webprogram>dir mysite
C 드라이브의 볼륨에는 이름이 없습니다.
볼륨 일련 번호: FCA3-2376
C:\project\webprogram\mysite 디렉터리
2020-06-22 오후 01:27 <DIR> .
2020-06-22 오후 01:27 <DIR> ..
2020-06-22 오후 01:27 647 manage.py
2020-06-22 오후 01:27 <DIR> mysite
1개 파일 647 바이트
3개 디렉터리 138,620,768,256 바이트 남음
C:\project\webprogram>dir mysite\mysite
C 드라이브의 볼륨에는 이름이 없습니다.
볼륨 일련 번호: FCA3-2376
C:\project\webprogram\mysite\mysite 디렉터리
2020-06-22 오후 01:27 <DIR> .
2020-06-22 오후 01:27 <DIR> ..
2020-06-22 오후 01:27 405 asgi.py
2020-06-22 오후 01:27 3,208 settings.py
2020-06-22 오후 01:27 769 urls.py
2020-06-22 오후 01:27 405 wsgi.py
2020-06-22 오후 01:27 0 __init__.py
5개 파일 4,787 바이트
2개 디렉터리 138,620,768,256 바이트 남음
C:\project\webprogram>move mysite ch4
1개의 디렉터리를 이동했습니다.
C:\project\webprogram\ch4>mkdir templates
C:\project\webprogram\ch4>mkdir templates/admin
명령 구문이 올바르지 않습니다.
C:\project\webprogram\ch4>mkdir templates\admin
C:\project\webprogram\ch4>copy C:\Users\NB-0308\anaconda3\Lib\site-packages\django\contrib\admin\templates\admin templates\admin\
C:\Users\NB-0308\anaconda3\Lib\site-packages\django\contrib\admin\templates\admin\404.html
C:\Users\NB-0308\anaconda3\Lib\site-packages\django\contrib\admin\templates\admin\500.html
C:\Users\NB-0308\anaconda3\Lib\site-packages\django\contrib\admin\templates\admin\actions.html
C:\Users\NB-0308\anaconda3\Lib\site-packages\django\contrib\admin\templates\admin\app_index.html
C:\Users\NB-0308\anaconda3\Lib\site-packages\django\contrib\admin\templates\admin\base.html
C:\Users\NB-0308\anaconda3\Lib\site-packages\django\contrib\admin\templates\admin\base_site.html
C:\Users\NB-0308\anaconda3\Lib\site-packages\django\contrib\admin\templates\admin\change_form.html
C:\Users\NB-0308\anaconda3\Lib\site-packages\django\contrib\admin\templates\admin\change_form_object_tools.html
C:\Users\NB-0308\anaconda3\Lib\site-packages\django\contrib\admin\templates\admin\change_list.html
C:\Users\NB-0308\anaconda3\Lib\site-packages\django\contrib\admin\templates\admin\change_list_object_tools.html
C:\Users\NB-0308\anaconda3\Lib\site-packages\django\contrib\admin\templates\admin\change_list_results.html
C:\Users\NB-0308\anaconda3\Lib\site-packages\django\contrib\admin\templates\admin\date_hierarchy.html
C:\Users\NB-0308\anaconda3\Lib\site-packages\django\contrib\admin\templates\admin\delete_confirmation.html
C:\Users\NB-0308\anaconda3\Lib\site-packages\django\contrib\admin\templates\admin\delete_selected_confirmation.html
C:\Users\NB-0308\anaconda3\Lib\site-packages\django\contrib\admin\templates\admin\filter.html
C:\Users\NB-0308\anaconda3\Lib\site-packages\django\contrib\admin\templates\admin\index.html
C:\Users\NB-0308\anaconda3\Lib\site-packages\django\contrib\admin\templates\admin\invalid_setup.html
C:\Users\NB-0308\anaconda3\Lib\site-packages\django\contrib\admin\templates\admin\login.html
C:\Users\NB-0308\anaconda3\Lib\site-packages\django\contrib\admin\templates\admin\object_history.html
C:\Users\NB-0308\anaconda3\Lib\site-packages\django\contrib\admin\templates\admin\pagination.html
C:\Users\NB-0308\anaconda3\Lib\site-packages\django\contrib\admin\templates\admin\popup_response.html
C:\Users\NB-0308\anaconda3\Lib\site-packages\django\contrib\admin\templates\admin\prepopulated_fields_js.html
C:\Users\NB-0308\anaconda3\Lib\site-packages\django\contrib\admin\templates\admin\search_form.html
C:\Users\NB-0308\anaconda3\Lib\site-packages\django\contrib\admin\templates\admin\submit_line.html
24개 파일이 복사되었습니다.
ALLOWED_HOSTS = ['192.168.56.101','localhost','127.0.0.1']
LANGUAGE_CODE = 'Asia/Seoul'
'DIRS': [os.path.join(BASE_DIR, 'templates')],

C:\project\webprogram\ch4>cd templates\admin
C:\project\webprogram\ch4\templates\admin>notepad base_site.html
C:\project\webprogram\ch4\templates\admin>
python manage.py runserver 0.0.0.0:8000
C:\project\webprogram\ch4>cd templates
C:\project\webprogram\ch4\templates>cd admin
C:\project\webprogram\ch4\templates\admin>notepad base_site.html
{% extends "admin/base.html" %}
{% block title %}{{ title }} | {{ site_title|default:_('Django site admin') }}{% endblock %}
{% block branding %}
<!--<h1 id="site-name"><a href="{% url 'admin:index' %}">{{ site_header|default:_('Django administration') }}</a></h1>-->
<h1 id="site-name"><a href="{% url 'admin:index' %}">SHK Polls Administration</a></h1>
{% endblock %}
{% block nav-global %}{% endblock %}
C:\project\webprogram\ch4>python manage.py migrate
Operations to perform:
Apply all migrations: admin, auth, contenttypes, sessions
Running migrations:
Applying contenttypes.0001_initial... OK
Applying auth.0001_initial... OK
Applying admin.0001_initial... OK
Applying admin.0002_logentry_remove_auto_add... OK
Applying admin.0003_logentry_add_action_flag_choices... OK
Applying contenttypes.0002_remove_content_type_name... OK
Applying auth.0002_alter_permission_name_max_length... OK
Applying auth.0003_alter_user_email_max_length... OK
Applying auth.0004_alter_user_username_opts... OK
Applying auth.0005_alter_user_last_login_null... OK
Applying auth.0006_require_contenttypes_0002... OK
Applying auth.0007_alter_validators_add_error_messages... OK
Applying auth.0008_alter_user_username_max_length... OK
Applying auth.0009_alter_user_last_name_max_length... OK
Applying auth.0010_alter_group_name_max_length... OK
Applying auth.0011_update_proxy_permissions... OK
Applying sessions.0001_initial... OK
C:\project\webprogram\ch4>python manage.py runserver 0.0.0.0:8000
migrate안하면 오류 난다.
C:\project\webprogram\ch4>python manage.py createsuperuser
사용자 생성

4.2 장고 파이썬 쉘로 데이터 조작하기
C:\project\webprogram\ch4>python manage.py shell
Python 3.7.6 (default, Jan 8 2020, 20:23:39) [MSC v.1916 64 bit (AMD64)]
Type 'copyright', 'credits' or 'license' for more information
IPython 7.12.0 -- An enhanced Interactive Python. Type '?' for help.
In [1]:
DJANGO_SETTINGS_MODULE
속셩을 이용하여 미리 mysite.settings.py모듈을 임포트 한다는 것입니다.
C:\project\webprogram\ch4>python manage.py startapp polls
C:\project\webprogram\ch4>cd polls
models.py
from django.db import models
# Create your models here.
from django.db import models
class Question(models.Model):
question_text = models.CharField(max_length=200)
pub_date = models.DateField('date published')
def __str__(self):
return self.question_text
class Choice(models.Model):
question = models.ForeignKey(Question, on_delete=models.CASCADE)
choice_text = models.CharField(max_length=200)
votes = models.IntegerField(default=0)
def __str__(self):
return self.choice_text
C:\project\webprogram\ch4\polls>notepad admin.py
from django.contrib import admin
from polls.models import Question, Choice
# Register your models here.
admin.site.register(Question)
admin.site.register(Choice)
C:\project\webprogram\ch4>python manage.py makemigrations
No changes detected
C:\project\webprogram\ch4>python manage.py migrate
Operations to perform:
Apply all migrations: admin, auth, contenttypes, sessions
Running migrations:
No migrations to apply.
C:\project\webprogram\ch4>
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'polls.apps.PollsConfig',
]
C:\project\webprogram\ch4>python manage.py makemigrations
Migrations for 'polls':
polls\migrations\0001_initial.py
- Create model Question
- Create model Choice
C:\project\webprogram\ch4>python manage.py migrate
Operations to perform:
Apply all migrations: admin, auth, contenttypes, polls, sessions
Running migrations:
Applying polls.0001_initial... OK
C:\project\webprogram\ch4>python manage.py runserver 0.0.0.0:8000
Watching for file changes with StatReloader
Performing system checks...
System check identified no issues (0 silenced).
June 22, 2020 - 15:05:14
Django version 3.0.7, using settings 'mysite.settings'
Starting development server at http://0.0.0.0:8000/
Quit the server with CTRL-BREAK.

In [1]: from polls.models import Questin, Choice
---------------------------------------------------------------------------
ImportError Traceback (most recent call last)
<ipython-input-1-e97d395e2540> in <module>
----> 1 from polls.models import Questin, Choice
ImportError: cannot import name 'Questin' from 'polls.models' (C:\project\webprogram\ch4\polls\models.py)
In [2]: from polls.models import Question,Choice
In [3]: from django.utils import timezone
In [4]: q = Question(question_text="What's new?",pub_date=timezone.now())
In [5]: q.save
Out[5]: <bound method Model.save of <Question: What's new?>>
In [6]: q.save()
In [7]:

In [5]: Question.objects.filter(
...: question_text_startswith='What'
...: ).exclue(
...: pub_date_gte = datetime.date.today()
...: ).filter(
...: pub_date_gte = datetime(2005,1,30)
...: )
---------------------------------------------------------------------------
FieldError Traceback (most recent call last)
<ipython-input-5-960ef36d3940> in <module>
1 Question.objects.filter(
----> 2 quesstion_text_startswith='What'
3 ).exclue(
4 pub_date_gte = datetime.date.today()
5 ).filter(
~\anaconda3\lib\site-packages\django\db\models\manager.py in manager_method(self, *args, **kwargs)
80 def create_method(name, method):
81 def manager_method(self, *args, **kwargs):
---> 82 return getattr(self.get_queryset(), name)(*args, **kwargs)
83 manager_method.__name__ = method.__name__
84 manager_method.__doc__ = method.__doc__
~\anaconda3\lib\site-packages\django\db\models\query.py in filter(self, *args, **kwargs)
902 """
903 self._not_support_combined_queries('filter')
--> 904 return self._filter_or_exclude(False, *args, **kwargs)
905
906 def exclude(self, *args, **kwargs):
~\anaconda3\lib\site-packages\django\db\models\query.py in _filter_or_exclude(self, negate, *args, **kwargs)
921 clone.query.add_q(~Q(*args, **kwargs))
922 else:
--> 923 clone.query.add_q(Q(*args, **kwargs))
924 return clone
925
~\anaconda3\lib\site-packages\django\db\models\sql\query.py in add_q(self, q_object)
1349 # So, demotion is OK.
1350 existing_inner = {a for a in self.alias_map if self.alias_map[a].join_type == INNER}
-> 1351 clause, _ = self._add_q(q_object, self.used_aliases)
1352 if clause:
1353 self.where.add(clause, AND)
~\anaconda3\lib\site-packages\django\db\models\sql\query.py in _add_q(self, q_object, used_aliases, branch_negated, current_negated, allow_joins, split_subq, simple_col, check_filterable)
1380 current_negated=current_negated, allow_joins=allow_joins,
1381 split_subq=split_subq, simple_col=simple_col,
-> 1382 check_filterable=check_filterable,
1383 )
1384 joinpromoter.add_votes(needed_inner)
~\anaconda3\lib\site-packages\django\db\models\sql\query.py in build_filter(self, filter_expr, branch_negated, current_negated, can_reuse, allow_joins, split_subq, reuse_with_filtered_relation, simple_col, check_filterable)
1249 if not arg:
1250 raise FieldError("Cannot parse keyword query %r" % arg)
-> 1251 lookups, parts, reffed_expression = self.solve_lookup_type(arg)
1252
1253 if check_filterable:
~\anaconda3\lib\site-packages\django\db\models\sql\query.py in solve_lookup_type(self, lookup)
1086 if expression:
1087 return expression_lookups, (), expression
-> 1088 _, field, _, lookup_parts = self.names_to_path(lookup_splitted, self.get_meta())
1089 field_parts = lookup_splitted[0:len(lookup_splitted) - len(lookup_parts)]
1090 if len(lookup_parts) > 1 and not field_parts:
~\anaconda3\lib\site-packages\django\db\models\sql\query.py in names_to_path(self, names, opts, allow_many, fail_on_missing)
1482 ])
1483 raise FieldError("Cannot resolve keyword '%s' into field. "
-> 1484 "Choices are: %s" % (name, ", ".join(available)))
1485 break
1486 # Check if we need any joins for concrete inheritance cases (the
FieldError: Cannot resolve keyword 'quesstion_text_startswith' into field. Choices are: choice, id, pub_date, question_text
In [6]: Question.objects.filter(
...: question_text_startswith='What'
...: ).exclue(
...: pub_date_gte = datetime.date.today()
...: ).filter(
...: pub_date_gte = datetime(2005,1,30)
...: )
---------------------------------------------------------------------------
FieldError Traceback (most recent call last)
<ipython-input-6-779424d2cb55> in <module>
1 Question.objects.filter(
----> 2 question_text_startswith='What'
3 ).exclue(
4 pub_date_gte = datetime.date.today()
5 ).filter(
~\anaconda3\lib\site-packages\django\db\models\manager.py in manager_method(self, *args, **kwargs)
80 def create_method(name, method):
81 def manager_method(self, *args, **kwargs):
---> 82 return getattr(self.get_queryset(), name)(*args, **kwargs)
83 manager_method.__name__ = method.__name__
84 manager_method.__doc__ = method.__doc__
~\anaconda3\lib\site-packages\django\db\models\query.py in filter(self, *args, **kwargs)
902 """
903 self._not_support_combined_queries('filter')
--> 904 return self._filter_or_exclude(False, *args, **kwargs)
905
906 def exclude(self, *args, **kwargs):
~\anaconda3\lib\site-packages\django\db\models\query.py in _filter_or_exclude(self, negate, *args, **kwargs)
921 clone.query.add_q(~Q(*args, **kwargs))
922 else:
--> 923 clone.query.add_q(Q(*args, **kwargs))
924 return clone
925
~\anaconda3\lib\site-packages\django\db\models\sql\query.py in add_q(self, q_object)
1349 # So, demotion is OK.
1350 existing_inner = {a for a in self.alias_map if self.alias_map[a].join_type == INNER}
-> 1351 clause, _ = self._add_q(q_object, self.used_aliases)
1352 if clause:
1353 self.where.add(clause, AND)
~\anaconda3\lib\site-packages\django\db\models\sql\query.py in _add_q(self, q_object, used_aliases, branch_negated, current_negated, allow_joins, split_subq, simple_col, check_filterable)
1380 current_negated=current_negated, allow_joins=allow_joins,
1381 split_subq=split_subq, simple_col=simple_col,
-> 1382 check_filterable=check_filterable,
1383 )
1384 joinpromoter.add_votes(needed_inner)
~\anaconda3\lib\site-packages\django\db\models\sql\query.py in build_filter(self, filter_expr, branch_negated, current_negated, can_reuse, allow_joins, split_subq, reuse_with_filtered_relation, simple_col, check_filterable)
1249 if not arg:
1250 raise FieldError("Cannot parse keyword query %r" % arg)
-> 1251 lookups, parts, reffed_expression = self.solve_lookup_type(arg)
1252
1253 if check_filterable:
~\anaconda3\lib\site-packages\django\db\models\sql\query.py in solve_lookup_type(self, lookup)
1086 if expression:
1087 return expression_lookups, (), expression
-> 1088 _, field, _, lookup_parts = self.names_to_path(lookup_splitted, self.get_meta())
1089 field_parts = lookup_splitted[0:len(lookup_splitted) - len(lookup_parts)]
1090 if len(lookup_parts) > 1 and not field_parts:
~\anaconda3\lib\site-packages\django\db\models\sql\query.py in names_to_path(self, names, opts, allow_many, fail_on_missing)
1482 ])
1483 raise FieldError("Cannot resolve keyword '%s' into field. "
-> 1484 "Choices are: %s" % (name, ", ".join(available)))
1485 break
1486 # Check if we need any joins for concrete inheritance cases (the
FieldError: Cannot resolve keyword 'question_text_startswith' into field. Choices are: choice, id, pub_date, question_text
In [9]: Question.objects.filter(
...: question_text__startswith='What'
...: ).exclue(
...: pub_date__gte = datetime.date.today()
...: ).filter(
...: pub_date__gte = datetime(2005,1,30)
...: )
---------------------------------------------------------------------------
AttributeError Traceback (most recent call last)
<ipython-input-9-bf746d06f3dc> in <module>
1 Question.objects.filter(
----> 2 question_text__startswith='What'
3 ).exclue(
4 pub_date__gte = datetime.date.today()
5 ).filter(
AttributeError: 'QuerySet' object has no attribute 'exclue'
In [9]: Question.objects.filter(
...: question_text__startswith='What'
...: ).exclude(
...: pub_date__gte = datetime.date.today()
...: ).filter(
...: pub_date__gte = datetime(2005,1,30)
...: )
In [10]: Question.objects.filter(
...: question_text__startswith='What'
...: ).exclude(
...: pub_date__gte = datetime.date.today()
...: ).filter(
...: pub_date__gte = datetime(2005,1,30)
...: )
---------------------------------------------------------------------------
NameError Traceback (most recent call last)
<ipython-input-10-b00731584e5c> in <module>
2 question_text__startswith='What'
3 ).exclude(
----> 4 pub_date__gte = datetime.date.today()
5 ).filter(
6 pub_date__gte = datetime(2005,1,30)
NameError: name 'datetime' is not defined
In [16]: one_entry = Question.objects.get(pk=1)
In [17]: one_entry
Out[17]: <Question: What's new?>
In [18]: Question.objects.all()[:5]
Out[18]: <QuerySet [<Question: What's new?>]>
In [19]:
4.2.3 Update 데이터 수정
q.question_text ='What is your favorite hobby?'
q.save()
4.2.4 delete데이터 삭제
Question.objects.filter(pub_date__year=2005).delete()
Question.objects.all().delete()
Question.objects.delete()
4.2.5 polls 애플리케이션의 데이터 실습
In [4]: from django.utils import timezone
In [5]: q = Question(question_text="What'up?
Object `up` not found.
In [6]: q = Question(question_text="What'up?
Object `up` not found.
In [7]: q = Question(question_text="What'up?", pub_date = timezone.now())
In [8]: q.save()
In [9]: q.id
Out[9]: 5
In [10]: q.question_text
Out[10]: "What'up?"
In [11]: q.pub_date
Out[11]: datetime.datetime(2020, 6, 22, 7, 7, 16, 177977, tzinfo=<UTC>)
In [12]: q.question_text = "What's new ? "
In [13]: q.save()
In [14]: Question.objects.all()
Out[14]: <QuerySet [<Question: What's new?>, <Question: What is you hobby ?>, <Question: What do you like best ?>, <Question: Where do you live ?>, <Question: What's new ? >]>
In [15]: exit()
C:\project\webprogram\ch4>python manage.py shell
Python 3.7.6 (default, Jan 8 2020, 20:23:39) [MSC v.1916 64 bit (AMD64)]
Type 'copyright', 'credits' or 'license' for more information
IPython 7.12.0 -- An enhanced Interactive Python. Type '?' for help.
In [1]: from polls.models import Question, Choice
In [2]: Question.objects.filter(pk=1)
Out[2]: <QuerySet [<Question: What's new?>]>
In [3]: Question.objects.filter(id=1)
Out[3]: <QuerySet [<Question: What's new?>]>
In [4]: Question.objects.filter(question_text__startswith='What')
Out[4]: <QuerySet [<Question: What's new?>, <Question: What is you hobby ?>, <Question: What do you like best ?>, <Question: What's new ? >]>
In [5]: from ajango.utils import timezone
---------------------------------------------------------------------------
ModuleNotFoundError Traceback (most recent call last)
<ipython-input-5-3d9b29a9cc81> in <module>
----> 1 from ajango.utils import timezone
ModuleNotFoundError: No module named 'ajango'
In [6]: from django.utils import timezone
In [7]: current_year = timezone.now().year
In [8]: Question.objects.filter(pub_date__year= current_year)
Out[8]: <QuerySet [<Question: What's new?>, <Question: What is you hobby ?>, <Question: What do you like best ?>, <Question: Where do you live ?>, <Question: What's new ? >]>
In [9]: Question.objects.get(id=5)
Out[9]: <Question: What's new ? >
In [10]: Question.objects.get(id=6)
---------------------------------------------------------------------------
DoesNotExist Traceback (most recent call last)
<ipython-input-10-24ef5a462b1a> in <module>
----> 1 Question.objects.get(id=6)
~\anaconda3\lib\site-packages\django\db\models\manager.py in manager_method(self, *args, **kwargs)
80 def create_method(name, method):
81 def manager_method(self, *args, **kwargs):
---> 82 return getattr(self.get_queryset(), name)(*args, **kwargs)
83 manager_method.__name__ = method.__name__
84 manager_method.__doc__ = method.__doc__
~\anaconda3\lib\site-packages\django\db\models\query.py in get(self, *args, **kwargs)
415 raise self.model.DoesNotExist(
416 "%s matching query does not exist." %
--> 417 self.model._meta.object_name
418 )
419 raise self.model.MultipleObjectsReturned(
DoesNotExist: Question matching query does not exist.
In [11]: Question.objects.get(pk=1)
Out[11]: <Question: What's new?>
In [12]: q = Question.objects.get(pk=2)
In [13]: q.choice_set.all()
Out[13]: <QuerySet [<Choice: Reading>, <Choice: Climbing>, <Choice: Soccer>]>
In [14]: q = Question.objects.get(pk=3)
In [15]: q.choice_set.all()
Out[15]: <QuerySet []>
In [16]: q.choice_set.create(choice_text ='Sleeping',votes=0)
Out[16]: <Choice: Sleeping>
In [17]: q.choice_set.create(choice_text='Eating',votes=0)
Out[17]: <Choice: Eating>
In [18]: c = q.choice_set.create(choice_text='Playing',votes=0)
In [19]: c.question
Out[19]: <Question: What do you like best ?>
In [20]: q.choice_set.all()
Out[20]: <QuerySet [<Choice: Sleeping>, <Choice: Eating>, <Choice: Playing>]>
In [21]: q.choice_set.count()
Out[21]: 3
In [22]: Choice.objects.filter(question__pub_date__year=current_year)
Out[22]: <QuerySet [<Choice: Reading>, <Choice: Climbing>, <Choice: Soccer>, <Choice: Seoul>, <Choice: Daejeon>, <Choice: Jeju>, <Choice: Sleeping>, <Choice: Eating>, <Choice: Playing>]>
In [23]: c = q.choice_set.filter(choice_text__startswith='Sleeping')
In [24]: c.delete()
Out[24]: (1, {'polls.Choice': 1})
장고 파이썬 쉘에서 중요한 점은 SQL쿼리 문장을 사용하지 않고도 데이터베이스에 대한 처리를 할 수 있다는 점이다.
4.3 템플릿 시스템
4.3.1 템플릿 변수
4.3.2 템플릿 필터
필터란 일반적인 용어로 어떤 객체나 결과에 추가적으로 명령을 적용하여 해당 명령에 맞게 최종 결과를 변경하는 것
{{ name|lower }} 소문자로 바꾸기
{{ text|escatpe|linebreaks }} text변수 값 중에서 특수 문자를 이스케이프해주고 (escape), 그 결과 스트링에 html<p>태그를 붙여줍니다 (linebreaks)
{{ bio|truncatewords:30 }} 앞에 30개우ㅏ 단어만 보여주고 , 줄 바꿈 문자는 모두 없애줍니다.
{{ list|join:” //” }} 만약 list가 [‘a’,’b’,’c’]라면 결과는 “a//b//c”
{{ value|default:”nothing” }} false이거나 없는 경우, “nothing”으로 보여줍니다.
{{ value|length }} 변수값의 길이 반환
{{ value|striptags }} html태그를 모두 없애줍니다. 100%보장한느 것은 아니다.
{{ value|pluralize }} Results.html에서 사용했던 복수 접미사 필터입니다.
{{ value|pluralize:”es” }} 또는 {{ value|pluralize:”ies” }} 변수값이 1이 아니면 접미사 s를 붙여줍니다.
{{ first|add:second }} 더하기
First=”python”,second=”django” =>”pythondjango”
First=[1,2,3],second=[4,5,6] =>[1,2,3,4,5,6]
First=”5”,second=”10” => 15
4.3.3 템플릿 태그
{% tag %}
{% if %}
{% for %}

{% if 태그 %}

{% if athlete_list|length > 1 %}
And, or, not , and , not , == , !=, < , >, <= , >= , in , not in
{% csrf_token %}태그
post방식의 <form>을 사용하는 템플릿 코드에서는 CSRF Cross Site Request Forgery공격
{% csrf_token %} =>악의적인 스크립트 문장이 들어있을 수도 있기 때문입니다.
<form action =”.” Method=”post” >{% csrf_token %}
위치는 forn엘리먼트의 첫줄 다음에 넣어주면 됩니다.
Csrf 토큰값의 유효성을 검증합니다. 만일 csrf토큰값 검증에 실패하면 사용자에게 403에러를 보여줍니다.
한가지 주의 할 점은 CSRF토큰값이 유출될 수 도 있으므로 , 외부 URL로 보내는 <form>에는 사용하지 않도록 합니다.
{% url %}
<form action = “{% url ‘polls:vote’ question.id %} method=”post”>
<form action=”/polls/3/vote/” method=”post”>
{% url ‘namespace;view-name’ arg1 arg2 %}
Namespace: urls.py파일의 include()함수 또는 app_name변수에 정의한 이름공간(namespace)이름
View-name:urls.py파일에서 정의한 url패턴이름
argN: 뷰 함수에서 사용하는 인자로 ,없을 수도 있고 여러 개인 경우 빈칸으로 구분함
{% with %}태그

{% load %}
{%load somelibrary package.otherlibrary %}
4.3.4 템플릿 주석
{# greeting #}hello
{# {% if foo %} bar{% else %} #}
{% comment “Optional note” %}
<p>Commented out text here</p>
{% endcomment %}
4.3.5 HTML 이스케이프
Name = “<b>username”
Hello, {{ name }}
Hello, <b>username =>약점 xss Cross Site Scripting 공격이 이루어집니다.
XSS공격이란 Cross-Site Scripting는 사이트 간 스크립팅 공격이라고도 합니다. 웹 사이트의 취약점을 공격하는 방식 중의 하나로 , 웹 사이트 관리자가 아닌 일반 사용자라도 시도할 수 있는 공격 방법입니다. 주로 여러 사용자가 보게 되는 전자 게시판에 악성 스크립트가 담긴 글을 올리는 형태로 이루어집니다. 이 취약점은 웹 애플리케이션이 사용자로부터 입력 받은 값을 제대로 검사하지 않고 사용할 경우 나타냅니다.
< <
> >
‘ '
“ "
& &
4.3.6 템플릿 상속
Title 블록, sidebar블록, content블록 3개입니다.
{% block %}
4.4 폼 처리하기
4.4.1 html에서의 폼
get post 방식
4.4.2 장고의 폼 기능
데이터가 없는 폼을 언바운드 unbound폼이라고 하며 , 언바운드 폼은 렌더링 되어 사용자에게 보옂루 때 비어있거나 디폴트 값으로 채워집니다.
바운드 bound폼은 제출된 데이터를 갖고 있어서 데이터의 유효성 검사를 하는데 사용됩니다.
4.4.3 폼 클래스로 폼 생성
참고로 장고의 폼 클래스는 모든 필드에 대해 유효성 검사 루틴을 실행시키는 is_valide()메소드 를 갖고 있습니다. 이 메소드가 호출되어 유효성 검사를 하고 , 그 결과 만일 모든 필드가 유효하다면 is_valid()메소드는 다음과 같은 2가지 일을 합니다.
True를 반환합니다.
폼 데이터를 cleaned_data속성에 넣습니다.
4.4.4 뷰에서 폼 클래스 처리
뷰 함수
Form.is_valie():
Get_name()
4.4.5 폼 클래슬르 템플릿으로 변환
{{ from.as_table }}
{{ from.as_p }}
{{ from.as_ul }}
4.5 클래스형 뷰
뷰 callable
4.5.1 클래스형 뷰의 시작점
As_view()진입 메소드의 역할은 크ㄹ래스의 인스턴스를 생성하고 , 그 인스턴스의 dispatch()메소드를 호출합니다.
Dispatch()메소드는 요청을 검사해서 GET, POST등의 어떤 HTTP메소드로 요청되었는지를 알아낸 다음 ,인스턴스 내에서 해당 이름을 갖는 메소드로 요청을 중계해줍니다.
HttpResponseNotAllowed 익셉션을 발생시킵니다.
4.5.2 클래스형 뷰의 장점 – 효율적인 메소드 구분
4.5.3 클래스형 뷰의 정점 – 상속 기능 가능
4.5.4 클래스형 제네릭 뷰
제네릭 뷰 generic view
4.5.5 클래스형 뷰에서 폼 처리
4.6 로그 남기기
4.6.1 로거
4.6.2 핸들러
4.6.3 필터
4.6.4 포맷터
4.6.5 로거 사용 및 로거 이름 계층화
mysite/settings.py
# logging
LOGGING = {
'version' :1,
# 기존의 로깅 설정을 비활성화 할 것인가?
'disable_existing_loggers' : False,
# 핸들러
# 로그 레코드로 무슨 작업을 할 것인지 정의
# 여러 핸들러 정의 가능
'handlers':{
'console':{
'class': 'loggingStreamHandler'
},
},
# 로거
# 로그 레코드 저장소
# 로거를 이름별로 정의
'loggers': {
'mylogger' :{
'handlers' : ['console'],
'level' :'INFO'
}
}
}
사용법
Import logging
#settngs.py파일에서 설정된 로거를 취득함
Logger = logging.getLogger(‘mylogger’)
4.6.6장고의 default 로깅 설정
4.6.7 장고의 로깅 추가 사항 정리



로깅 설정 – 디폴트 설정 유지

# logging
LOGGING = {
'version' :1,
# 기존의 로깅 설정을 비활성화 할 것인가?
'disable_existing_loggers' : False,
# 포맷터
# 로그 레코드는 최종적으로 텍스트로 표현됨
# 이 텍스트의 포맷 형식 정의
# 여러 포맷 정의 가능
'formatters': {
'verbose': {
'format': '[%(asctime)s] %(levelname)s [%(name)s:%(lineno)s] %(message)s',
'datefmt': '%d/%b/%Y %H:%M:%S'
},
'format2': {
'format': '%(levelname)s %(message)s'
},
},
# 핸들러
# 로그 레코드로 무슨 작업을 할 것인지 정의
# 여러 핸들러 정의 가능
'handlers':{
#'console':{
# 'class': 'loggingStreamHandler'
#},
# 로그 파일을 만들어 텍스트로 로그레코드 저장
'file': {
'level': 'DEBUG',
'class': 'logging.FileHandler',
'filename': os.path.join(BASE_DIR, 'logs','mysite.log'),
'formatter': 'verbose',
},
# 콘솔(터미널)에 출력
'console': {
'level': 'DEBUG',
'class': 'logging.StreamHandler',
'formatter': 'format2',
}
},
# 로거
# 로그 레코드 저장소
# 로거를 이름별로 정의
'loggers': {
'django' :{
'handlers' : ['file'],
'level' :'DEBUG'
},
'mysite':{
'handlers' : ['file'],
'level' : 'DEBUG',
}
}
}
4.6.9 로깅 설정 – 디폴트 설정 무시
LOGGING_CONFIG= None
LOGGING = {
}
Import logging.config
Logging.config.dictConfig(LOGGING)
출처 : Django로 배우는 쉽고 빠른 웹 개발 파이썬 웹 프로그래밍
'책 > Django로 배우는 쉽고 빠른 웹 개발 파이썬 웹 프로그래밍' 카테고리의 다른 글
05.실습 예제 확장하기 (0) | 2020.09.02 |
---|---|
03.Django 웹 프레임워크 (0) | 2020.09.02 |
02.파이썬 웹 표준 라이브러리 (0) | 2020.09.02 |
01.웹프로그래밍의 이해 (0) | 2020.09.02 |