SEIYU風のECサイトを作りましょう（2）Xadminを使って管理画面を一新します

## 前回の記事
[SEIYU風のECサイトを作りましょう（1）要求分析とプロジェクト初期化](https://qiita.com/Syoitu/items/eae447432c6135ff1174)

# Xadminとは何か

GitHub上に公開されてるDjangoの管理画面の上位互換パッケージ。
<img width="545" alt="キャプチャ.PNG" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/320164/86f3ab87-6eb1-6deb-4e02-5a6eded3fe5c.png">

管理画面本来の機能を拡張し、見た目も良くします。
![https___qiita-image-store.s3.ap-northeast-1.amazonaws.com_0_320164_3cdce46d-cb8b-9fc9-3b6d-c38e8e618403.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/320164/041625cb-0307-ebd2-3641-8a3eb0e151ab.jpeg)
前回の記事で完成した管理画面を、Xadmin使用してリメイクすれば、以下のようになります。
<img width="943" alt="キ21ャプチャ.PNG" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/320164/f0b4b8f8-81fe-6dd5-1c5c-0c7f312357a3.png">
また、スタイルの切り替えも可能ですし、データのexcel出力などもデフォルト機能としてはいってます。
<img width="940" alt="キャプチャ.PNG" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/320164/d59e832f-9b80-f096-2134-c44167ee4294.png">


では、早速作っていきます。
## Xadminダウンロード
githubのリポジトリはこちらになります。[xadmin](https://github.com/sshwsfc/xadmin)

- ブランチは`django2`を選んでダウンロードしてください
- あるいは本記事のリポジトリ**extra_apps**からxadminを抜いて使ってください

本記事のリポジトリから抜いて使うことがオススメです:point_up:

**注意事項**
`pip install xadmin`は絶対しないことです、古いバージョンのxadminをおとすことで、パッケージ依存がややこしいことになります。

## 依存パッケージインストール

以下コマンドを実行し、xadminに必要なパッケージをインストールします。

[公式参考リンク](https://github.com/sshwsfc/xadmin/blob/django2/requirements.txt)

```shell
pip install django-crispy-forms
pip install django-import-export
pip install django-reversion
pip install django-formtools
pip install future
pip install httplib2
pip install six
```
### ファイル配置
**apps**と同じディレクトリで、**extra_apps**という名のフォルダを作ります。
**extra_apps**配下にダウンロードした**xadmin**を置きます。
完成後のディレクトリ構成は以下になります。

```shell

qiita-Django-supermarket
|-- requirements.txt
|-- README.md
|-- LICENSE
|-- CHANGELOG.md
|-- api
|-- |--api
|-- |-- |-- __init__.py
|-- |-- |-- settings.py
|-- |-- |-- urls.py
|-- |-- |-- wsgi.py
|-- |--apps
|-- |-- |-- goods
|-- |-- |-- users
|-- |--extra_apps
|-- |-- |-- xadmin
|-- |--manage.py

```

その後settings.pyに以下の内容を追加します。

```python:settings.py
...
sys.path.insert(0, os.path.join(BASE_DIR, 'extra_apps'))
...

INSTALLED_APPS = [
    ...
    'crispy_forms',
    'xadmin',
]

```
その後**extra_apps**を**apps**と同じように`souruces Root`に指定します。
PyCharmの操作方法は
1.extra_appsを右クリック
2. Mark Directory as 
3. souruces Root

### usersとgoods appにadminx.pyファイルを作る

usersアプリに移動して、**adminx.py**ファイルを作ります

```
cd apps/users
vim adminx.py
```

```python:apps/users/adminx.py
import xadmin
from xadmin import views
from .models import VerifyCode


class BaseSetting(object):
    enable_themes = True
    use_bootswatch = True


class GlobalSettings(object):
    site_title = "ネットスーパー"
    site_footer = "supermarket_Back"


class VerifyCodeAdmin(object):
    list_display = ['code', 'mobile', "add_time"]


xadmin.site.register(VerifyCode, VerifyCodeAdmin)
xadmin.site.register(views.BaseAdminView, BaseSetting)
xadmin.site.register(views.CommAdminView, GlobalSettings)

```

その後goodsファイルに移動し、**adminx.py**を作ります

```shell
cd ../goods
vim adminx.py
```

```python:apps/goods/adminx.py
import xadmin
from .models import Goods, GoodsCategory, GoodsImage, GoodsCategoryBrand, Banner, HotSearchWords
from .models import IndexAd

class GoodsAdmin(object):
    list_display = ["name", "click_num", "sold_num", "fav_num", "goods_num", "market_price",
                    "shop_price", "goods_brief", "is_new", "is_hot", "add_time"]
    search_fields = ['name', ]
    list_editable = ["is_hot", ]
    list_filter = ["name", "click_num", "sold_num", "fav_num", "goods_num", "market_price",
                   "shop_price", "is_new", "is_hot", "add_time", "category__name"]

    class GoodsImagesInline(object):
        model = GoodsImage
        exclude = ["add_time"]
        extra = 1
        style = 'tab'

    inlines = [GoodsImagesInline]


class GoodsCategoryAdmin(object):
    list_display = ["name", "category_type", "parent_category", "add_time"]
    list_filter = ["category_type", "parent_category", "name"]
    search_fields = ['name', ]


class GoodsBrandAdmin(object):
    list_display = ["category", "image", "name", "desc"]

    def get_context(self):
        context = super(GoodsBrandAdmin, self).get_context()
        if 'form' in context:
            context['form'].fields['category'].queryset = GoodsCategory.objects.filter(category_type=1)
        return context


class BannerGoodsAdmin(object):
    list_display = ["goods", "image", "index"]


class HotSearchAdmin(object):
    list_display = ["keywords", "index", "add_time"]


class IndexAdAdmin(object):
    list_display = ["category", "goods"]


xadmin.site.register(Goods, GoodsAdmin)
xadmin.site.register(GoodsCategory, GoodsCategoryAdmin)
xadmin.site.register(Banner, BannerGoodsAdmin)
xadmin.site.register(GoodsCategoryBrand, GoodsBrandAdmin)

xadmin.site.register(HotSearchWords, HotSearchAdmin)
xadmin.site.register(IndexAd, IndexAdAdmin)

```

### urls.pyにxadmin用のpathを追加

```python:api/urls.py
import xadmin

urlpatterns = [
    ...
    path('xadmin/', xadmin.site.urls),
    ...
]
```

最後にマイグレートを実行します。
xadmin内部にmigrateファイルがあるため、それを実行します。

```
python manage.py makemigrations 
python manage.py migrate
```
ここまで来れば

```shell
python manage.py runserver
```

サーバーを立ち上げて`http://127.0.0.1:8000/xadmin`にアクセスすると、xadminにアクセスできるようになってるはずです。

### 補足
アプリの表示名を修正したい場合。
<img width="390" alt="キャプチャ.PNG" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/320164/af422264-4268-ef35-f29d-e528d1dc63f8.png">

下記の二つの手順を実行してください。

```python:apps/goods/apps.py
from django.apps import AppConfig


class GoodsConfig(AppConfig):
    name = 'goods'
    verbose_name = "商品だよ"

```

```python:api/setting.py
INSTALLED_APPS = [
...
 'goods.apps.GoodsConfig'
...
]
```
修正後、以下のようになります。
<img width="485" alt="キャプチャ.PNG" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/320164/dd104886-cadf-83e6-90f0-f68a9b089180.png">

#次回予告

思ったよりxadminを紹介するのに時間がかかりました:frowning2:
次回は一気にAPIを作って行きたいと思います。
そしていよいよVue.jsのセットアップです。
# 次回
[SEIYU風のECサイトを作りましょう（3）Django REST frameworkで爆速APIを作りましょう](https://qiita.com/Syoitu/items/2ab045f5618bf9cb31d4)