توی یه مدل جنگو میخاستم یه JSON ذخیره کنم، طبیعتا رفتم تو کار استفاده از JSONField. تعریف مدل اینجوری شد:
1 2 3 4 5 6 7 |
class DocumentChangeHistory(models.Model): user = models.ForeignKey(User, on_delete=models.CASCADE) request_view = models.CharField(max_length=100) request_path = models.CharField(max_length=200) request_kwargs = models.JSONField(default=dict) event_date_time = models.DateTimeField(default=now) message = models.CharField(max_length=255) |
توی یه view میخاستم kwargs ای که به view پاس داده شده رو توی این فیلد ذخیره کنم بنابراین با ORM زیر اون رو آپدیت میکردم:
1 2 3 4 5 6 7 |
DocumentChangeHistory.objects.create( user=request.user, request_view=request.resolver_match.view_name, request_path=request.path, request_kwargs=json.dumps(kwargs), message=message_to_log ) |
دیتایی که توی این فیلد ذخیره میشه حالات مختلفی داره مثل
1 2 3 |
"{\"service_id\": 78, \"doc_type\": \"0\"}" یا "{\"doc_id\": 381}" |
نکته اینجاست که من میخام یه جاهای query بزنم و اون آبجکتهایی رو داشته باشم که این فلدشون پارامتر doc_id رو توش داره (همشون ندارن) و مجبور از روش زیر query بزنم:
1 2 3 4 5 6 |
import json for hist in DocumentChangeHistory.objects.all(): js = json.loads(hist.request_kwargs) if js.get('doc_id'): print(js) |
مشکل این چیه؟ اینکه بهینه نیست باید راه حلی باشه که با یه query جواب رو بگیرم. در واقع یک ORM جنگو یکجا به SQL تبدیل بشه و یک هیت دیتابیس داشته باشه. فهمیدم که با تغییر زیر میتونم این کار رو بکنم
اول اینکه باید JSONField رو هست بگم که دیفالتش دیکشنری باشه
1 2 3 4 5 6 7 8 |
class DocumentChangeHistory(models.Model): . . . request_kwargs = models.JSONField(default=dict) . . . |
و حالا دیگه از json.dumps برای وارد کردن دیتا استفاده نمیکنیم:
1 2 3 4 5 6 7 |
DocumentChangeHistory.objects.create( user=request.user, request_view=request.resolver_match.view_name, request_path=request.path, request_kwargs=kwargs, message=message_to_log ) |
و حالا دیتایی که توی دیتابیس ذخیره میشه این فیلدش دیکشنریه و میتونیم با یه query دیتایی که میخاستیم رو بگیریم:
1 |
DocumentChangeHistory.objects.filter(request_kwargs__has_key="doc_id") |