1211 lines
52 KiB
Python
Executable File
1211 lines
52 KiB
Python
Executable File
import email
|
||
from django.contrib import admin
|
||
from django.shortcuts import render,redirect
|
||
from leaflet.admin import LeafletGeoAdmin
|
||
from leaflet.admin import LeafletGeoAdminMixin
|
||
from leaflet_admin_list.admin import LeafletAdminListMixin
|
||
from .models import RogUser, Location2025, SystemSettings, JoinedEvent, Favorite, TravelList, TravelPoint, ShapeLayers, Event, Location_line, Location_polygon, JpnAdminMainPerf, Useractions, CustomUser, GifuAreas, UserTracks, templocation, UserUpload, EventUser, GoalImages, CheckinImages, NewEvent2, Team, NewCategory, Entry, Member, TempUser, GifurogeRegister, GpsLog, GpsCheckin, Checkpoint, Waypoint
|
||
from django.contrib.auth.admin import UserAdmin
|
||
from django.urls import path,reverse
|
||
from django.shortcuts import render
|
||
from django import forms;
|
||
import requests
|
||
|
||
from django.http import HttpResponseRedirect
|
||
from django.utils.html import format_html
|
||
from .forms import CSVUploadForm
|
||
from .views import process_csv_upload
|
||
|
||
from django.db.models import F # F式をインポート
|
||
from django.db import transaction
|
||
from django.contrib import messages
|
||
import csv
|
||
from io import StringIO,TextIOWrapper
|
||
from datetime import timedelta
|
||
from django.contrib.auth.hashers import make_password
|
||
from datetime import datetime, date
|
||
from django.core.exceptions import ValidationError
|
||
|
||
from django.contrib.auth.forms import UserChangeForm, UserCreationForm
|
||
from django.utils.translation import gettext_lazy as _
|
||
|
||
from .services.csv_processor import EntryCSVProcessor
|
||
|
||
@admin.register(Entry)
|
||
class EntryAdmin(admin.ModelAdmin):
|
||
list_display = ['team', 'zekken_number', 'event', 'category', 'date', 'is_active']
|
||
|
||
# change_list_templateの追加
|
||
change_list_template = 'admin/entry/change_list.html' # この行を追加
|
||
|
||
def get_urls(self):
|
||
from django.urls import path
|
||
urls = super().get_urls()
|
||
custom_urls = [
|
||
path('upload-csv/', self.upload_csv_view, name='entry_upload_csv'),
|
||
]
|
||
return custom_urls + urls
|
||
|
||
def upload_csv_view(self, request):
|
||
processor = EntryCSVProcessor()
|
||
return processor.process_upload(request)
|
||
|
||
@admin.register(GifurogeRegister)
|
||
class GifurogeRegisterAdmin(admin.ModelAdmin):
|
||
list_display = ('event_code', 'time', 'owner_name', 'email', 'team_name', 'department')
|
||
change_list_template = 'admin/rog/gifurogeregister/change_list.html' # この行を追加
|
||
|
||
def find_matching_category(self, time, department):
|
||
"""
|
||
時間とdepartmentに基づいて適切なカテゴリを見つける
|
||
"""
|
||
try:
|
||
duration = timedelta(hours=time)
|
||
|
||
# 検索前の情報出力
|
||
print(f" Searching for category with parameters:")
|
||
print(f" - Duration: {duration}")
|
||
print(f" - Department: {department}")
|
||
|
||
# 利用可能なカテゴリの一覧を出力
|
||
all_categories = NewCategory.objects.all()
|
||
print(" Available categories:")
|
||
for cat in all_categories:
|
||
#print(f" - ID: {cat.id}")
|
||
print(f" - Name: {cat.category_name}")
|
||
print(f" - Duration: {cat.duration}")
|
||
print(f" - Number: {cat.category_number}")
|
||
|
||
# カテゴリ検索のクエリをログ出力
|
||
query = NewCategory.objects.filter(
|
||
duration=duration,
|
||
category_name__startswith=department
|
||
)
|
||
print(f" Query SQL: {query.query}")
|
||
|
||
# 検索結果の取得
|
||
category = query.first()
|
||
|
||
if category:
|
||
print(f" Found matching category:")
|
||
print(f" - Name: {category.category_name}")
|
||
print(f" - Duration: {category.duration}")
|
||
print(f" - Category Number: {getattr(category, 'category_number', 'N/A')}")
|
||
|
||
else:
|
||
print(" No matching category found with the following filters:")
|
||
print(f" - Duration equals: {duration}")
|
||
print(f" - Category name starts with: {department}")
|
||
|
||
return category
|
||
|
||
except Exception as e:
|
||
print(f"Error finding category: {e}")
|
||
print(f"Exception type: {type(e)}")
|
||
import traceback
|
||
print(f"Traceback: {traceback.format_exc()}")
|
||
return None
|
||
|
||
def create_entry_with_number(self, team, category, owner, event):
|
||
"""
|
||
カテゴリ番号をインクリメントしてエントリーを作成
|
||
"""
|
||
try:
|
||
with transaction.atomic():
|
||
# 事前バリデーション
|
||
try:
|
||
# チームメンバーの性別をチェック
|
||
if category.female:
|
||
for member in team.members.all():
|
||
|
||
print(f" Check existing member {member.user.lastname} {member.user.firstname} female:{member.user.female}")
|
||
if not member.user.female:
|
||
raise ValidationError(f"チーム '{team.team_name}' に男性メンバーが含まれているため、"
|
||
f"カテゴリー '{category.category_name}' には参加できません。")
|
||
except ValidationError as e:
|
||
print(f"Pre-validation error: {str(e)}")
|
||
raise
|
||
|
||
# カテゴリを再度ロックして取得
|
||
category_for_update = NewCategory.objects.select_for_update().get(
|
||
category_name=category.category_name
|
||
)
|
||
|
||
print(f" Creating entry with following details:")
|
||
print(f" - Category: {category_for_update.category_name}")
|
||
print(f" - Current category number: {category_for_update.category_number}")
|
||
|
||
# イベントの日付を取得
|
||
entry_date = event.start_datetime.date()
|
||
|
||
# 既存のエントリーをチェック
|
||
existing_entry = Entry.objects.filter(
|
||
team=team,
|
||
event=event,
|
||
date=entry_date,
|
||
is_active=True # アクティブなエントリーのみをチェック
|
||
).first()
|
||
|
||
if existing_entry:
|
||
print(f" Found existing entry for team {team.team_name} on {entry_date}")
|
||
raise ValidationError(
|
||
f"Team {team.team_name} already has an entry for event {event.event_name} on {entry_date}"
|
||
)
|
||
|
||
# 現在の番号を取得してインクリメント
|
||
current_number = category_for_update.category_number
|
||
zekken_number = current_number
|
||
|
||
# カテゴリ番号をインクリメント
|
||
category_for_update.category_number = F('category_number') + 1
|
||
category_for_update.save()
|
||
|
||
# 変更後の値を取得して表示
|
||
category_for_update.refresh_from_db()
|
||
print(f" Updated category number: {category_for_update.category_number}")
|
||
|
||
# エントリーの作成
|
||
try:
|
||
entry = Entry.objects.create(
|
||
date=event.start_datetime,
|
||
team=team,
|
||
category=category,
|
||
owner=owner,
|
||
event=event,
|
||
zekken_number=zekken_number,
|
||
is_active=True
|
||
)
|
||
# バリデーションを実行
|
||
entry.full_clean()
|
||
# 問題なければ保存
|
||
entry.save()
|
||
|
||
print(f" Created entry:")
|
||
print(f" - Team: {team.team_name}")
|
||
print(f" - Event: {event.event_name}")
|
||
print(f" - Category: {category.category_name}")
|
||
print(f" - Zekken Number: {zekken_number}")
|
||
|
||
return entry
|
||
|
||
except ValidationError as e:
|
||
print(f"Entry validation error: {str(e)}")
|
||
raise
|
||
|
||
except Exception as e:
|
||
print(f"Error creating entry: {e}")
|
||
print(f"Exception type: {type(e)}")
|
||
import traceback
|
||
print(f"Traceback: {traceback.format_exc()}")
|
||
raise
|
||
|
||
def split_full_name(self, full_name):
|
||
"""
|
||
フルネームを姓と名に分割
|
||
半角または全角スペースに対応
|
||
"""
|
||
try:
|
||
# 空白文字で分割(半角スペース、全角スペース、タブなど)
|
||
parts = full_name.replace(' ', ' ').split()
|
||
if len(parts) >= 2:
|
||
last_name = parts[0]
|
||
first_name = ' '.join(parts[1:]) # 名が複数単語の場合に対応
|
||
return last_name, first_name
|
||
else:
|
||
# 分割できない場合は全体を姓とする
|
||
return full_name, ''
|
||
except Exception as e:
|
||
print(f"Error splitting name '{full_name}': {e}")
|
||
return full_name, ''
|
||
|
||
def convert_japanese_date(self, date_text):
|
||
"""
|
||
日本式の日付テキストをDateField形式に変換
|
||
例: '1990年1月1日' -> datetime.date(1990, 1, 1)
|
||
"""
|
||
try:
|
||
if not date_text or date_text.strip() == '':
|
||
return None
|
||
|
||
# 全角数字を半角数字に変換
|
||
date_text = date_text.translate(str.maketrans('0123456789', '0123456789'))
|
||
date_text = date_text.strip()
|
||
|
||
# 区切り文字の判定と分割
|
||
if '年' in date_text:
|
||
# 年月日形式の場合
|
||
date_parts = date_text.replace('年', '-').replace('月', '-').replace('日', '').split('-')
|
||
elif '/' in date_text:
|
||
# スラッシュ区切りの場合
|
||
date_parts = date_text.split('/')
|
||
elif '-' in date_text:
|
||
date_parts = date_text.split('-')
|
||
else:
|
||
print(f"Unsupported date format: {date_text}")
|
||
return None
|
||
|
||
# 部分の数を確認
|
||
if len(date_parts) != 3:
|
||
print(f"Invalid date parts count: {len(date_parts)} in '{date_text}'")
|
||
return None
|
||
|
||
year = int(date_parts[0])
|
||
month = int(date_parts[1])
|
||
day = int(date_parts[2])
|
||
|
||
# 簡単な妥当性チェック
|
||
if not (1900 <= year <= 2100):
|
||
print(f"Invalid year: {year}")
|
||
return None
|
||
if not (1 <= month <= 12):
|
||
print(f"Invalid month: {month}")
|
||
return None
|
||
if not (1 <= day <= 31): # 月ごとの日数チェックは省略
|
||
print(f"Invalid day: {day}")
|
||
return None
|
||
|
||
print(f"Converted from {date_text} to year-{year} / month-{month} / day-{day}")
|
||
|
||
return date(year, month, day)
|
||
|
||
except Exception as e:
|
||
print(f"Error converting date '{date_text}': {str(e)}")
|
||
return None
|
||
|
||
def create_owner_member( self,team,row ):
|
||
"""
|
||
オーナーをチームメンバー1として作成
|
||
既存のメンバーは更新
|
||
"""
|
||
try:
|
||
owner_name = row.get('owner_name').strip()
|
||
# 姓名を分割
|
||
last_name, first_name = self.split_full_name(owner_name)
|
||
print(f" Split name - Last: {last_name}, First: {first_name}")
|
||
# 誕生日の処理
|
||
birthday = row.get(f'owner_birthday', '').strip()
|
||
birth_date = self.convert_japanese_date(birthday)
|
||
print(f" Converted birthday: {birth_date}")
|
||
|
||
# 性別の処理
|
||
sex = row.get(f'owner_sex', '').strip()
|
||
is_female = sex in ['女性','女','女子','female','girl','lady']
|
||
print(f" Sex: {sex}, is_female: {is_female}")
|
||
|
||
# メンバーを作成
|
||
member,created = Member.objects.get_or_create(
|
||
team=team,
|
||
user=team.owner,
|
||
defaults={
|
||
'is_temporary': True # 仮登録
|
||
}
|
||
)
|
||
|
||
|
||
# 既存メンバーの場合は情報を更新
|
||
if not created:
|
||
member.lastname = last_name
|
||
member.firstname = first_name
|
||
member.date_of_birth = birth_date
|
||
member.female = is_female
|
||
member.is_temporary = True
|
||
member.save()
|
||
print(f" Updated existing member {last_name} {first_name}")
|
||
else:
|
||
print(f" Created new member {last_name} {first_name}")
|
||
|
||
return member
|
||
|
||
except Exception as e:
|
||
print(f"Error creating/updating member: {e}")
|
||
raise
|
||
|
||
def create_members(self, team, row):
|
||
"""
|
||
チームのメンバーを作成
|
||
既存のメンバーは更新
|
||
"""
|
||
try:
|
||
created_members = []
|
||
|
||
# オーナーをメンバーに登録
|
||
member = self.create_owner_member(team,row)
|
||
created_members.append(member)
|
||
|
||
# メンバー2から5までを処理
|
||
for i in range(2, 6):
|
||
member_name = row.get(f'member{i}', '').strip()
|
||
if member_name:
|
||
print(f"===== Processing member: {member_name} =====")
|
||
|
||
# 姓名を分割
|
||
last_name, first_name = self.split_full_name(member_name)
|
||
print(f" Split name - Last: {last_name}, First: {first_name}")
|
||
|
||
# 誕生日の処理
|
||
birthday = row.get(f'birthday{i}', '').strip()
|
||
birth_date = self.convert_japanese_date(birthday)
|
||
print(f" Converted birthday: {birth_date}")
|
||
|
||
# 性別の処理
|
||
sex = row.get(f'sex{i}', '').strip()
|
||
is_female = sex in ['女性','女','女子','female','girl','lady']
|
||
print(f" Sex: {sex}, is_female: {is_female}")
|
||
|
||
# メンバー用のユーザーを作成
|
||
email = f"dummy_{team.id}_{i}@gifuai.net".lower()
|
||
member_user, created = CustomUser.objects.get_or_create(
|
||
email=email,
|
||
defaults={
|
||
'password': make_password('temporary_password'),
|
||
'lastname': last_name,
|
||
'firstname': first_name,
|
||
'date_of_birth': birth_date,
|
||
'female':is_female
|
||
}
|
||
)
|
||
|
||
# 既存ユーザーの場合も姓名を更新
|
||
if not created:
|
||
member_user.lastname = last_name
|
||
member_user.firstname = first_name
|
||
member_user.date_of_birth = birth_date
|
||
member_user.female = is_female
|
||
member_user.save()
|
||
|
||
try:
|
||
# メンバーを作成
|
||
member,created = Member.objects.get_or_create(
|
||
team=team,
|
||
user=member_user,
|
||
defaults={
|
||
'is_temporary': True # 仮登録
|
||
}
|
||
)
|
||
|
||
# 既存メンバーの場合は情報を更新
|
||
if not created:
|
||
member.is_temporary = True
|
||
member.save()
|
||
print(f" Updated existing member {member_user.lastname} {member_user.firstname}")
|
||
else:
|
||
print(f" Created new member {member_user.lastname} {member_user.firstname}")
|
||
|
||
created_members.append(member)
|
||
print(f" - Birthday: {member_user.date_of_birth}")
|
||
print(f" - Sex: {'Female' if member_user.female else 'Male'}")
|
||
|
||
except Exception as e:
|
||
print(f"Error creating/updating member: {e}")
|
||
raise
|
||
|
||
return created_members
|
||
|
||
except Exception as e:
|
||
print(f"Error creating members: {e}")
|
||
print(f"Exception type: {type(e)}")
|
||
import traceback
|
||
print(f"Traceback: {traceback.format_exc()}")
|
||
raise
|
||
|
||
def get_urls(self):
|
||
urls = super().get_urls()
|
||
custom_urls = [
|
||
path('upload-csv/', self.upload_csv, name='gifuroge_register_upload_csv'),
|
||
]
|
||
return custom_urls + urls
|
||
|
||
def upload_csv(self, request):
|
||
print("upload_csv")
|
||
if request.method == 'POST':
|
||
print("POST")
|
||
if 'csv_file' not in request.FILES:
|
||
messages.error(request, 'No file was uploaded.')
|
||
return redirect('..')
|
||
|
||
csv_file = request.FILES['csv_file']
|
||
print(f"csv_file(1) = {csv_file}")
|
||
if not csv_file.name.endswith('.csv'):
|
||
messages.error(request, 'File is not CSV type')
|
||
return redirect('..')
|
||
|
||
try:
|
||
# BOMを考慮してファイルを読み込む
|
||
file_content = csv_file.read()
|
||
# BOMがある場合は除去
|
||
if file_content.startswith(b'\xef\xbb\xbf'):
|
||
file_content = file_content[3:]
|
||
|
||
# デコード
|
||
file_content = file_content.decode('utf-8')
|
||
csv_file = StringIO(file_content)
|
||
reader = csv.DictReader(csv_file)
|
||
|
||
print(f"csv_file(2) = {csv_file}")
|
||
print(f"reader = {reader}")
|
||
|
||
with transaction.atomic():
|
||
for row in reader:
|
||
print(f" row={row}")
|
||
|
||
# オーナーの姓名を分割
|
||
owner_lastname, owner_firstname = self.split_full_name(row['owner_name'])
|
||
|
||
# パスワードをハッシュ化
|
||
hashed_password = make_password(row['password'])
|
||
|
||
# オーナーの誕生日の処理
|
||
owner_birthday = row.get('owner_birthday', '').strip()
|
||
owner_birth_date = self.convert_japanese_date(owner_birthday)
|
||
print(f" Owner birthday: {owner_birth_date}")
|
||
|
||
# オーナーの性別の処理
|
||
owner_sex = row.get('owner_sex', '').strip()
|
||
owner_is_female = owner_sex in ['女性','女','女子','female','girl','lady']
|
||
print(f" Owner sex: {owner_sex}, is_female: {owner_is_female}")
|
||
|
||
# ユーザーの取得または作成
|
||
user, created = CustomUser.objects.get_or_create(
|
||
email=row['email'],
|
||
defaults={
|
||
'password': hashed_password, # make_password(row['password'])
|
||
'lastname': owner_lastname,
|
||
'firstname': owner_firstname,
|
||
'date_of_birth': owner_birth_date,
|
||
'female': owner_is_female
|
||
}
|
||
)
|
||
|
||
if not created:
|
||
# 既存ユーザーの場合、空のフィールドがあれば更新
|
||
should_update = False
|
||
update_fields = []
|
||
|
||
print(f" Checking existing user data for {user.email}:")
|
||
print(f" - Current lastname: '{user.lastname}'")
|
||
print(f" - Current firstname: '{user.firstname}'")
|
||
print(f" - Current birth date: {user.date_of_birth}")
|
||
print(f" - Current female: {user.female}")
|
||
|
||
# 姓が空またはNoneの場合
|
||
if not user.lastname or user.lastname.strip() == '':
|
||
user.lastname = owner_lastname
|
||
should_update = True
|
||
update_fields.append('lastname')
|
||
print(f" - Updating lastname to: {owner_lastname}")
|
||
|
||
# 名が空またはNoneの場合
|
||
if not user.firstname or user.firstname.strip() == '':
|
||
user.firstname = owner_firstname
|
||
should_update = True
|
||
update_fields.append('firstname')
|
||
print(f" - Updating firstname to: {owner_firstname}")
|
||
|
||
# 生年月日が空またはNoneの場合
|
||
if not user.date_of_birth and owner_birth_date:
|
||
user.date_of_birth = owner_birth_date
|
||
should_update = True
|
||
update_fields.append('date_of_birth')
|
||
print(f" - Updating birth date to: {owner_birth_date}")
|
||
|
||
# 性別が空またはNoneの場合
|
||
# Booleanフィールドなのでis None で判定
|
||
if user.female is None:
|
||
user.female = owner_is_female
|
||
should_update = True
|
||
update_fields.append('female')
|
||
print(f" - Updating female to: {owner_is_female}")
|
||
|
||
# パスワードが'登録済み'でない場合のみ更新
|
||
if row['password'] != '登録済み':
|
||
user.password = hashed_password
|
||
should_update = True
|
||
update_fields.append('password')
|
||
print(f" - Updating password")
|
||
|
||
# 変更があった場合のみ保存
|
||
if should_update:
|
||
try:
|
||
# 特定のフィールドのみを更新
|
||
user.save(update_fields=update_fields)
|
||
print(f" Updated user {user.email} fields: {', '.join(update_fields)}")
|
||
except Exception as e:
|
||
print(f" Error updating user {user.email}: {str(e)}")
|
||
raise
|
||
else:
|
||
print(f" No updates needed for user {user.email}")
|
||
|
||
|
||
print(f" user created...")
|
||
print(f" Owner member created: {user.lastname} {user.firstname}")
|
||
print(f" - Birthday: {user.date_of_birth}")
|
||
print(f" - Sex: {'Female' if user.female else 'Male'}")
|
||
|
||
# 適切なカテゴリを見つける
|
||
category = self.find_matching_category(
|
||
time=int(row['time']),
|
||
department=row['department']
|
||
)
|
||
|
||
if not category:
|
||
raise ValueError(
|
||
f"No matching category found for time={row['time']} minutes "
|
||
f"and department={row['department']}"
|
||
)
|
||
|
||
print(f" Using category: {category.category_name}")
|
||
|
||
# Teamの作成(既存のチームがある場合は取得)
|
||
team, created = Team.objects.get_or_create(
|
||
team_name=row['team_name'],
|
||
defaults={
|
||
'owner': user,
|
||
'category': category
|
||
}
|
||
)
|
||
|
||
# 既存のチームの場合でもカテゴリを更新
|
||
if not created:
|
||
team.category = category
|
||
team.save()
|
||
|
||
print(" team created/updated...")
|
||
|
||
self.create_members(team, row)
|
||
|
||
# イベントの検索
|
||
try:
|
||
event_code = row['event_code']
|
||
event = NewEvent2.objects.get(event_name=event_code)
|
||
print(f" Found event: {event.event_name}")
|
||
except NewEvent2.DoesNotExist:
|
||
raise ValueError(f"Event with code {event_code} does not exist")
|
||
|
||
try:
|
||
# エントリーの作成
|
||
entry = self.create_entry_with_number(
|
||
team=team,
|
||
category=category,
|
||
owner=user,
|
||
event=event,
|
||
)
|
||
|
||
print(" entry created...")
|
||
except ValidationError as e:
|
||
messages.error(request, str(e))
|
||
return redirect('..')
|
||
|
||
gifuroge_register = GifurogeRegister.objects.create(
|
||
event_code=row['event_code'],
|
||
time=int(row['time']),
|
||
owner_name_kana=row['owner_name_kana'],
|
||
owner_name=row['owner_name'],
|
||
owner_birthday=self.convert_japanese_date(row['owner_birthday']),
|
||
owner_sex=row['owner_sex'],
|
||
email=row['email'],
|
||
password=row['password'],
|
||
team_name=row['team_name'],
|
||
department=row['department'],
|
||
members_count=int(row['members_count']),
|
||
member2=row.get('member2', '') or None,
|
||
birthday2=self.convert_japanese_date(row.get('birthday2', '') ),
|
||
sex2=row.get('sex2', '') or None,
|
||
member3=row.get('member3', '') or None,
|
||
birthday3=self.convert_japanese_date(row.get('birthday3', '') ),
|
||
sex3=row.get('sex3', '') or None,
|
||
member4=row.get('member4', '') or None,
|
||
birthday4=self.convert_japanese_date(row.get('birthday4', '') ),
|
||
sex4=row.get('sex4', '') or None,
|
||
member5=row.get('member5', '') or None,
|
||
birthday5=self.convert_japanese_date(row.get('birthday5', '') ),
|
||
sex5=row.get('sex5', '') or None
|
||
)
|
||
print(f" saved gifuroge_register...")
|
||
|
||
except UnicodeDecodeError:
|
||
messages.error(request, 'File encoding error. Please ensure the file is UTF-8 encoded.')
|
||
return redirect('..')
|
||
except Exception as e:
|
||
print(f"Error processing row: {e}")
|
||
raise
|
||
|
||
messages.success(request, 'CSV file uploaded successfully')
|
||
return redirect('..')
|
||
|
||
return render(request, 'admin/rog/gifurogeregister/upload-csv.html')
|
||
|
||
class RogAdmin(LeafletAdminListMixin, LeafletGeoAdminMixin, admin.ModelAdmin):
|
||
list_display=['title', 'venue', 'at_date',]
|
||
|
||
class ShopAdmin(LeafletAdminListMixin, LeafletGeoAdminMixin, admin.ModelAdmin):
|
||
list_display=['name',]
|
||
|
||
class EventRouteAdmin(LeafletAdminListMixin, LeafletGeoAdminMixin, admin.ModelAdmin):
|
||
list_display=['name',]
|
||
|
||
class ShopRouteAdmin(LeafletAdminListMixin, LeafletGeoAdminMixin, admin.ModelAdmin):
|
||
list_display=['name',]
|
||
|
||
class loadUserForm(forms.Form):
|
||
server_url = forms.CharField(label="Load Data from *" ,initial='https://natnats.mobilous.com/get_team_list', widget=forms.Textarea(attrs={"rows":2, "cols":95}))
|
||
|
||
|
||
class UserAdminConfig(UserAdmin):
|
||
search_fields = ('email', 'group', 'zekken_number', 'event_code', 'team_name', 'is_rogaining')
|
||
list_filter = ('email', 'group', 'is_rogaining')
|
||
ordering = ('email',)
|
||
list_display = ('email', 'group','zekken_number', 'event_code', 'team_name', 'is_active', 'is_staff', 'is_rogaining')
|
||
|
||
def get_urls(self):
|
||
urls = super().get_urls()
|
||
new_url = [path('load-users/', self.loadUsers),]
|
||
return new_url + urls
|
||
|
||
def loadUsers(self, request):
|
||
|
||
if request.method == "POST":
|
||
frm = loadUserForm(request.POST)
|
||
if frm.is_valid():
|
||
print(frm.cleaned_data['server_url'])
|
||
#load json from server
|
||
url = frm.cleaned_data['server_url']
|
||
response = requests.get(url)
|
||
data = response.json()
|
||
print("-------Event code--------")
|
||
print(data)
|
||
print("-------Event code--------")
|
||
for i in data:
|
||
_exist = CustomUser.objects.filter(email=i["zekken_number"]).delete()
|
||
other_fields.setDefaut('zekken_number',i['zekken_number'])
|
||
other_fields.setdefault('is_staff', True)
|
||
other_fields.setdefault('is_superuser', False)
|
||
other_fields.setdefault('is_active', True)
|
||
other_fields.setdefault('event_code', i['event_code'])
|
||
other_fields.setdefault('team_name', i['team_name'])
|
||
other_fields.setdefault('group', '大垣-初心者')
|
||
|
||
usr = CustomUser.objects.create_user(
|
||
email=i["zekken_number"],
|
||
password=i['password'],
|
||
**other_fields
|
||
)
|
||
|
||
form = loadUserForm()
|
||
data = {'form': form}
|
||
return render(request, 'admin/load_users.html', data)
|
||
|
||
"""
|
||
fieldsets = (
|
||
(None, {'fields':('email', 'group', 'zekken_number', 'event_code', 'team_name',)}),
|
||
('Permissions', {'fields':('is_staff', 'is_active', 'is_rogaining')}),
|
||
)
|
||
|
||
add_fieldsets = (
|
||
(None, {'classes':('wide',), 'fields':('email', 'group','zekken_number', 'event_code', 'team_name', 'password1', 'password2')}),
|
||
)
|
||
"""
|
||
# readonly_fieldsを明示的に設定
|
||
readonly_fields = ('date_joined',) # 変更不可のフィールドのみを指定=>Personal Infoも編集可能にする。
|
||
|
||
fieldsets = (
|
||
(None, {'fields': ('email', 'password')}),
|
||
(_('Personal info'), {
|
||
'fields': ('firstname', 'lastname', 'date_of_birth', 'female'),
|
||
'classes': ('wide',) # フィールドの表示を広げる
|
||
}),
|
||
(_('Permissions'), {'fields': ('is_staff', 'is_active', 'is_rogaining','user_permissions')}),
|
||
(_('Rogaining info'), {
|
||
'fields': ('zekken_number', 'event_code', 'team_name', 'group'),
|
||
'classes': ('wide',)
|
||
}),
|
||
(_('Important dates'), {
|
||
'fields': ('date_joined','last_login'),
|
||
'classes': ('wide',)
|
||
}), # 読み取り専用
|
||
)
|
||
add_fieldsets = (
|
||
(None, {
|
||
'classes': ('wide',),
|
||
#'fields': ('email', 'password1', 'password2', 'is_staff', 'is_active', 'is_rogaining')}
|
||
'fields': ('email', 'password1', 'password2', 'lastname','firstname', 'date_of_birth', 'female','is_staff', 'is_active', 'is_rogaining')}
|
||
),
|
||
)
|
||
search_fields = ('email', 'firstname', 'lastname', 'zekken_number', 'team_name')
|
||
ordering = ('email',)
|
||
|
||
class JpnSubPerfAdmin(LeafletGeoAdmin):
|
||
search_fields = ('adm0_ja', 'adm1_ja', 'adm2_ja', 'name_modified', 'area_name',)
|
||
list_filter = ('adm0_ja', 'adm0_ja', 'name_modified',)
|
||
ordering = ('adm0_ja',)
|
||
list_display = ('adm0_ja','adm1_ja','adm2_ja' ,'name_modified', 'area_name',)
|
||
|
||
class LocationAdmin(LeafletGeoAdmin):
|
||
search_fields = ('location_id', 'cp', 'location_name', 'category', 'event_name','group',)
|
||
list_filter = ('event_name', 'group',)
|
||
ordering = ('location_id', 'cp',)
|
||
list_display = ('location_id','sub_loc_id', 'cp', 'location_name', 'photos', 'category', 'group', 'event_name', 'auto_checkin', 'checkin_radius', 'checkin_point', 'buy_point',)
|
||
|
||
|
||
def tranfer_to_location(modeladmin, request, queryset):
|
||
tmp_locs = templocation.objects.all();
|
||
for l in tmp_locs :
|
||
found = Location2025.objects.filter(location_id = l.location_id).exists()
|
||
if found:
|
||
Location2025.objects.filter(location_id = l.location_id).update(
|
||
sub_loc_id = l.sub_loc_id,
|
||
cp = l.cp,
|
||
location_name = l.location_name,
|
||
category = l.category,
|
||
subcategory = l.subcategory,
|
||
zip = l.zip,
|
||
address = l.address,
|
||
prefecture = l.prefecture,
|
||
area = l.area,
|
||
city = l.city,
|
||
latitude = l.latitude,
|
||
longitude = l.longitude,
|
||
photos = l.photos,
|
||
videos = l.videos,
|
||
webcontents = l.webcontents,
|
||
status = l.status,
|
||
portal = l.portal,
|
||
group = l.group,
|
||
phone = l.phone,
|
||
fax = l.fax,
|
||
email = l.email,
|
||
facility = l.facility,
|
||
remark = l.remark,
|
||
tags = l.tags,
|
||
hidden_location = l.hidden_location,
|
||
auto_checkin = l.auto_checkin,
|
||
checkin_radius = l.checkin_radius,
|
||
checkin_point = l.checkin_point,
|
||
buy_point = l.buy_point,
|
||
evaluation_value = l.evaluation_value,
|
||
shop_closed = l.shop_closed,
|
||
shop_shutdown = l.shop_shutdown,
|
||
opening_hours_mon = l.opening_hours_mon,
|
||
opening_hours_tue = l.opening_hours_tue,
|
||
opening_hours_wed = l.opening_hours_wed,
|
||
opening_hours_thu = l.opening_hours_thu,
|
||
opening_hours_fri = l.opening_hours_fri,
|
||
opening_hours_sat = l.opening_hours_sat,
|
||
opening_hours_sun = l.opening_hours_sun,
|
||
geom=l.geom
|
||
)
|
||
else:
|
||
loc = Location2025(
|
||
location_id=l.location_id,
|
||
sub_loc_id = l.sub_loc_id,
|
||
cp = l.cp,
|
||
location_name = l.location_name,
|
||
category = l.category,
|
||
subcategory = l.subcategory,
|
||
zip = l.zip,
|
||
address = l.address,
|
||
prefecture = l.prefecture,
|
||
area = l.area,
|
||
city = l.city,
|
||
latitude = l.latitude,
|
||
longitude = l.longitude,
|
||
photos = l.photos,
|
||
videos = l.videos,
|
||
webcontents = l.webcontents,
|
||
status = l.status,
|
||
portal = l.portal,
|
||
group = l.group,
|
||
phone = l.phone,
|
||
fax = l.fax,
|
||
email = l.email,
|
||
facility = l.facility,
|
||
remark = l.remark,
|
||
tags = l.tags,
|
||
hidden_location = l.hidden_location,
|
||
auto_checkin = l.auto_checkin,
|
||
checkin_radius = l.checkin_radius,
|
||
checkin_point = l.checkin_point,
|
||
buy_point = l.buy_point,
|
||
evaluation_value = l.evaluation_value,
|
||
shop_closed = l.shop_closed,
|
||
shop_shutdown = l.shop_shutdown,
|
||
opening_hours_mon = l.opening_hours_mon,
|
||
opening_hours_tue = l.opening_hours_tue,
|
||
opening_hours_wed = l.opening_hours_wed,
|
||
opening_hours_thu = l.opening_hours_thu,
|
||
opening_hours_fri = l.opening_hours_fri,
|
||
opening_hours_sat = l.opening_hours_sat,
|
||
opening_hours_sun = l.opening_hours_sun,
|
||
geom=l.geom
|
||
)
|
||
loc.save()
|
||
l.delete()
|
||
return True
|
||
|
||
#tranfer_to_location.short_description = "Transfer all locations in temp table to location table"
|
||
|
||
|
||
class TempLocationAdmin(LeafletGeoAdmin):
|
||
search_fields = ('location_id', 'cp', 'location_name', 'category', 'event_name',)
|
||
list_filter = ('category', 'event_name',)
|
||
ordering = ('location_id', 'cp',)
|
||
list_display = ('location_id','cp', 'location_name', 'category', 'event_name', 'auto_checkin', 'checkin_radius', 'checkin_point', 'buy_point',)
|
||
actions = [tranfer_to_location,]
|
||
|
||
|
||
@admin.register(NewEvent2)
|
||
class NewEvent2Admin(admin.ModelAdmin):
|
||
list_display = ['event_name', 'start_datetime', 'end_datetime', 'csv_upload_button']
|
||
|
||
def get_urls(self):
|
||
urls = super().get_urls()
|
||
my_urls = [
|
||
path('csv-upload/', self.admin_site.admin_view(self.csv_upload_view), name='newevent2_csv_upload'),
|
||
]
|
||
return my_urls + urls
|
||
|
||
def csv_upload_view(self, request):
|
||
if request.method == 'POST':
|
||
form = CSVUploadForm(request.POST, request.FILES)
|
||
if form.is_valid():
|
||
csv_file = request.FILES['csv_file']
|
||
event = form.cleaned_data['event']
|
||
process_csv_upload(csv_file, event)
|
||
self.message_user(request, "CSV file has been processed successfully.")
|
||
return HttpResponseRedirect("../")
|
||
else:
|
||
form = CSVUploadForm()
|
||
|
||
return render(request, 'admin/csv_upload.html', {'form': form})
|
||
|
||
def csv_upload_button(self, obj):
|
||
url = reverse('admin:newevent2_csv_upload')
|
||
return format_html('<a class="button" href="{}">CSVアップロード</a>', url)
|
||
csv_upload_button.short_description = 'CSV Upload'
|
||
|
||
def changelist_view(self, request, extra_context=None):
|
||
extra_context = extra_context or {}
|
||
extra_context['csv_upload_url'] = reverse('admin:newevent2_csv_upload')
|
||
return super().changelist_view(request, extra_context=extra_context)
|
||
|
||
|
||
@admin.register(Team)
|
||
class TeamAdmin(admin.ModelAdmin):
|
||
list_display = ['team_name', 'owner']
|
||
search_fields = ['team_name', 'owner__email']
|
||
|
||
@admin.register(NewCategory)
|
||
class NewCategoryAdmin(admin.ModelAdmin):
|
||
list_display = ['category_name', 'category_number', 'duration', 'num_of_member', 'family', 'female']
|
||
list_filter = ['family', 'female']
|
||
search_fields = ['category_name']
|
||
|
||
#@admin.register(Entry)
|
||
#class EntryAdmin(admin.ModelAdmin):
|
||
# list_display = ['team', 'event', 'category', 'date']
|
||
# list_filter = ['event', 'category']
|
||
# search_fields = ['team__team_name', 'event__event_name']
|
||
|
||
@admin.register(Member)
|
||
class MemberAdmin(admin.ModelAdmin):
|
||
list_display = ['team', 'user']
|
||
search_fields = ['team__team_name', 'user__email']
|
||
|
||
@admin.register(TempUser)
|
||
class TempUserAdmin(admin.ModelAdmin):
|
||
list_display = ['email', 'is_rogaining', 'zekken_number', 'event_code', 'team_name', 'group', 'created_at', 'expires_at']
|
||
list_filter = ['is_rogaining', 'group']
|
||
search_fields = ['email', 'zekken_number', 'team_name']
|
||
|
||
|
||
# CustomUserAdmin の修正(既存のものを更新)
|
||
class CustomUserChangeForm(UserChangeForm):
|
||
class Meta(UserChangeForm.Meta):
|
||
model = CustomUser
|
||
fields = '__all__'
|
||
|
||
class CustomUserCreationForm(UserCreationForm):
|
||
class Meta(UserCreationForm.Meta):
|
||
model = CustomUser
|
||
fields = ('email', 'lastname', 'firstname', 'date_of_birth', 'female')
|
||
|
||
@admin.register(CustomUser)
|
||
class CustomUserAdmin(UserAdmin):
|
||
form = CustomUserChangeForm
|
||
add_form = CustomUserCreationForm
|
||
#model = CustomUser
|
||
|
||
list_display = ('email', 'is_staff', 'is_active', 'is_rogaining', 'zekken_number', 'event_code', 'team_name', 'group', 'firstname', 'lastname')
|
||
search_fields = ('egit mail', 'firstname', 'lastname', 'zekken_number')
|
||
list_filter = ('is_staff', 'is_active', 'is_rogaining', 'group')
|
||
ordering = ('email',)
|
||
|
||
# readonly_fieldsを明示的に設定
|
||
readonly_fields = ('date_joined',) # 変更不可のフィールドのみを指定=>Personal Infoも編集可能にする。
|
||
|
||
fieldsets = (
|
||
(None, {'fields': ('email', 'password')}),
|
||
(_('Personal info'), {
|
||
'fields': ('firstname', 'lastname', 'date_of_birth', 'female'),
|
||
'classes': ('wide',) # フィールドの表示を広げる
|
||
}),
|
||
(_('Permissions'), {'fields': ('is_staff', 'is_active', 'is_rogaining','user_permissions')}),
|
||
(_('Rogaining info'), {
|
||
'fields': ('zekken_number', 'event_code', 'team_name', 'group'),
|
||
'classes': ('wide',)
|
||
}),
|
||
(_('Important dates'), {
|
||
'fields': ('date_joined','last_login'),
|
||
'classes': ('wide',)
|
||
}), # 読み取り専用
|
||
)
|
||
add_fieldsets = (
|
||
(None, {
|
||
'classes': ('wide',),
|
||
#'fields': ('email', 'password1', 'password2', 'is_staff', 'is_active', 'is_rogaining')}
|
||
'fields': ('email', 'password1', 'password2', 'lastname','firstname', 'date_of_birth', 'female','is_staff', 'is_active', 'is_rogaining')}
|
||
),
|
||
)
|
||
search_fields = ('email', 'firstname', 'lastname', 'zekken_number', 'team_name')
|
||
ordering = ('email',)
|
||
|
||
def get_readonly_fields_old(self, request, obj=None):
|
||
# スーパーユーザーの場合は読み取り専用フィールドを最小限に
|
||
if request.user.is_superuser:
|
||
return self.readonly_fields
|
||
# 通常のスタッフユーザーの場合は追加の制限を設定可能
|
||
return self.readonly_fields + ('is_staff', 'is_superuser')
|
||
|
||
def get_readonly_fields(self, request, obj=None):
|
||
if request.user.is_superuser:
|
||
return ('date_joined', 'last_login')
|
||
return ('date_joined', 'last_login', 'is_staff', 'is_superuser')
|
||
|
||
|
||
admin.site.register(Useractions)
|
||
admin.site.register(RogUser, admin.ModelAdmin)
|
||
admin.site.register(SystemSettings, admin.ModelAdmin)
|
||
admin.site.register(JoinedEvent, admin.ModelAdmin)
|
||
admin.site.register(Favorite, admin.ModelAdmin)
|
||
admin.site.register(TravelList, admin.ModelAdmin)
|
||
admin.site.register(TravelPoint, admin.ModelAdmin)
|
||
admin.site.register(Event, admin.ModelAdmin)
|
||
admin.site.register(Location_line, LeafletGeoAdmin)
|
||
admin.site.register(Location_polygon, LeafletGeoAdmin)
|
||
admin.site.register(JpnAdminMainPerf, LeafletGeoAdmin)
|
||
admin.site.register(UserTracks, LeafletGeoAdmin);
|
||
#admin.site.register(JpnAdminPerf, LeafletGeoAdmin)
|
||
admin.site.register(GifuAreas, LeafletGeoAdmin)
|
||
admin.site.register(ShapeLayers, admin.ModelAdmin)
|
||
admin.site.register(UserUpload, admin.ModelAdmin)
|
||
admin.site.register(EventUser, admin.ModelAdmin)
|
||
#admin.site.register(UserUploadUser, admin.ModelAdmin)
|
||
#admin.site.register(ShapeFileLocations, admin.ModelAdmin)
|
||
|
||
#admin.site.register(CustomUser, UserAdminConfig)
|
||
# 古いtemplocationは無効化 - Location2025を使用
|
||
#admin.site.register(templocation, TempLocationAdmin)
|
||
admin.site.register(GoalImages, admin.ModelAdmin)
|
||
admin.site.register(CheckinImages, admin.ModelAdmin)
|
||
|
||
# GpsLogとその他の新しいモデルの登録
|
||
@admin.register(GpsLog)
|
||
class GpsLogAdmin(admin.ModelAdmin):
|
||
list_display = ['id', 'serial_number', 'zekken_number', 'event_code', 'cp_number', 'checkin_time']
|
||
list_filter = ['event_code', 'checkin_time', 'buy_flag', 'is_service_checked']
|
||
search_fields = ['zekken_number', 'event_code', 'cp_number']
|
||
readonly_fields = ['checkin_time']
|
||
|
||
@admin.register(GpsCheckin)
|
||
class GpsCheckinAdmin(admin.ModelAdmin):
|
||
list_display = ['id', 'zekken', 'event_code', 'cp_number', 'checkin_time']
|
||
list_filter = ['event_code', 'checkin_time']
|
||
search_fields = ['zekken', 'event_code', 'cp_number']
|
||
readonly_fields = ['checkin_time', 'record_time']
|
||
|
||
@admin.register(Checkpoint)
|
||
class CheckpointAdmin(admin.ModelAdmin):
|
||
list_display = ['id', 'cp_name', 'cp_number', 'photo_point', 'buy_point']
|
||
search_fields = ['cp_name', 'cp_number']
|
||
list_filter = ['photo_point', 'buy_point']
|
||
readonly_fields = ['created_at', 'updated_at']
|
||
|
||
@admin.register(Waypoint)
|
||
class WaypointAdmin(admin.ModelAdmin):
|
||
list_display = ['id', 'entry', 'latitude', 'longitude', 'recorded_at']
|
||
search_fields = ['entry__team_name']
|
||
list_filter = ['recorded_at']
|
||
readonly_fields = ['created_at']
|
||
|
||
|
||
@admin.register(Location2025)
|
||
class Location2025Admin(LeafletGeoAdmin):
|
||
"""Location2025の管理画面(全フィールド対応)"""
|
||
list_display = [
|
||
'cp_number', 'cp_name', 'event', 'sub_loc_id', 'subcategory',
|
||
'total_point', 'has_photos', 'has_videos', 'is_active',
|
||
'csv_upload_date', 'created_at'
|
||
]
|
||
list_filter = [
|
||
'event', 'is_active', 'shop_closed', 'shop_shutdown',
|
||
'subcategory', 'hidden_location',
|
||
'csv_upload_date', 'created_at'
|
||
]
|
||
search_fields = [
|
||
'cp_name', 'address', 'description', 'remark', 'tags',
|
||
'sub_loc_id', 'subcategory', 'evaluation_value'
|
||
]
|
||
readonly_fields = [
|
||
'csv_source_file', 'csv_upload_date', 'csv_upload_user',
|
||
'created_at', 'updated_at', 'created_by', 'updated_by'
|
||
]
|
||
|
||
fieldsets = (
|
||
('基本情報', {
|
||
'fields': ('cp_number', 'event', 'cp_name', 'sub_loc_id', 'subcategory', 'is_active', 'sort_order')
|
||
}),
|
||
('位置情報', {
|
||
'fields': ('latitude', 'longitude', 'location', 'address')
|
||
}),
|
||
('ポイント設定', {
|
||
'fields': ('checkin_point', 'buy_point')
|
||
}),
|
||
('チェックイン設定', {
|
||
'fields': ('checkin_radius', 'auto_checkin')
|
||
}),
|
||
('営業情報', {
|
||
'fields': ('shop_closed', 'shop_shutdown', 'opening_hours')
|
||
}),
|
||
('詳細情報', {
|
||
'fields': ('phone', 'website', 'description', 'remark')
|
||
}),
|
||
('メディア・タグ情報', {
|
||
'fields': ('photos', 'videos', 'tags', 'evaluation_value'),
|
||
'classes': ('wide',)
|
||
}),
|
||
('高度設定', {
|
||
'fields': ('hidden_location',),
|
||
'classes': ('collapse',)
|
||
}),
|
||
('CSV情報', {
|
||
'fields': ('csv_source_file', 'csv_upload_date', 'csv_upload_user'),
|
||
'classes': ('collapse',)
|
||
}),
|
||
('管理情報', {
|
||
'fields': ('created_at', 'updated_at', 'created_by', 'updated_by'),
|
||
'classes': ('collapse',)
|
||
}),
|
||
)
|
||
|
||
def has_photos(self, obj):
|
||
"""写真データ有無の表示"""
|
||
return bool(obj.photos and obj.photos.strip())
|
||
has_photos.boolean = True
|
||
has_photos.short_description = '写真'
|
||
|
||
def has_videos(self, obj):
|
||
"""動画データ有無の表示"""
|
||
return bool(obj.videos and obj.videos.strip())
|
||
has_videos.boolean = True
|
||
has_videos.short_description = '動画'
|
||
|
||
# CSV一括アップロード機能
|
||
change_list_template = 'admin/location2025/change_list.html'
|
||
|
||
def get_urls(self):
|
||
from django.urls import path
|
||
urls = super().get_urls()
|
||
custom_urls = [
|
||
path('upload-csv/', self.upload_csv_view, name='location2025_upload_csv'),
|
||
path('export-csv/', self.export_csv_view, name='location2025_export_csv'),
|
||
]
|
||
return custom_urls + urls
|
||
|
||
def upload_csv_view(self, request):
|
||
"""CSVアップロード画面"""
|
||
if request.method == 'POST':
|
||
if 'csv_file' in request.FILES and 'event' in request.POST:
|
||
csv_file = request.FILES['csv_file']
|
||
event_id = request.POST['event']
|
||
|
||
try:
|
||
from .models import NewEvent2
|
||
event = NewEvent2.objects.get(id=event_id)
|
||
|
||
# CSVインポート実行
|
||
result = Location2025.import_from_csv(
|
||
csv_file,
|
||
event,
|
||
user=request.user
|
||
)
|
||
|
||
# 結果メッセージ
|
||
if result['errors']:
|
||
messages.warning(
|
||
request,
|
||
f"インポート完了: 作成{result['created']}件, 更新{result['updated']}件, "
|
||
f"エラー{len(result['errors'])}件 - {'; '.join(result['errors'][:5])}"
|
||
)
|
||
else:
|
||
messages.success(
|
||
request,
|
||
f"CSVインポートが完了しました。作成: {result['created']}件, 更新: {result['updated']}件"
|
||
)
|
||
|
||
except Exception as e:
|
||
messages.error(request, f"CSVインポートエラー: {str(e)}")
|
||
|
||
return redirect('..')
|
||
|
||
# フォーム表示 - Location2025システム用
|
||
from .models import NewEvent2
|
||
# スタッフユーザーの場合は全ステータスのイベントを表示
|
||
if request.user.is_staff:
|
||
events = NewEvent2.objects.all().order_by('-start_datetime')
|
||
else:
|
||
events = NewEvent2.objects.filter(status='public').order_by('-start_datetime')
|
||
|
||
return render(request, 'admin/location2025/upload_csv.html', {
|
||
'events': events,
|
||
'title': 'チェックポイントCSVアップロード'
|
||
})
|
||
|
||
def export_csv_view(self, request):
|
||
"""CSVエクスポート(全フィールド対応)"""
|
||
import csv
|
||
from django.http import HttpResponse
|
||
from django.utils import timezone
|
||
|
||
response = HttpResponse(content_type='text/csv; charset=utf-8')
|
||
response['Content-Disposition'] = f'attachment; filename="checkpoints_enhanced_{timezone.now().strftime("%Y%m%d_%H%M%S")}.csv"'
|
||
|
||
# BOM付きUTF-8で出力
|
||
response.write('\ufeff')
|
||
|
||
writer = csv.writer(response)
|
||
# 全フィールドのヘッダー
|
||
writer.writerow([
|
||
'cp_number', 'cp_name', 'latitude', 'longitude', 'checkin_point',
|
||
'buy_point', 'address', 'phone', 'description',
|
||
'sub_loc_id', 'subcategory', 'photos', 'videos', 'tags',
|
||
'evaluation_value', 'remark', 'hidden_location'
|
||
])
|
||
|
||
queryset = self.get_queryset(request)
|
||
for obj in queryset:
|
||
writer.writerow([
|
||
obj.cp_number, obj.cp_name, obj.latitude, obj.longitude,
|
||
obj.checkin_point, obj.buy_point,
|
||
obj.address or '', obj.phone or '', obj.description or '',
|
||
obj.sub_loc_id or '', obj.subcategory or '', obj.photos or '',
|
||
obj.videos or '', obj.tags or '', obj.evaluation_value or '',
|
||
obj.remark or '', obj.hidden_location
|
||
])
|
||
|
||
return response
|
||
|
||
def save_model(self, request, obj, form, change):
|
||
"""保存時にユーザー情報を自動設定"""
|
||
if not change: # 新規作成時
|
||
obj.created_by = request.user
|
||
obj.updated_by = request.user
|
||
super().save_model(request, obj, form, change) |