NSDataのエンコーディングを変更する
XPathQuery.h[m]に渡すNSDataはUTF-8でないといけないようで、Shift-JISのページをダウンロードしたNSDataを渡したら怒られてしまった。そこでNSDataのエンコーディングを変更する方法。
以下のサンプルはShift-JIS -> UTF-8の変換。NS***StringEncodingを適宜変えることで他のエンコーディングにも対応できる。
NSString *str = [[NSString alloc] initWithData:responseData encoding:NSShiftJISStringEncoding]; NSData *data = [str dataUsingEncoding:NSUTF8StringEncoding];
djangoのログインフォームで「ログイン情報を保持」の有無を選択できるようにする
django標準のログインフォーム(確かAuthenticationForm)ではブラウザをとじたあともログイン状態を保持するかを選択できません。実際のサイト構築ではこの機能が必須になってくるかと思います。
スコトプリゴニエフスク通信さんを参考にしました。
pinaxというdjangoをベースにしたフレームワーク?のコードが引用されています。
私の場合、ログインにusernameを使わず、emailで行っているので強引に工夫します(usernameはプレースホルダが書きこまれています)
forms.py
class LoginForm(forms.Form): email = forms.EmailField(label=_("Email"), max_length=30) password = forms.CharField(label=_("Password"), widget=forms.PasswordInput(render_value=False)) remember = forms.BooleanField(label=_("Remember Me"), help_text=_("If checked you will stay logged in for 3 weeks"), required=False) user = None def clean(self): if self._errors: return try: u = User.objects.get(email=self.cleaned_data["email"]) except User.DoesNotExist: raise forms.ValidationError(_("The username and/or password you specified are not correct.")) user = authenticate(username=u.username, password=self.cleaned_data["password"]) if user: if user.is_active: self.user = user else: raise forms.ValidationError(_("This account is currently inactive.")) else: raise forms.ValidationError(_("The username and/or password you specified are not correct.")) return self.cleaned_data def login(self, request): if self.is_valid(): login(request, self.user) # request.user.message_set.create(message=_(u"Successfully logged in as %(username)s.") % {'username': self.user.username}) if self.cleaned_data['remember']: request.session.set_expiry(60 * 60 * 24 * 7 * 3) else: request.session.set_expiry(0) return True return False
views.py
def login(request): if request.user.is_authenticated(): # すでにログイン済み if request.method == 'POST': form = LoginForm(data=request.POST) if form.is_valid(): if form.login(request): # ログイン成功 else: # ログイン失敗 else: form = LoginForm() return render_to_response('accounts/index.html', { 'form': form, })
簡単ですね。formのclean()はview側でis_valid()を呼ばないと実行されないので注意。
djangoappengineでBlobstoreを用いてファイルアップロード・ダウンロードを実装する
djangoappengineでファイルアップロード、ダウンロードを実装するにはfiletransferを使うのが基本だと思いますが、このサンプル通りに実装すると、アップロード時の動きがGoogle App Engineに隠蔽されまくってて、謎の挙動がいっぱいあります。(単純に私のスキルに起因するものかと思いますが)
そこで、ちょっと工夫してみたいと思います。
モデルにフィールドを追加する
ファイルを保持させたいモデルにフィールド追加します。例えば、
class UserProfile(models.Model) profile_photo = models.FileField(upload_to='p', blank=True)
といったように。upload_toは適当で良いと思いますが、指定しておかないとどっかでエラーしたような気がします。
アップロードを実装
viewのファイルを編集します。アップロードされたファイルはrequest.FILES['profile_photo']といった形で取得できます。
このファイルを以下の関数でブロブストアに保存します。
(※2011/06/20現在、この方法はExperimental(実験的)とされています。使うかどうかは各個人の責任としてください)
from __future__ import with_statement #ファイルの先頭に記述する必要あり from google.appengine.api import files def _upload_to_blobstore(file): file_name = files.blobstore.create(mime_type='image/jpeg') with files.open(file_name, 'a') as f: for chunk in file.chunks(): f.write(chunk) files.finalize(file_name) return files.blobstore.get_blob_key(file_name)
戻り値でBlob Keyが返ってきます。これはダウンロードの際に必要になるので、データベースに保存します。
bk = _upload_to_blobstore(request.FILES['profile_photo']) # upがUserProfileのインスタンスだとすると up.profile_photo = str(bk)
up.profile_photoはFileFieldですが、内部的にはBlobKeyが文字列で保存されているだけなので、問題なく動作します。
ダウンロードを実装
ここもAppEngineのAPIを直接たたこうかと思いましたが、あまり上手くいかなかったので、filetransferを使います。
ダウンロードに関してはサンプル通りに実装すれば問題ありません。
def profile_photo_download_handler(request, user_pk): profile = get_object_or_404(UserProfile, user__pk=user_pk) if profile.profile_photo: return serve_file(request, profile.profile_photo) else: return HttpResponseRedirect('/static/images/default_profile_photo.png')
こんな感じで。
適当に解説してきましたが、不明な点、質問がありましたら、コメントしてください。答えられる範囲で答えます。
VirtualBox + UbuntuでSSH
ポートフォワーディングの設定
VirtualBox 4.0登場、NATポートフォワーディングとエクステンション導入 | エンタープライズ | マイコミジャーナル
VirtualBox4からGUIでポートフォワーディングの設定が可能。親2222->子22のように。
UbuntuでCUI起動をデフォルトにする
[http://labs.zsrv.net/2009/11/ubuntucui%E3%81%A7%E8%B5%B7%E5%8B%95%E3%81%99%E3%82%8B%E3%82%88%E3%81%86%E3%81%AB%E8%A8%AD%E5%AE%9A%E3%82%92%E5%A4%89%E6%9B%B4%E3%81%99%E3%82%8B/:title=[Ubuntu]CUIで起動するように設定を変更する | Labs Zsrv Net]
この記事を参考にしました。ただ、現在のUbuntuには/etc/inittabはなく、/etc/event.d/rc-defaultを変更する必要があります。
【Ubuntu】ランレベルの変更 - チラシの裏
今日の開発で参考になったサイト
自分の備忘録として、書いておきます。
Model->find()で得られる結果から関連モデルを省きたいときはrecursiveを使う
recursiveの正しい理解CakePHP - CPA-LABテクニカル
recursive :: Model の属性 :: モデル :: CakePHPによる開発 :: マニュアル :: 1.3コレクション
あるモデルから他のモデルを扱いたいときはClassRegistry::init()を使う
以下のように。
<?php $User = ClassRegistry::init('User'); $allUsers = $User->find('all');
Model->find()のconditionsには配列も使える
メモ: CakePHP find() での条件指定バリエーション - ftshの日記
複雑な find の条件 :: データを取得する :: モデル :: CakePHPによる開発 :: マニュアル :: 1.3コレクション
CakePHPのグローバル関数
array_merge(), htmlspecialchars()などよく使う関数はCakePHPのグローバル関数として用意されています。
CakePHP グローバル関数 | Sun Limited Mt.