ECサイト演習（自分用メモ）

JsonResponse()は、JSONのレスポンスを返す関数です
成功すればモーダルのように上からでてくるような表示になる
```python:
return JsonResponse({'message':'商品をカートに追加しました'})
```

ajaxでカートに商品を追加した。
これのメリットって何？って考えた時にDB（カート）にデータを保存すると一緒に
jQueryをつかっているためボタンを押したら「商品を追加しました」とボタンの表示を
変えることができた。
もしDjangoの関数やcreateviewをつかってカートに保存した場合、
「商品を追加しました」というメッセージは表示はできるけど、カートに追加ボタンの表示は変わらないし、
なんども押せるような状態になっているはず（でもAmazonでも２を追加した後に３を追加すれば結果カートに５個入ってるからいいのか？）

でもajaxという機能を使って実装できるというのは新しい技術に触れられるからそこはいい点


・id=forms.CharField(widget=forms.HiddenInput())とは？
CartUpdateFormで実際にidを触ることはないけど
更新の際に在庫数を超えていないかを確認しないといけないためそこでidをつかっている
その商品の在庫数をとってくるためにidを利用しているのでHiddenInputとして載せないといけない？


わからなかったからCharGPTにきいた
```python
#cartに商品が入っていない場合にリダイレクトする関数
def get(self,request):
    cart=get_object_or_404(Carts,user_id=request.user.id)
    if not cart.cartitems_set.all(): #インスタンス名.モデル名_set.allのインスタンスからの逆参照
        raise Http404('商品が入っていません')
    return super().get(request) #?これなに？→ 基本的なビューの振る舞いを変えずに例外を発生させるために基底クラスのgetメゾットを呼び出す必要があるとのこと
```
return super().get(request)とは振る舞いを変えないために呼び出す必要がある記述ってことかな



・IntegrityError at /stores/input_address/
NOT NULL constraint failed: addresses.user_id

上記はDjangoでのエラーになりますがどういうことが原因でしょうか？

:::note
このエラーは、データベーステーブルのカラムに対して NOT NULL 制約が設定されており、それに違反する状況でデータを挿入しようとしたときに発生します。

エラーメッセージ "NOT NULL constraint failed: addresses.user_id" は、"addresses" テーブルの "user_id" カラムに対して NOT NULL 制約があり、そのカラムに値を挿入しようとした際に "user_id" の値が NULL（空）だったことを示しています。

解決策としては、"addresses" テーブルに新しい行を挿入する際に "user_id" の値を適切な値（通常はユーザーのID）で設定するか、データベースの設計を見直してこのカラムにデフォルト値を設定することが考えられます。また、Djangoのモデルにおいても "user_id" フィールドに関する設定を確認し、正しく関連付けられているかどうかも確認してください。

:::
つまりAddressesに保存をかけようとしたけど
Addressesのカラムはzip_code,prefecture,address,userの４つであるのに対して
views.pyで設定したform_classのAddressInputFormでは
```python:forms.py

class AddressInputForm(forms.ModelForm):
    address=forms.CharField(label='住所',widget=forms.TextInput(attrs={'size':'80'}))
    
    class Meta:
        model = Addresses
        fields=['zip_code','prefecture','address']
        labels={
            'zip_code':'郵便番号',
            'prefecture':'都道府県',
        }
```
userが指定されていない。つまり外部キーで指定しているのに対して、NULLになっているから
エラーになった
これを防ぐためにform_validでログインしているユーザーをいれてあげる
```python:views.py
#住所の入力
class InputAddressView(LoginRequiredMixin,CreateView):
    template_name = os.path.join('stores','input_address.html')
    form_class = AddressInputForm
    success_url=reverse_lazy('stores:cart_items')
    #cartに商品が入っていない場合にリダイレクトする関数
    def get(self,request):
        cart=get_object_or_404(Carts,user_id=request.user.id)
        if not cart.cartitems_set.all(): #インスタンス名.モデル名_set.allのインスタンスからの逆参照
            raise Http404('商品が入っていません')
        return super().get(request) #?これなに？→ 基本的なビューの振る舞いを変えずに例外を発生させるために基底クラスのgetメゾットを呼び出す必要があるとのこと
    #下記を追加
    def form_valid(self,form): #Addressesのカラムの一つであるuserを設定する。これがないとNOT NULL制約エラーになる
        form.user=self.request.user #form.userにログインしているユーザを渡してforms.pyへ次の設定をする
        return super().form_valid(form)
```

```python:forms.py
class AddressInputForm(forms.ModelForm):
    address=forms.CharField(label='住所',widget=forms.TextInput(attrs={'size':'80'}))
    
    class Meta:
        model = Addresses
        fields=['zip_code','prefecture','address']
        labels={
            'zip_code':'郵便番号',
            'prefecture':'都道府県',
        }
      
    #NOT NULL制約エラーのための設定  
    def save(self):
        address=super().save(commit=False)
        address.user=self.user #selfとはviews.pyで渡したformのインスタンス。self.userとは渡したrequest.userが入ってる
        address.save()
        return address
```

:::note
・疑問
```python:forms.py
 #NOT NULL制約エラーのための設定  
    def save(self):
        address=super().save(commit=False)
        address.user=self.user #selfとはviews.pyで渡したformのインスタンス。self.userとは渡したrequest.userが入ってる
        address.save()
        #次回アドレスの入力を省略するためキャッシュを保存する
        cache.set(f'address_user_{self.user.id}',address) #ここ
        return address
```
forms.pyではキャッシュのキーがaddress_user_{self.user.id}なのにたいして
views.pyでは
```python:views.py
        address=cache.get(f'address_user_{self.request.user.id}','')
```
self.request.user.idでとりだすの？

→解決
views.pyのfrom_validにてform.user=self.request.userを渡している。
forms.pyのdef save（self）内でselfとはviews.pyで渡したformのインスタンスのことで
self.userとはself.request.userのこと
views.pyでformをわたし、それをforms.pyでselfという形で受け取っているためややこしい
だからcache.setの{self.user.id}とは[self.user]が[self.request.user]なので
結果的にforms.pyでもviews.pyでも同じキーで保存していることになる
:::

:::note
住所一覧をだしてそれらをクリックして住所を指定する処理を作成する自分で考えたメモ
Addressモデルからアドレス全てを取得
input_address.htmlに表示ができる
ボタンを追加する
ボタンを押したらフォームの初期値に設定する

実際は
Addressモデルからアドレス全てを取得
input_address.htmlに表示ができる
aタグでpkを指定してstores:input_addressでview.pyの関数に処理を渡す
pkをself.kwargs.get('pk')で受け取って
(その前にdef getの引数にpk=Noneを追加とreturn super().get(request,pk)も追加)
pkがあればAddressesからデータをとってきてそれをaddressという変数にいれてコンテキストに渡す、なければキャッシュのアドレスを返すといった処理にする。むずい
:::

:::note
・SQLite explorerからSQLを発行してDBのデータをいじれることを知った
![スクリーンショット 2023-08-30 17.47.56.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/627182/f2a74f9c-8333-dec5-b977-d36834df20a2.png)
SQLを書き換えて、右クリックでRun Queryを実行する
![スクリーンショット 2023-08-30 17.48.04.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/627182/b70dd14f-fd1a-8a38-bca8-f6291b2bab39.png)
:::

:::note
データベースの原子性とは
上からプログラムを実行していった際に、途中で何らかの不具合が起きて処理が途中で終わってしまったとき
望んでいない結果になることを恐れて
すべて実行するか、途中で終わるならすべて実行させないというような原則をみたす必要がある

Djangoの場合、メゾットにtransaction.atomicをデコレータにつけるとメゾット内のDB操作をまとめて、途中でエラーが発生した場合に、ロールバック（元の状態に戻すこと）される
```python
from djnago.db import transaction
@transaction.atomic
def post(self,request,*args,**kwargs):
:::