JsonResponse()は、JSONのレスポンスを返す関数です
成功すればモーダルのように上からでてくるような表示になる
return JsonResponse({'message':'商品をカートに追加しました'})
ajaxでカートに商品を追加した。
これのメリットって何?って考えた時にDB(カート)にデータを保存すると一緒に
jQueryをつかっているためボタンを押したら「商品を追加しました」とボタンの表示を
変えることができた。
もしDjangoの関数やcreateviewをつかってカートに保存した場合、
「商品を追加しました」というメッセージは表示はできるけど、カートに追加ボタンの表示は変わらないし、
なんども押せるような状態になっているはず(でもAmazonでも2を追加した後に3を追加すれば結果カートに5個入ってるからいいのか?)
でもajaxという機能を使って実装できるというのは新しい技術に触れられるからそこはいい点
・id=forms.CharField(widget=forms.HiddenInput())とは?
CartUpdateFormで実際にidを触ることはないけど
更新の際に在庫数を超えていないかを確認しないといけないためそこでidをつかっている
その商品の在庫数をとってくるためにidを利用しているのでHiddenInputとして載せないといけない?
わからなかったからCharGPTにきいた
#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でのエラーになりますがどういうことが原因でしょうか?
このエラーは、データベーステーブルのカラムに対して 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の4つであるのに対して
views.pyで設定したform_classのAddressInputFormでは
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でログインしているユーザーをいれてあげる
#住所の入力
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)
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
・疑問
#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では
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でも同じキーで保存していることになる
住所一覧をだしてそれらをクリックして住所を指定する処理を作成する自分で考えたメモ
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という変数にいれてコンテキストに渡す、なければキャッシュのアドレスを返すといった処理にする。むずい
データベースの原子性とは
上からプログラムを実行していった際に、途中で何らかの不具合が起きて処理が途中で終わってしまったとき
望んでいない結果になることを恐れて
すべて実行するか、途中で終わるならすべて実行させないというような原則をみたす必要がある
Djangoの場合、メゾットにtransaction.atomicをデコレータにつけるとメゾット内のDB操作をまとめて、途中でエラーが発生した場合に、ロールバック(元の状態に戻すこと)される
from djnago.db import transaction
@transaction.atomic
def post(self,request,*args,**kwargs):