9health / moviegeek

A django website used in the book Practical Recommender Systems to illustrate how recommender algorithms can be implemented.
MIT License
0 stars 0 forks source link

Python Django QuerySet trying #26

Open 9health opened 1 year ago

9health commented 1 year ago

Description

Expected result

quangvv9Life commented 1 year ago

Hi Hải, @9health

Đây là 1 phần trong việc hiểu và áp dụng Chương 5 phải không Hải ?

Các task nhiều và loạn quá, Hải gom nhóm kết quả một vài output để tớ cho vào taiga theo dõi theo từng sprint nhé

BR Quang

9health commented 1 year ago

Hello @quangvv9Life,

Trước hết sorry Quang rất nhiều vì hôm qua tớ có làm 1 giờ thôi chứ không có hơn được ấy :(

Về thời gian biểu của tớ hôm qua và hôm nay

Nay thì tớ đang ở quê, cũng không biết có join họp được hay không nữa :(.

Nhà bà ngoại tớ thì chưa dọn dẹp gì, nhà dì tớ cũng thế :(. Hix

Qua thì tớ dậy lúc tầm 7 giờ hơn và ngồi tới 8 giờ hơn thì ăn sáng.

Sau đấy tớ ngồi thử nghĩ ra cách viết cái Ghi Nhận Cảm Xúc nhanh hơn.

Có lẽ là dùng file Word là nhanh hơn PowerPoint hix.

Viết ý theo kiểu gạch đầu dòng và ngắn thôi nữa :(

Viết ý lớn trước, ý nhỏ sau chứ không sa đà vào chi tiết :(.

Chiều thì 14h30 mẹ tớ về quê, tớ đòi về cùng :(.

Về đến nơi thì tớ ngồi viết email cho bạn ĐH tới tận tối @@. Bạn ĐH khác lâu lắm không liên lạc rồi...

Rồi tối cũng chả làm gì được :(

Sáng nay định dậy sớm mà cũng không dậy được hix :(

Sorry Quang

Về Python Django Shell

Hôm trước đến nhà Quang thấy Quang demo dùng Python Django shell để thử database model mà lúc ý tớ cũng chưa nghĩ ra gì.

Cơ mà về nhà tớ bắt đầu suy nghĩ dần tới cái task học QuerySet trong Python Django và thấy là cái của Quang demo có lẽ rất hợp với cái task đấy @@.

Chỉ cần mở 1 dòng gọi cái interpreter đấy ra và import là mình có được tất cả thư viện Python Django trong đấy rồi và làm gì cũng được hết!!!

Quả thật là hay ho đấy, tớ thấy nó giống như là học SQL vào đấy gõ các lệnh và dần dần quen vậy!!!

Đúng là dùng shell cách tiếp cận ban đầu nhanh hơn được chứ file thì nó hơi bị kiểu như gò bó quá!!!

Về thư viện Python Django và MovieGEEKs

Đây là cách tớ gọi interactive shell của Python Django ra

(venv_3.6.9) ninehealth@LinuxVM15:~/work/moviegeek$ python3 manage.py shell

>>> from collector.models import Log

Tớ thử import cái database model của collector apps và không có vấn đề gì!!!

Nếu mà gọi lệnh python3 như bình thường đảm bảo sẽ bảo error hix.

>>> help(Log.objects)

Help on Manager in module django.db.models.manager object:

class Manager(BaseManagerFromQuerySet)
 |  Method resolution order:
 |      Manager
 |      BaseManagerFromQuerySet
 |      BaseManager
 |      builtins.object
 |  
 |  Data and other attributes defined here:
 |  
 |  __slotnames__ = []
 |  
 |  ----------------------------------------------------------------------
 |  Methods inherited from BaseManagerFromQuerySet:
 |  
 |  aggregate(self, *args, **kwargs)
 |      Return a dictionary containing the calculations (aggregation)
 |      over the current queryset.

Tiếp đó tớ thử dùng lệnh help() trong Python Django shell xem có cái gì hay ho hiện ra không.

Lệnh này tớ học được ở khóa học Python trên Google University hồi trước năm 2011 thì phải. Vậy là hơn chục năm rùi :(.

Khóa học đấy hay thật, mọi thứ đều rất là đơn giản và dễ hiểu lại còn thực tế nữa.

Mỗi tội là tớ chỉ biết học theo thôi chứ áp dụng chắc là ít =.=

Như Quang nhìn thấy ở trên thì có thể thấy là Log.objects là 1 object được instantiate được từ Manager class.

Manager class đấy là từ module django.db.models.manager của Python Django.

Sorry Quang nếu có gì tớ giải thích sai nhé vì khái niệm này có vẻ tớ ít dùng nên dễ bị nhầm lẫn :(. Tớ chỉ thuộc lý thuyết thôi. Hi vọng là tương lai sẽ cải thiện hơn hix hix.

Class Manager này được kế thừa từ class BaseManagerFromQuerySet.

Class BaseManagerFromQuerySet được kế thừa từ class BaseManager.

Class BaseManager được kế thừa từ class builtins.object.

Và nếu 1 methods (hàm) trong class Manager mà không tìm thấy ở class kế thừa level trên rồi level trên trên nữa!!!

Trong class này cũng chả thấy members (các biến) có gì cả, chỉ thấy có mỗi __slotnames__

>>> help(Log)

Help on class Log in module collector.models:

class Log(django.db.models.base.Model)
 |  Log(id, created, user_id, content_id, event, session_id)
 |  
 |  Method resolution order:
 |      Log
 |      django.db.models.base.Model
 |      builtins.object
 |  
 |  Methods defined here:
 |  
 |  __str__(self)
 |      Return str(self).
 |  
 |  content_id = <django.db.models.query_utils.DeferredAttribute object>
 |  created = <django.db.models.query_utils.DeferredAttribute object>
 |  event = <django.db.models.query_utils.DeferredAttribute object>
 |  get_next_by_created = _method(self, *, field=<django.db.models.fields.DateTimeField: created>, is_next=True, **kwargs)

Tương tự như thế tớ xem thử phần Help cho Log class.

Như collector app ở đây được gọi là Python module.

Python module sẽ bao gồm nhiều class ở trong đấy...

Dùng Python module sẽ làm cho việc quản lý nhiều class đễ hơn :|.

Có cái gì đó tớ thấy nó khác khác giữa LogLog.objects

Thôi tìm hiểu sau vậy :(

Dùng cách trên thì tương tự có thể xem class Log đấy

 |  ----------------------------------------------------------------------
 |  Methods inherited from BaseManager:
 |  
 |  __eq__(self, other)
 |      Return self==value.
 |  
 |  __hash__(self)
 |      Return hash(self).
 |  
 |  __init__(self)
 |      Initialize self.  See help(type(self)) for accurate signature.
 |  
 |  __str__(self)
 |      Return "app_label.model_label.manager_name".
 |  
 |  all(self)
 |  
 |  check(self, **kwargs)
 |  
 |  contribute_to_class(self, model, name)

Đây là các hàm trong Log.objects kế thừa được từ class Base Manager.

 |  Data and other attributes defined here:
 |  
 |  DoesNotExist = <class 'collector.models.Log.DoesNotExist'>
 |      The requested object does not exist
 |  
 |  MultipleObjectsReturned = <class 'collector.models.Log.MultipleObjects...
 |      The query returned multiple objects when only one was expected.
 |  
 |  objects = <django.db.models.manager.Manager object>

Đây là phần data (các biến hay variables) trong Log class

Như Quang thấy có thể thấy objects là 1 member trong class Log.

Help on class Log in module collector.models:

class Log(django.db.models.base.Model)
 |  Log(id, created, user_id, content_id, event, session_id)
 |  
 |  Method resolution order:
 |      Log
 |      django.db.models.base.Model
 |      builtins.object
 |  
 |  Methods defined here:
 |  ----------------------------------------------------------------------
 |  Data and other attributes defined here:
 |  ----------------------------------------------------------------------
 |  Methods inherited from django.db.models.base.Model:
 |  ----------------------------------------------------------------------
 |  Class methods inherited from django.db.models.base.Model:
 |  ----------------------------------------------------------------------
 |  Data descriptors inherited from django.db.models.base.Model:
 |  ----------------------------------------------------------------------

Đây là tớ copy ra những mục chính ở phần help của class Log

Python rất là dễ hiểu luôn.

Phần help mà tự động generate ra quả là hay ho đấy.

Và truy cập vào cũng rất là dễ luôn!!!

Tuy là không có hình về các class quan hệ với nhau thế nào nhưng mà tương lai khi đọc nhiều rồi mình có thể hình dung được ở trong đầu ý!!1

Hi vọng là như thế!!!

Kiến thức sẽ tăng lên dần!!!

Help on Manager in module django.db.models.manager object:

class Manager(BaseManagerFromQuerySet)
 |  Method resolution order:
 |      Manager
 |      BaseManagerFromQuerySet
 |      BaseManager
 |      builtins.object
 |  
 |  Data and other attributes defined here:
 |  ----------------------------------------------------------------------
 |  Methods inherited from BaseManagerFromQuerySet:
 |  ----------------------------------------------------------------------
 |  Methods inherited from BaseManager:
 |  ----------------------------------------------------------------------
 |  Class methods inherited from BaseManager:
 |  ----------------------------------------------------------------------
 |  Static methods inherited from BaseManager:
 |  ----------------------------------------------------------------------
 |  Data descriptors inherited from BaseManager:
 |  ----------------------------------------------------------------------
 |  Data and other attributes inherited from BaseManager:

Còn đây là tớ copy lại các mục chính trong phần Help của Log.objects

https://en.wikibooks.org/wiki/Python_Programming/Self_Help

https://docs.python.org/3/tutorial/interpreter.html

Tớ thấy phần Help của Python hay quá và lên mạng xem là có tính năng gì nữa không

>>> help("django")
Help on package django:

NAME
    django

PACKAGE CONTENTS
    __main__
    apps (package)
    conf (package)
    contrib (package)
    core (package)
    db (package)
    dispatch (package)
    forms (package)
    http (package)
    middleware (package)
    shortcuts

Như ở trên thì có thể thấy nội dung của Python Django package.

Lại 1 khái niệm mới nữa xuất hiện ở đây là package!!!

Có lẽ package sẽ là 1 tập hợp của nhiều module trong Python.

Kiến thức của tớ có vẻ bị rỗng hay quên nhiều quá!!!

Có lẽ sẽ cần bổ sung thêm hix.

Cơ mà công nhận là phần Help trong Python interpreter quả là hay vì đọc kiểu này có thể cũng hiểu sơ sơ rồi, list ra các hàm mình có thể dùng rồi thay vì lên mạng search và vào web lung tung, có khi lại còn bị giải thích sai nữa ý @_@.

Về các thứ khác

Hix tới đây thì tớ bị gọi đi ăn sáng hôm qua rồi

Mong Quang thông cảm nhé :( Tớ cũng chưa biết recover cái 1 tiếng đấy thế nào đây huhu.

Lý do tớ phải tìm hiểu kỹ thế này thay vì lên mang xem QuerySet người ta viết như thế nào và bắt chước là để hiểu sâu hơn mình có thể làm gì với QuerySet!!!

Không thể chỉ có lên mạng và đọc tài liệu mãi được mà cần nhìn vào source code hoặc documentation để dùng =.=

Mà documentation của Django tớ thấy viết cứ ảo ảo thế nào ấy =.= Chắc do tớ còn non nên chưa quen =.=

Mà tớ thấy kiểu xem Help bằng command line thế này hay hơn nhiều so với dùng chuột như ở Visual Studio các thứ hay lên trang Microsoft Docs =.=

Do intepreter tiện mà!!!

Visual Studio tớ nghĩ cũng có khả năng hiển thị tài liệu như Python thôi cơ mà nó nhiều và nhìn choáng quá =.=

Còn nếu mà dùng auto-complete hay IntelliSense của Microsoft để gợi ý thì nói thật là mình cũng không hiểu các hàm ý làm gì :(.

Xong rồi click vào ra 1 cái document to đùng :(. Ngại thật!!!

Vậy nên hi vọng Quang chấp nhận cách tìm hiểu này của tớ nhé @@@@@. Cho dù nó hơi miên man thật cơ mà sẽ hiểu sâu hơn và debug có lẽ sẽ tốt hơn :(.

Dù gì cũng khá mới với tớ vì tớ cũng toàn theo kiểu dùng thư viện Python trong 1 file thôi chứ có bao giờ viết Python ở nhiều file đâu :(.

Cũng chỉ xem ví dụ trên mạng và gọi hàm đấy ra thui!!!

Cơ mà tớ nghĩ tiếp cận kiểu này thì mới có thể dùng hết chức năng của Python Django được.

Và còn hiểu về OOP trong Python nữa, quả là hay ho!!!

Ngoài ra thì tớ cũng nghĩ về buổi họp với Microsoft hôm trước ở nhà Quang với ở quán cafe.

Đúng là khi mình ngồi làm việc, có bàn làm việc, chuẩn bị tư thế vào đấy họp trước 15 phút thì mọi thứ mới smooth được, tài liệu mới ghi chép đầy đủ được :(.

Chứ như hôm ở chỗ chị Nhi tớ với Quang chả ghi lại gì, chả chụp lại màn hình gì :(. Cũng phí thật.

Thôi rút kinh nghiệm hix hix T_T. Hi vọng là tuần sau là tuần thứ 3 từ hôm họp, Quang gửi 1 cái email remind lý do đấy và họ sẽ share lại cho mình cái video =.=

Hoặc là nếu thấy audio và ảnh tớ capture là đủ rồi thì thôi vậy!!!

Cảm ơn Quang một lần nữa!!!

Có gì tớ sẽ xem meeting minute của Quang và anh Công sau.

Nếu Quang muốn làm theo kiểu cứ insert dần slide vào thì cứ làm nhé!!!

Cơ mà có thể làm theo kiểu mỗi lần họp copy file cũ ra 1 file mới ý được không mặc dù OneDrive cũng cho lưu version T_T.

Cảm ơn Quang nhiều!!!

Chúc Quang cuối tuần vui vẻ và họp thật tốt!!!

À qua thì tớ phát hiện ra 1 lỗi chưa setup đúng Python Virtual Environments nữa. Có lẽ là Quang cũng đã phát hiện ra và fix lại được rồi!!!

Thôi tớ thấy mọi thứ với tớ vẫn đang kiểu còn okay nên tớ sẽ để pending tạm thời hix.

9health commented 1 year ago

Hello @quangvv9Life,

Thanks Quang đã chờ đợi nhé @@.

Tớ có đọc lướt qua comment trên của Quang cơ mà chưa kỹ lắm.

Có gì tớ sẽ trả lời sau nhé.

Tớ vừa mới phơi quần áo xong :(.

Sorry tớ comment hơi muộn.

Về thời gian biểu của tớ

Qua thì tớ về quê rồi. Sáng thì lúc Quang gọi họp tớ cũng ăn sáng xong rồi cơ mà đang ở nhà dì với cả em họ đang ngủ nên là thôi :( Tớ quay vào đọc QuerySet tiếp :(.

Chiều ngủ dậy thì mẹ tớ bắt tớ ngồi làm bài tập chị kia và kêu là tốn bao nhiêu xiền 1 buổi @@. Cơ mà thôi tớ lại đọc tiếp QuerySet từ 4 giờ chiều tới 6 giờ 30 chiều.

Hình như tớ ngồi không đúng tư thế cái bàn học gấp nên tối bị đau cổ @@. Mệt quá thui chả làm gì nữa.

https://www.oxfordlearnersdictionaries.com/external/pdf/wordlists/oxford-3000-5000/American_Oxford_3000.pdf

Tớ ngồi xem thử file The Oxford 3000 xem là mình biết bao nhiêu từ trong ý (chị kia thì nghe bảo muốn học PhD cần tiếng Anh cơ mà tớ hỏi vài từ trong này mà cũng không biết hết @@, sợ thật mà dịch tiếng Việt qua Google Translate vẫn ổn lắm...)

Chắc 30 phút mới kiểm tra xong thì thấy là mình không biết có 15 từ @@.

Ngẫm nghĩ lại không hiểu mình học 3,000 từ dấy kiểu gì vậy @@. Nói thật hình như tớ cũng ít tự học tiếng Anh lắm =.=

Thôi hôm nào thử file 5,000 từ xem biết được bao nhiêu từ :|. Tạm thời mình đang là Upper-Intermediate rùi...

Sáng dậy thì tớ ngồi lau cửa kính cho nhà dì tớ @@. Sợ thật lau tới 12 giờ trưa mà chưa xong cơ mà mẹ gọi ăn cơm với hái khế nên là T_T.

Chiều thì 2 giờ tớ với mẹ đi xe buýt về nhà. 4 giờ về tới nhà.

Tớ ngồi học tiếp cái QuerySet từ lúc 5 giờ 30 tới 7 giờ tối :-?

Ăn cơm xong lại ngồi vào học tiếp cái QuerySet từ 8 giờ 30 tối tới 9 giờ 30 tối rồi mẹ nhờ gõ văn bản.

Tổng cộng hôm qua thì 4 tiếng. Hôm nay thì 2 tiếng cho cái QuerySet này @@.

Tiếp tục về Python Django QuerySet

Hao thời gian phết nhưng mà vui @@.

Giờ chắc tớ sẽ chả cần mở SQLite3 ra để xem database có gì nữa mà sẽ python3 manage.py shell rồi dùng lệnh import collector help(collector.models) để từ đấy xem các biến có gì :|.

Thanks Quang nhiều về lệnh gọi cái shell kia hix. Cái shell ý giúp tớ tăng productivity lên nhiều lắm vì nói thật tớ thích dùng intepreter hơn là cứ viết file, sửa, save rồi compile, run @@.

Okay tiếp tục tìm hiểu thêm về Python Django shell nào.

Về hàm help

>>> help(help)

Help on _Helper in module _sitebuiltins object:

class _Helper(builtins.object)
 |  Define the builtin 'help'.
 |  
 |  This is a wrapper around pydoc.help that provides a helpful message
 |  when 'help' is typed at the Python interactive prompt.
 |  
 |  Calling help() at the Python prompt starts an interactive help session.
 |  Calling help(thing) prints help for the python object 'thing'.
 |  
 |  Methods defined here:
 |  
 |  __call__(self, *args, **kwds)
 |      Call self as a function.

Cách sử dụng hàm help trong Python intepreter.

i = 1

>>> help(int)

Help on int object:

class int(object)
 |  int(x=0) -> integer
 |  int(x, base=10) -> integer
 |  
 |  Convert a number or string to an integer, or return 0 if no arguments
 |  are given.  If x is a number, return x.__int__().  For floating point
 |  numbers, this truncates towards zero.
 |  

 |  __add__(self, value, /)
 |      Return self+value.
 |  
 |  __and__(self, value, /)
 |      Return self&value.
 |  
 |  __bool__(self, /)
 |      self != 0
 |  
 |  __ceil__(...)
 |      Ceiling of an Integral returns itself.
 |  
 |  __divmod__(self, value, /)
 |      Return divmod(self, value).
 |  
 |  __eq__(self, value, /)
 |      Return self==value.
 |  
 |  __float__(self, /)
 |      float(self)

Xem các hàm có sẵn của int class. Rất là hay ho luôn, nếu quên có thể vào đấy tham khảo O_O.

Để ý 1 chút là class int này kế thừa từ class object.

Cái này cũng giống như bên .NET thì object sẽ là abstract class cao nhất, mọi class đều kế thừa từ đấy T_T.

Ngôn ngữ Python hình như hướng đối tượng (OOP) từ lúc mới nghĩ ra. Cái này khác với cả C hồi đầu tiên hự hự.

>>> i.__eq__(5)
False
>>> i==5
False
>>> i.__eq__(1)
True
>>> i==1
True

Thử một vài hàm internal của class int và thấy là cũng ra kết quả như là mình dùng dấu == O_O.

Cái này cũng giống như là overloaded operator trong các kiểu hàm của class O_O.

 |  __new__(*args, **kwargs) from builtins.type
 |      Create and return a new object.  See help(type) for accurate signature.
 |  

Tớ thấy có cái này ở trong help(int) nên thử mò mẫm xem thế nào

>>> help(type)

Help on class type in module builtins:

class type(object)
 |  type(object_or_name, bases, dict)
 |  type(object) -> the object's type
 |  type(name, bases, dict) -> a new type
 |  
 |  Methods defined here:
 |  
 |  __call__(self, /, *args, **kwargs)
 |      Call self as a function.
 |  
 |  __delattr__(self, name, /)
 |      Implement delattr(self, name).
 |  

Hàm type() dùng để trả về định dạng của 1 biến.

>>> help(object)
Help on class object in module builtins:

class object
 |  The most base type

Class object là class tổ tiên của tất cả các built-in classes khác O_O.

>>> r=2.5
>>> help(r)

Help on float object:

class float(object)
 |  float(x) -> floating point number
 |  
 |  Convert a string or number to a floating point number, if possible.
 |  
 |  Methods defined here:
 |  

Thử 1 tính năng của hàm help().

Hàm help() có thể tự động tìm kiểu của biến r và đưa ra tài liệu cho biến ý.

Ở đây là kiểu float (số thực).

>>> help(i==1)

Help on bool object:

class bool(int)
 |  bool(x) -> bool
 |  
 |  Returns True when the argument x is true, False otherwise.
 |  The builtins True and False are the only two instances of the class bool.
 |  The class bool is a subclass of the class int, and cannot be subclassed.
 |  
 |  Method resolution order:
 |      bool
 |      int
 |      object

 |  Methods defined here:
 |  
 |  __and__(self, value, /)
 |      Return self&value.
 |  
 |  __new__(*args, **kwargs) from builtins.type
 |      Create and return a new object.  See help(type) for accurate signature.
 |  
 |  __or__(self, value, /)
 |      Return self|value.
 |  
 |  __rand__(self, value, /)
 |      Return value&self.
 |  
 |  __repr__(self, /)
 |      Return repr(self).

 |  ----------------------------------------------------------------------
 |  Methods inherited from int:
 |  
 |  __abs__(self, /)
 |      abs(self)
 |  
 |  __add__(self, value, /)
 |      Return self+value.
 |  
 |  __bool__(self, /)
 |      self != 0
 |  
 |  __ceil__(...)
 |      Ceiling of an Integral returns itself.

Thử tiếp xem hàm help() có nhận kiểu khác không :-?

Giá trị trả về của phép kiểm tra i==1bool. Vậy là nhận đúng rồi.

Chú ý ở đây class bool lại kế thừa từ class int.

Class int kế thừa từ class object.

Vậy là những methods (hàm) gì mà class int có thì hàm bool cũng có!!!

Kiểu bool thì chỉ có 2 giá trị là True và False thôi ^_^.

Kể ra kế thừa từ int cũng là hợp lý.

>>> s='kid'
>>> help(s)

No Python documentation found for 'kid'.
Use help() to get the interactive help utility.
Use help(str) for help on the str class.

Help on class str in module builtins:

class str(object)
 |  str(object='') -> str
 |  str(bytes_or_buffer[, encoding[, errors]]) -> str
 |  
 |  Create a new string object from the given object. If encoding or
 |  errors is specified, then the object must expose a data buffer
 |  that will be decoded using the given encoding and error handler.
 |  Otherwise, returns the result of object.__str__() (if defined)
 |  or repr(object).
 |  encoding defaults to sys.getdefaultencoding().
 |  errors defaults to 'strict'.
 |  
 |  Methods defined here:
 |  
 |  __add__(self, value, /)
 |      Return self+value.
 |  
 |  __contains__(self, key, /)
 |      Return key in self.
 |  

Thử xem Help cho String sẽ như thế nào O_O.

>>> sys.getdefaultencoding()
Traceback (most recent call last):
  File "<console>", line 1, in <module>
NameError: name 'sys' is not defined

>>> import sys

>>> sys.getdefaultencoding()
'utf-8'

Thử xem default encoding của String là gì đây.

Về Python built-in functions

Help on built-in module sys:

NAME
    sys

MODULE REFERENCE
    https://docs.python.org/3.6/library/sys

    The following documentation is automatically generated from the Python
    source files.  It may be incomplete, incorrect or include features that
    are considered implementation detail and may vary between Python
    implementations.  When in doubt, consult the module reference at the
    location listed above.

DESCRIPTION
    This module provides access to some objects used or maintained by the
    interpreter and to functions that interact strongly with the interpreter.

    Dynamic objects:

    argv -- command line arguments; argv[0] is the script pathname if known
    path -- module search path; path[0] is the script directory, else ''
    modules -- dictionary of loaded modules

    displayhook -- called to show results in an interactive session
    excepthook -- called to handle any uncaught exception other than SystemExit
      To customize printing in an interactive session or to install a custom
      top-level exception handler, assign other functions to replace these.
    stdin -- standard input file object; used by input()
    stdout -- standard output file object; used by print()
    stderr -- standard error object; used for error messages
      By assigning other file objects (or objects that behave like files)
      to these, it is possible to redirect all of the interpreter's I/O.

    argv = ['manage.py', 'shell']
    base_exec_prefix = '/usr'
    base_prefix = '/usr'
    builtin_module_names = ('_ast', '_bisect', '_blake2', '_codecs', '_col...
    byteorder = 'little'
    copyright = 'Copyright (c) 2001-2019 Python Software Foundati...ematis...
    dont_write_bytecode = False
    exec_prefix = '/home/ninehealth/work/moviegeek/venv_3.6.9'
    executable = '/home/ninehealth/work/moviegeek/venv_3.6.9/bin/python3'
    flags = sys.flags(debug=0, inspect=0, interactive=0, opt...ing=0, quie...
    float_info = sys.float_info(max=1.7976931348623157e+308, max_...epsilo...

    path_importer_cache = {'/home/ninehealth/work/moviegeek': FileFinder('...
    platform = 'linux'
    prefix = '/home/ninehealth/work/moviegeek/venv_3.6.9'
    ps1 = '>>> '
    ps2 = '... '
    stderr = <_io.TextIOWrapper name='<stderr>' mode='w' encoding='UTF-8'>
    stdin = <_io.TextIOWrapper name='<stdin>' mode='r' encoding='UTF-8'>
    stdout = <_io.TextIOWrapper name='<stdout>' mode='w' encoding='UTF-8'>
    thread_info = sys.thread_info(name='pthread', lock='semaphore', versio...
    version = '3.6.9 (default, Nov 25 2022, 14:10:45) \n[GCC 8.4.0]'
    version_info = sys.version_info(major=3, minor=6, micro=9, releaseleve...
    warnoptions = []

Tìm hiểu thêm module sys làm gì.

Ở đây có thể hiểu module chính là 1 file .py có nhiều class ở bên trong.

Module sys này tớ cũng thấy các file Python dùng nhiều :-?.

Đặc biệt ở đoạn cuối của phần help (ấn Shift + G, giống keyboard shortcut của less) có thể thấy là đường dẫn tuyệt đối tới folder moviegeek trong môi trường Python ảo T_T.

https://stackoverflow.com/questions/20651249/how-do-i-get-a-list-of-all-the-built-in-functions-in-python

Mò mẫm để tìm hiểu các built-in functions có sẵn lúc mà vừa mới mở Python ra...

>>> dir()
['__builtins__', 'i', 'r', 's', 'sys']

>>> dir(__builtins__)
['__class__', '__contains__', '__delattr__', '__delitem__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__getitem__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__iter__', '__le__', '__len__', '__lt__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__setitem__', '__sizeof__', '__str__', '__subclasshook__', 'clear', 'copy', 'fromkeys', 'get', 'items', 'keys', 'pop', 'popitem', 'setdefault', 'update', 'values']

Thử xem nào.

Có vẻ hàm dir() cũng hay cơ mà nhìn đau mắt quá @@.

Hàm dir() ý cũng hiện ra các biến tớ dùng là i, r, s và module sys được import.

>>> dir(int)
['__abs__', '__add__', '__and__', '__bool__', '__ceil__', '__class__', '__delattr__', '__dir__', '__divmod__', '__doc__', '__eq__', '__float__', '__floor__', '__floordiv__', '__format__', '__ge__', '__getattribute__', '__getnewargs__', '__gt__', '__hash__', '__index__', '__init__', '__init_subclass__', '__int__', '__invert__', '__le__', '__lshift__', '__lt__', '__mod__', '__mul__', '__ne__', '__neg__', '__new__', '__or__', '__pos__', '__pow__', '__radd__', '__rand__', '__rdivmod__', '__reduce__', '__reduce_ex__', '__repr__', '__rfloordiv__', '__rlshift__', '__rmod__', '__rmul__', '__ror__', '__round__', '__rpow__', '__rrshift__', '__rshift__', '__rsub__', '__rtruediv__', '__rxor__', '__setattr__', '__sizeof__', '__str__', '__sub__', '__subclasshook__', '__truediv__', '__trunc__', '__xor__', 'bit_length', 'conjugate', 'denominator', 'from_bytes', 'imag', 'numerator', 'real', 'to_bytes']

>>> dir(float)
['__abs__', '__add__', '__bool__', '__class__', '__delattr__', '__dir__', '__divmod__', '__doc__', '__eq__', '__float__', '__floordiv__', '__format__', '__ge__', '__getattribute__', '__getformat__', '__getnewargs__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__int__', '__le__', '__lt__', '__mod__', '__mul__', '__ne__', '__neg__', '__new__', '__pos__', '__pow__', '__radd__', '__rdivmod__', '__reduce__', '__reduce_ex__', '__repr__', '__rfloordiv__', '__rmod__', '__rmul__', '__round__', '__rpow__', '__rsub__', '__rtruediv__', '__setattr__', '__setformat__', '__sizeof__', '__str__', '__sub__', '__subclasshook__', '__truediv__', '__trunc__', 'as_integer_ratio', 'conjugate', 'fromhex', 'hex', 'imag', 'is_integer', 'real']

Thử xem class int có những hàm nào bên trong nào :-?

Có vẻ dir() list ra cũng đầy đủ đấy. Cho cả class float nữa.

Python Built-in Functions - W3Schools

https://www.w3schools.com/python/python_ref_functions.asp

1 link tham khảo khác về các hàm có sẵn trong Python.

>>> help(dir)
Help on built-in function dir in module builtins:

dir(...)
    dir([object]) -> list of strings

    If called without an argument, return the names in the current scope.
    Else, return an alphabetized list of names comprising (some of) the attributes
    of the given object, and of attributes reachable from it.
    If the object supplies a method named __dir__, it will be used; otherwise
    the default dir() logic is used and returns:
      for a module object: the module's attributes.
      for a class object:  its attributes, and recursively the attributes
        of its bases.
      for any other object: its attributes, its class's attributes, and
        recursively the attributes of its class's base classes.

Có thể thấy hàm dir() trả về rất nhiều thứ hay ho @@. Attributes ở đây dịch nôm là thuộc tính.

Nói thật tớ thấy từ attributes hơi sao sao, ở trên nhìn là hiện methods mà nhỉ T_T

Attributes là kiểu như members và data ý hix.

>>> help(builtins)

Help on built-in module builtins:

NAME
    builtins - Built-in functions, exceptions, and other objects.

DESCRIPTION
    Noteworthy: None is the `nil' object; Ellipsis represents `...' in slices.

CLASSES
    object
        BaseException
            Exception
                ArithmeticError
                    FloatingPointError
                    OverflowError
                    ZeroDivisionError
                AssertionError
                AttributeError
                BufferError
                EOFError
                ImportError

            KeyboardInterrupt
            SystemExit
        bytearray
        bytes
        classmethod
        complex
        dict
        enumerate
        filter
        float
        frozenset
        int
            bool
        list
        map
        memoryview
        property
        range
        reversed
        set
        slice
        staticmethod
        str
        super
        tuple
        type
        zip

FUNCTIONS
    __build_class__(...)
        __build_class__(func, name, *bases, metaclass=None, **kwds) -> class

        Internal helper function used by the class statement.

    __import__(...)
        __import__(name, globals=None, locals=None, fromlist=(), level=0) -> module

        Import a module. Because this function is meant for use by the Python
        interpreter and not for general use, it is better to use
        importlib.import_module() to programmatically import a module.

    delattr(obj, name, /)
        Deletes the named attribute from the given object.

        delattr(x, 'y') is equivalent to ``del x.y''

    dir(...)
        dir([object]) -> list of strings

    divmod(x, y, /)
        Return the tuple (x//y, x%y).  Invariant: div*y + mod == x.

DATA
    Ellipsis = Ellipsis
    False = False
    None = None
    NotImplemented = NotImplemented
    True = True
    __debug__ = True
    copyright = Copyright (c) 2001-2019 Python Software Foundati...ematisc...
    credits =     Thanks to CWI, CNRI, BeOpen.com, Zope Corpor...opment.  ...
    exit = Use exit() or Ctrl-D (i.e. EOF) to exit
    help = Type help() for interactive help, or help(object) for help abou...
    license = Type license() to see the full license text
    quit = Use quit() or Ctrl-D (i.e. EOF) to exit

FILE
    (built-in)

Và đây là các built-in classes tớ mong muốn xem đây.

Nhìn ở trên thấy class bool dịch vào bên trong 4 dấu cách vì được kế thừa từ class int.

Class object là cao nhất rùi @@. Class tổ tiên.

Ngoài class hay gặp ra như int, float, str, có thể thấy thêm dict, list, set, frozenset và rất nhiều class khác mà tớ cũng chưa bao giờ dùng!!!

Có cả các functions sẵn có lúc mà vừa mở Python luôn, có cả dir() kìa!

>>> import os
>>> dir()
['__builtins__', 'os']

>>> dir(os)
['CLD_CONTINUED', 'CLD_DUMPED', 'CLD_EXITED', 'CLD_TRAPPED', 'DirEntry', 'EX_CANTCREAT', 'EX_CONFIG', 'EX_DATAERR', 'EX_IOERR', 'EX_NOHOST', 'EX_NOINPUT', 'EX_NOPERM', 'EX_NOUSER', 'EX_OK', 'EX_OSERR', 'EX_OSFILE', 'EX_PROTOCOL', 'EX_SOFTWARE', 'EX_TEMPFAIL', 'EX_UNAVAILABLE', 'EX_USAGE', 'F_LOCK', 'F_OK', 'F_TEST', 'F_TLOCK', 'F_ULOCK', 'GRND_NONBLOCK', 'GRND_RANDOM', 'MutableMapping', 'NGROUPS_MAX', 'O_ACCMODE', 'O_APPEND', 'O_ASYNC', 'O_CLOEXEC', 'O_CREAT', 'O_DIRECT', 'O_DIRECTORY', 'O_DSYNC', 'O_EXCL', 'O_LARGEFILE', 'O_NDELAY', 'O_NOATIME', 'O_NOCTTY', 'O_NOFOLLOW', 'O_NONBLOCK', 'O_PATH', 'O_RDONLY', 'O_RDWR', 'O_RSYNC', 'O_SYNC', 'O_TMPFILE', 'O_TRUNC', 'O_WRONLY', 'POSIX_FADV_DONTNEED', 'POSIX_FADV_NOREUSE', 'POSIX_FADV_NORMAL', 'POSIX_FADV_RANDOM', 'POSIX_FADV_SEQUENTIAL', 'POSIX_FADV_WILLNEED', 'PRIO_PGRP', 'PRIO_PROCESS', 'PRIO_USER', 'P_ALL', 'P_NOWAIT', 'P_NOWAITO', 'P_PGID', 'P_PID', 'P_WAIT', 'PathLike', 'RTLD_DEEPBIND', 'RTLD_GLOBAL', 'RTLD_LAZY', 'RTLD_LOCAL', 'RTLD_NODELETE', 'RTLD_NOLOAD', 'RTLD_NOW', 'R_OK', 'SCHED_BATCH', 'SCHED_FIFO', 'SCHED_IDLE', 'SCHED_OTHER', 'SCHED_RESET_ON_FORK', 'SCHED_RR', 'SEEK_CUR', 'SEEK_DATA', 'SEEK_END', 'SEEK_HOLE', 'SEEK_SET', 'ST_APPEND', 'ST_MANDLOCK', 'ST_NOATIME', 'ST_NODEV', 'ST_NODIRATIME', 'ST_NOEXEC', 'ST_NOSUID', 'ST_RDONLY', 'ST_RELATIME', 'ST_SYNCHRONOUS', 'ST_WRITE', 'TMP_MAX', 'WCONTINUED', 'WCOREDUMP', 'WEXITED', 'WEXITSTATUS', 'WIFCONTINUED', 'WIFEXITED', 'WIFSIGNALED', 'WIFSTOPPED', 'WNOHANG', 'WNOWAIT', 'WSTOPPED', 'WSTOPSIG', 'WTERMSIG', 'WUNTRACED', 'W_OK', 'XATTR_CREATE', 'XATTR_REPLACE', 'XATTR_SIZE_MAX', 'X_OK', '_Environ', '__all__', '__builtins__', '__cached__', '__doc__', '__file__', '__loader__', '__name__', '__package__', '__spec__', '_execvpe', '_exists', '_exit', '_fspath', '_fwalk', '_get_exports_list', '_putenv', '_spawnvef', '_unsetenv', '_wrap_close', 'abc', 'abort', 'access', 'altsep', 'chdir', 'chmod', 'chown', 'ch

Thử tiếp thêm module OS có sẵn của Python nào.

Nhiều hàm ghê...

>>> help(os)

NAME
    os - OS routines for NT or Posix depending on what system we're on.

MODULE REFERENCE
    https://docs.python.org/3.6/library/os

DESCRIPTION
    This exports:
      - all functions from posix or nt, e.g. unlink, stat, etc.
      - os.path is either posixpath or ntpath
      - os.name is either 'posix' or 'nt'
      - os.curdir is a string representing the current directory (always '.')
      - os.pardir is a string representing the parent directory (always '..')

FILE
    /usr/lib/python3.6/os.py

Có thể thấy đường dẫn tới file chứ các hàm và class của module os.

-rwxr-xr-x  1 root root  93303 Nov 25 21:10 tarfile.py*
-rw-r--r--  1 root root  23136 Nov 25 21:10 telnetlib.py
-rw-r--r--  1 root root  31867 Nov 25 21:10 tempfile.py
-rw-r--r--  1 root root  19558 Nov 25 21:10 textwrap.py
-rw-r--r--  1 root root   1003 Nov 25 21:10 this.py
-rw-r--r--  1 root root  49029 Nov 25 21:10 threading.py
-rwxr-xr-x  1 root root  13332 Nov 25 21:10 timeit.py*
-rw-r--r--  1 root root   3075 Nov 25 21:10 token.py
-rw-r--r--  1 root root  29496 Nov 25 21:10 tokenize.py
-rwxr-xr-x  1 root root  28723 Nov 25 21:10 trace.py*
-rw-r--r--  1 root root  23458 Nov 25 21:10 traceback.py
-rw-r--r--  1 root root  16658 Nov 25 21:10 tracemalloc.py
-rw-r--r--  1 root root    879 Nov 25 21:10 tty.py
-rw-r--r--  1 root root 143620 Nov 25 21:10 turtle.py
-rw-r--r--  1 root root   8870 Nov 25 21:10 types.py
-rw-r--r--  1 root root  80274 Nov 25 21:10 typing.py
-rwxr-xr-x  1 root root   6753 Nov 25 21:10 uu.py*
-rw-r--r--  1 root root  23971 Nov 25 21:10 uuid.py
-rw-r--r--  1 root root  18488 Nov 25 21:10 warnings.py
-rw-r--r--  1 root root  17709 Nov 25 21:10 wave.py
-rw-r--r--  1 root root  20466 Nov 25 21:10 weakref.py
-rwxr-xr-x  1 root root  21757 Nov 25 21:10 webbrowser.py*
-rw-r--r--  1 root root   5913 Nov 25 21:10 xdrlib.py
-rw-r--r--  1 root root   7157 Nov 25 21:10 zipapp.py
-rw-r--r--  1 root root  76282 Nov 25 21:10 zipfile.py
ninehealth@LinuxVM15:~$ ll /usr/lib/python3.6/ | grep py

Thử mò lần 1.

ninehealth@LinuxVM15:~$ ll /usr/lib/python3.6/ | grep os
-rw-r--r--  1 root root  19119 Nov 25 21:10 _osx_support.py
-rw-r--r--  1 root root  37526 Nov 25 21:10 os.py
-rw-r--r--  1 root root  15772 Nov 25 21:10 posixpath.py

ninehealth@LinuxVM15:~$ ll /usr/lib/python3.6/ | grep sys
-rw-r--r--  1 root root  22325 Nov 25 21:10 _sysconfigdata_m_linux_x86_64-linux-gnu.py
-rw-r--r--  1 root root   4064 Nov 25 21:10 colorsys.py
-rw-r--r--  1 root root  25057 Nov 25 21:10 sysconfig.py

Thử mò lần 2.

>>> import sys
>>> help(sys)

    thread_info = sys.thread_info(name='pthread', lock='semaphore', versio...
    version = '3.6.9 (default, Nov 25 2022, 14:10:45) \n[GCC 8.4.0]'
    version_info = sys.version_info(major=3, minor=6, micro=9, releaseleve...
    warnoptions = []

DATA
    __stderr__ = <_io.TextIOWrapper name='<stderr>' mode='w' encoding='UTF...
    __stdin__ = <_io.TextIOWrapper name='<stdin>' mode='r' encoding='UTF-8...
    __stdout__ = <_io.TextIOWrapper name='<stdout>' mode='w' encoding='UTF...

FILE
    (built-in)

Không hiểu module sys.py ở đâu nữa...

>>> help(list)

Help on class list in module builtins:

class list(object)
 |  list() -> new empty list
 |  list(iterable) -> new list initialized from iterable's items
 |  
 |  Methods defined here:
 |  
 |  __add__(self, value, /)
 |      Return self+value.
 |  
 |  __contains__(self, key, /)
 |      Return key in self.
 |  

Tìm hiểu thêm về class list.

>>> help(dict)

Help on class dict in module builtins:

class dict(object)
 |  dict() -> new empty dictionary
 |  dict(mapping) -> new dictionary initialized from a mapping object's
 |      (key, value) pairs
 |  dict(iterable) -> new dictionary initialized as if via:
 |      d = {}
 |      for k, v in iterable:
 |          d[k] = v
 |  dict(**kwargs) -> new dictionary initialized with the name=value pairs
 |      in the keyword argument list.  For example:  dict(one=1, two=2)
 |  
 |  Methods defined here:
 |  
 |  __contains__(self, key, /)
 |      True if D has a key k, else False.

Tìm hiểu thêm về class dict.

>>> help(set)

Help on class set in module builtins:

class set(object)
 |  set() -> new empty set object
 |  set(iterable) -> new set object
 |  
 |  Build an unordered collection of unique elements.
 |  
 |  Methods defined here:
 |  
 |  __and__(self, value, /)
 |      Return self&value.
 |  
 |  __contains__(...)
 |      x.__contains__(y) <==> y in x.

Tìm hiểu thêm về class set.

Help on frozenset object:

class frozenset(object)
 |  frozenset() -> empty frozenset object
 |  frozenset(iterable) -> frozenset object
 |  
 |  Build an immutable unordered collection of unique elements.
 |  
 |  Methods defined here:
 |  
 |  __and__(self, value, /)
 |      Return self&value.
 |  
 |  __contains__(...)
 |      x.__contains__(y) <==> y in x.
 |  

Và class frozenset luôn...

Tìm hiểu về Python Django packages, modules, classes

>>> help("django")

Help on package django:

NAME
    django

PACKAGE CONTENTS
    __main__
    apps (package)
    conf (package)
    contrib (package)
    core (package)
    db (package)
    dispatch (package)
    forms (package)
    http (package)
    middleware (package)
    shortcuts
    template (package)
    templatetags (package)
    test (package)
    urls (package)
    utils (package)
    views (package)

FUNCTIONS
    setup(set_prefix=True)
FUNCTIONS
    setup(set_prefix=True)
        Configure the settings (this happens as a side effect of accessing the
        first setting), configure logging and populate the app registry.
        Set the thread-local urlresolvers script prefix if `set_prefix` is True.

DATA
    VERSION = (2, 2, 27, 'final', 0)

VERSION
    2.2.27

FILE
    /home/ninehealth/work/moviegeek/venv_3.6.9/lib/python3.6/site-packages/django/__init__.py

Chú ý ở đây trong hàm help() là phải để django trong dấu " ".

Django ở đây được gọi là 1 package.

Trong package Django có rất nhiều packages khác.

Help on package django.db in django:

NAME
    django.db

PACKAGE CONTENTS
    backends (package)
    migrations (package)
    models (package)
    transaction
    utils

Thử xem package Database của Django. Rất nhiều O_O.


Help on package django.db.models in django.db:

NAME
    django.db.models

PACKAGE CONTENTS
    aggregates
    base
    constants
    constraints
    deletion
    expressions
    fields (package)
    functions (package)
    indexes
    lookups
    manager
    options
    query
    query_utils
    signals
    sql (package)
    utils

Thử xem package Model trong Django Database package.

>>> help('django.db.models.query')

Help on module django.db.models.query in django.db.models:

NAME
    django.db.models.query - The main QuerySet implementation. This provides the public API for the ORM.

CLASSES
    builtins.object
        BaseIterable
            FlatValuesListIterable
            ModelIterable
            ValuesIterable
            ValuesListIterable
                NamedValuesListIterable
        EmptyQuerySet
        Prefetch
        QuerySet
        RawQuerySet
        RelatedPopulator
    builtins.type(builtins.object)
        InstanceCheckMeta

DATA
    CURSOR = 'cursor'
    DJANGO_VERSION_PICKLE_KEY = '_django_version'
    GET_ITERATOR_CHUNK_SIZE = 100
    LOOKUP_SEP = '__'
    REPR_OUTPUT_SIZE = 20
    connections = <django.db.utils.ConnectionHandler object>
    router = <django.db.utils.ConnectionRouter object>
    settings = <LazySettings "prs_project.settings">

FILE
    /home/ninehealth/work/moviegeek/venv_3.6.9/lib/python3.6/site-packages/django/db/models/query.py

Chà module query có vẻ hấp dẫn đây. Cái này chắc sẽ dùng nhiều. Xem thử nào.

django.db.models.query.QuerySet = class QuerySet(builtins.object)
 |  Represent a lazy database lookup for a set of objects.
 |  
 |  Methods defined here:
 |  
 |  __and__(self, other)
 |  
 |  __bool__(self)
 |  
 |  __deepcopy__(self, memo)
 |      Don't populate the QuerySet's cache.
 |  

 |  
 |  all(self)
 |      Return a new QuerySet that is a copy of the current one. This allows a
 |      QuerySet to proxy for a model manager in some cases.
 |  

 |  
 |  ----------------------------------------------------------------------
 |  Class methods defined here:
 |  
 |  as_manager() from builtins.type
 |  
 |  ----------------------------------------------------------------------
 |  Data descriptors defined here:
 |  
 |  __dict__
 |      dictionary for instance variables (if defined)
 |  
 |  __weakref__
 |      list of weak references to the object (if defined)
 |  
 |  db
 |      Return the database used if this query is executed now.
 |  
 |  ordered
 |      Return True if the QuerySet is ordered -- i.e. has an order_by()
 |      clause or a default ordering on the model (or is empty).

Tiếp tục xem class QuerySet trong class Query vì cái này có lẽ sẽ dùng nhiều đây O_O.

Vậy tóm tắt về các khái niệm trong Python là

Cách quản lý class, quản lý module và quản lý cao hơn nữa là packages rất khoa học luôn @@.

Khi mình gọi lệnh import thì có thể import bất cứ gì từ package tới module tới class luôn!!!

Class không chỉ có trong module mà có trong package cũng được!!!!

Về các Python apps (packages) trong PRS

>>> from django.db import models

>>> help(models.Model)

Help on class Model in module django.db.models.base:

class Model(builtins.object)
 |  Methods defined here:
 |  
 |  __eq__(self, other)
 |      Return self==value.
 |  
 |  __getstate__(self)
 |      Hook to allow choosing the attributes to pickle.
 |  
 |  __hash__(self)
 |      Return hash(self).
 |  

Bắt chước 1 lệnh hay có trong file models.py

Nhìn vào đây có thể hiểu là trong module django.db.models.base sẽ có class Model.

Class trong file models.py sẽ kế thừa từ class Model này.

>>> import collector
>>> help(collector)

Help on package collector:

NAME
    collector

PACKAGE CONTENTS
    apps
    migrations (package)
    models
    urls
    views

FILE
    /home/ninehealth/work/moviegeek/collector/__init__.py

Thử xem package collector được list ra như thế nào, có các modules gì...

>>> help(collector.models)
Help on module collector.models in collector:

NAME
    collector.models

CLASSES
    django.db.models.base.Model(builtins.object)
        Log

    class Log(django.db.models.base.Model)
     |  Log(id, created, user_id, content_id, event, session_id)
     |
     |  Method resolution order:
     |      Log
     |      django.db.models.base.Model
     |      builtins.object
     |
     |  Methods defined here:
     |
     |  __str__(self)
     |      Return str(self).
     |
     |  content_id = <django.db.models.query_utils.DeferredAttribute object>
     |  created = <django.db.models.query_utils.DeferredAttribute object>
     |  event = <django.db.models.query_utils.DeferredAttribute object>

Thử xem module models trong collector app (package) có gì.

Như thấy ở tren là có class Log được kế thừa từ django.db.models.base.Model

Có vẻ đúng đây.

>>> help('django.db.models.base')

Help on module django.db.models.base in django.db.models:

NAME
    django.db.models.base

CLASSES
    builtins.object
        Deferred
        Model
        ModelState
        ModelStateFieldsCacheDescriptor
    builtins.type(builtins.object)
        ModelBase

    class Deferred(builtins.object)
     |  Methods defined here:
     |  
     |  __repr__(self)
     |      Return repr(self).
     |  
     |  __str__(self)
     |      Return str(self).

Xem thử module django.db.models.base có những class gì.

Có class Model ở trong đấy rùi.

>>> help('django.db.models.base.Model')

Help on class Model in django.db.models.base:

django.db.models.base.Model = class Model(builtins.object)
 |  Methods defined here:
 |  
 |  __eq__(self, other)
 |      Return self==value.
 |  
 |  __getstate__(self)
 |      Hook to allow choosing the attributes to pickle.
 |  
 |  __hash__(self)
 |      Return hash(self).
 |  
 |  __init__(self, *args, **kwargs)
 |      Initialize self.  See help(type(self)) for accurate signature.
 |  

 |  clean(self)
 |      Hook for doing any extra model-wide validation after clean() has been
 |      called on every field by self.clean_fields. Any ValidationError raised
 |      by this method will not be associated with a particular field; it will
 |      have a special-case association with the field defined by NON_FIELD_ERRORS.
 |  

 |  
 |  save(self, force_insert=False, force_update=False, using=None, update_fields=None)
 |      Save the current instance. Override this in a subclass if you want to
 |      control the saving process.
 |      
 |      The 'force_insert' and 'force_update' parameters can be used to insist
 |      that the "save" must be an SQL insert or update (or equivalent for
 |      non-SQL backends), respectively. Normally, they should not be set.
 |  

Xem thử class Model có những hàm nào. Có hàm save cũng hay gặp O_O.

ninehealth@LinuxVM15:~/work/moviegeek$ less -SN venv_3.6.9/lib/python3.6/site-packages/django/db/models/base.py

    399 class Model(metaclass=ModelBase):
    400 
    401     def __init__(self, *args, **kwargs):
    402         # Alias some things as locals to avoid repeat global lookups
    403         cls = self.__class__
    404         opts = self._meta
    405         _setattr = setattr
    406         _DEFERRED = DEFERRED
    407 
    408         pre_init.send(sender=cls, args=args, kwargs=kwargs)
    409 
    410         # Set up the storage for instance state

Thử xem source code của module django.db.models.base

>>> help('django.db')

Help on package django.db in django:

NAME
    django.db

PACKAGE CONTENTS
    backends (package)
    migrations (package)
    models (package)
    transaction
    utils

CLASSES
    builtins.Exception(builtins.BaseException)
        django.db.utils.Error
            django.db.utils.DatabaseError
                django.db.utils.DataError
                django.db.utils.IntegrityError
                django.db.utils.InternalError
                django.db.utils.NotSupportedError
                django.db.utils.OperationalError
                django.db.utils.ProgrammingError
            django.db.utils.InterfaceError

    class DataError(DatabaseError)
     |  Common base class for all non-exit exceptions.
     |  
     |  Method resolution order:
     |      DataError
     |      DatabaseError

    class ProgrammingError(DatabaseError)
     |  Common base class for all non-exit exceptions.
     |  
     |  Method resolution order:
     |      ProgrammingError
     |      DatabaseError
     |      Error
     |      builtins.Exception
     |      builtins.BaseException
     |      builtins.object
     |  
     |  Data descriptors inherited from Error:
     |  
     |  __weakref__
     |      list of weak references to the object (if defined)

Xem thử phần Help của package django.db.

Có thể thấy trong Package cũng có Package và Classes!!!

Tìm hiểu thêm về các class liên quan tới QuerySet

>>> help(Log.objects)

Help on Manager in module django.db.models.manager object:

class Manager(BaseManagerFromQuerySet)
 |  Method resolution order:
 |      Manager
 |      BaseManagerFromQuerySet
 |      BaseManager
 |      builtins.object
 |  
 |  Data and other attributes defined here:
 |  
 |  __slotnames__ = []
 |  
 |  ----------------------------------------------------------------------
 |  Methods inherited from BaseManagerFromQuerySet:
 |  
 |  aggregate(self, *args, **kwargs)
 |      Return a dictionary containing the calculations (aggregation)
 |      over the current queryset.
 |      
 |      If args is present the expression is passed as a kwarg using
 |      the Aggregate object's default alias.
 |  

Có thể thấy mọi lần mình muốn dùng gì cho QuerySet là sẽ gõ Log.objects đầu tiên.

Nhìn ở đây có thể thấy Log.objects chính là Manager class trong module django.db.models.manager.

>>> help(Log)

Help on class Log in module collector.models:

class Log(django.db.models.base.Model)
 |  Log(id, created, user_id, content_id, event, session_id)
 |  
 |  Method resolution order:
 |      Log
 |      django.db.models.base.Model
 |      builtins.object
 |  
 |  Methods defined here:
 |  
 |  __str__(self)

 |  ----------------------------------------------------------------------
 |  Data and other attributes defined here:
 |  
 |  DoesNotExist = <class 'collector.models.Log.DoesNotExist'>
 |      The requested object does not exist
 |  
 |  MultipleObjectsReturned = <class 'collector.models.Log.MultipleObjects...
 |      The query returned multiple objects when only one was expected.
 |  
 |  objects = <django.db.models.manager.Manager object>

Có thể thấy objects được gán bằng django.db.models.manager.Manager trong phần help cho class Log kế thừa từ django.db.models.base.Model.

>>> help('django.db.models.manager')

Help on module django.db.models.manager in django.db.models:

NAME
    django.db.models.manager

CLASSES
    builtins.object
        BaseManager
        ManagerDescriptor
    BaseManagerFromQuerySet(BaseManager)
        Manager
            EmptyManager

    class BaseManager(builtins.object)
     |  Methods defined here:
     |  
     |  __eq__(self, other)
     |      Return self==value.
     |  
     |  __hash__(self)
     |      Return hash(self).
     |  

    class Manager(BaseManagerFromQuerySet)
     |  Method resolution order:
     |      Manager
     |      BaseManagerFromQuerySet
     |      BaseManager
     |      builtins.object
     |  
     |  Data and other attributes defined here:
     |  
     |  __slotnames__ = []
     |  
     |  ----------------------------------------------------------------------
     |  Methods inherited from BaseManagerFromQuerySet:
     |  
     |  aggregate(self, *args, **kwargs)
     |      Return a dictionary containing the calculations (aggregation)
     |      over the current queryset.
     |      
     |      If args is present the expression is passed as a kwarg using
     |      the Aggregate object's default alias.
     |  
     |  annotate(self, *args, **kwargs)
     |      Return a query set in which the returned objects have been annotated
     |      with extra data or aggregations.

Xem thử module django.db.models.manager chứa class Manager như thế nào.

Nhìn từ phần Help ở trên có thể thấy rằng class EmptyManager kế thừa từ class Manager.

Class BaseManagerFromQuerySet kế thừa từ class BaseManager tuy nhiên tự nhiên phàn indent của class BaseManagerFromQuerySet lại bị lùi ra ngoài 4 dấu cách.

Có thể hiểu rằng class Manager kế thừa từ class BaseManagerFromQuerySet.

Class BaseManagerFromQuerySet kế thừa từ class BaseManager.

Class BaseManager là class cao nhất trong module django.db.models.manager.

>>> help('django.db.models.manager.Manager')

Help on class Manager in django.db.models.manager:

django.db.models.manager.Manager = class Manager(BaseManagerFromQuerySet)
 |  Method resolution order:
 |      Manager
 |      BaseManagerFromQuerySet
 |      BaseManager
 |      builtins.object
 |  
 |  Data and other attributes defined here:
 |  
 |  __slotnames__ = []
 |  
 |  ----------------------------------------------------------------------
 |  Methods inherited from BaseManagerFromQuerySet:
 |  
 |  aggregate(self, *args, **kwargs)
 |      Return a dictionary containing the calculations (aggregation)
 |      over the current queryset.
 |      
 |      If args is present the expression is passed as a kwarg using
 |      the Aggregate object's default alias.

Xem thêm phần Help của class Manager.

>>> help('django.db.models.manager')

NAME
    django.db.models.manager

CLASSES

    builtins.object
        BaseManager
        ManagerDescriptor

    BaseManagerFromQuerySet(BaseManager)
        Manager
            EmptyManager

    class BaseManager(builtins.object)
     |  Methods defined here:
     |  
     |  __eq__(self, other)
     |      Return self==value.
     |  
     |  __hash__(self)

    class EmptyManager(Manager)
     |  Method resolution order:
     |      EmptyManager
     |      Manager
     |      BaseManagerFromQuerySet
     |      BaseManager
     |      builtins.object
     |  
     |  Methods defined here:
     |  

    class Manager(BaseManagerFromQuerySet)
     |  Method resolution order:
     |      Manager
     |      BaseManagerFromQuerySet
     |      BaseManager
     |      builtins.object
     |  
     |  Data and other attributes defined here:
     |  
     |  __slotnames__ = []

    class ManagerDescriptor(builtins.object)
     |  Methods defined here:
     |  
     |  __get__(self, instance, cls=None)
     |  
     |  __init__(self, manager)
     |      Initialize self.  See help(type(self)) for accurate signature.
     |  
     |  ----------------------------------------------------------------------
     |  Data descriptors defined here:
     |  
     |  __dict__
     |      dictionary for instance variables (if defined)
     |  
     |  __weakref__
     |      list of weak references to the object (if defined)

Tóm tắt phần Help của module django.db.models.manager.

ninehealth@LinuxVM15:~/work/moviegeek$ less -SN venv_3.6.9/lib/python3.6/site-packages/django/db/models/manager.py

      3 from importlib import import_module
      4 
      5 from django.db import router
      6 from django.db.models.query import QuerySet
      7 
      8 
      9 class BaseManager:
     10     # To retain order, track each time a Manager instance is created.
     11     creation_counter = 0
     12 
     13     # Set to True for the 'objects' managers that are automatically created.
     14     auto_created = False
     15 

    100     @classmethod
    101     def from_queryset(cls, queryset_class, class_name=None):
    102         if class_name is None:
    103             class_name = '%sFrom%s' % (cls.__name__, queryset_class.__name__)
    104         return type(class_name, (cls,), {
    105             '_queryset_class': queryset_class,
    106             **cls._get_queryset_methods(queryset_class),
    107         })
    108 

    164 
    165 class Manager(BaseManager.from_queryset(QuerySet)):
    166     pass
    167 

Xem source code của module django.db.models.manager.

Có thể thấy class Manager nội dung là pass. Tớ chưa hiểu lắm loại class này thế nào, chắc sẽ tìm hiểu sao hix.

Mà có 1 cái lạ là class thường kế thừa từ class mà class Manager này lại kế thừa từ hàm from_queryset() trong class BaseManager. Chắc cũng cần tìm hiểu thêm hix.

Thử QuerySet cho MovieGEEKs web app

>>> Log.objects.filter(user_id=3).values()
<QuerySet []>

>>> Log.objects.filter(user_id=4).values()
<QuerySet []>

>>> Log.objects.all.values()
Traceback (most recent call last):
  File "<console>", line 1, in <module>
AttributeError: 'function' object has no attribute 'values'

>>> Log.objects.all()

<QuerySet [<Log: user_id: 14271057339, content_id: 10121392, event: details>, <Log: user_id: 14271057339, content_id: 10121392, event: more_details>, <Log: user_id: 14271057339, content_id: 10121392, event: details>, <Log: user_id: 14271057339, content_id: 5618690, event: details>, <Log: user_id: 14271057339, content_id: 5537002, event: details>, <Log: user_id: 14271057339, content_id: 5537002, event: more_details>, <Log: user_id: 14271057339, content_id: 5537002, event: details>, <Log: user_id: 33606199645, content_id: 10152736, event: details>, <Log: user_id: 33606199645, content_id: 10380900, event: details>,

>>> Log.objects.all().values()

<QuerySet [{'id': 1, 'created': datetime.datetime(2022, 12, 14, 11, 37, 29, 805451), 'user_id': '14271057339', 'content_id': '10121392', 'event': 'details', 'session_id': 'ac631f04-7ba3-11ed-afd2-000d3a5a3fa5'}, {'id': 2, 'created': datetime.datetime(2022, 12, 14, 11, 37, 31, 753527), 'user_id': '14271057339', 'content_id': '10121392', 'event': 'more_details', 'session_id': 'ac631f04-7ba3-11ed-afd2-000d3a5a3fa5'}, {'id': 3, 'created': datetime.datetime(2022, 12, 14, 11, 37, 31, 756146), 'user_id': '14271057339', 'content_id': '10121392', 'event': 'details', 'session_id': 'ac631f04-7ba3-11ed-afd2-000d3a5a3fa5'}, {'id': 4, 'created': datetime.datetime(2022, 12, 14, 11, 40, 38, 408286), 'user_id': '14271057339', 'content_id': '5618690', 'event': 'details', 'session_id': 'ac631f04-7ba3-11ed-afd2-000d3a5a3fa5'}, {'id': 5, 'created': datetime.datetime(2022, 12, 14, 11, 44, 13, 825325),

Các lệnh trên tớ thử xem ra như thế nào.

ninehealth@LinuxVM15:~/work/moviegeek$ head -n 40 analytics/views.py 

def user(request, user_id):
    user_ratings = Rating.objects.filter(user_id=user_id).order_by('-rating')

    movies = Movie.objects.filter(movie_id__in=user_ratings.values('movie_id'))
    log = Log.objects.filter(user_id=user_id).order_by('-created').values()[:20]

    cluster = Cluster.objects.filter(user_id=user_id).first()
    ratings = {r.movie_id: r for r in user_ratings}

Đây là file tớ tham khảo :-?.

>>> Log.objects.all().filter(user_id=14271057339)

<QuerySet [<Log: user_id: 14271057339, content_id: 10121392, event: details>, <Log: user_id: 14271057339, content_id: 10121392, event: more_details>, <Log: user_id: 14271057339, content_id: 10121392, event: details>, <Log: user_id: 14271057339, content_id: 5618690, event: details>, <Log: user_id: 14271057339, content_id: 5537002, event: details>, <Log: user_id: 14271057339, content_id: 5537002, event: more_details>, <Log: user_id: 14271057339, content_id: 5537002, event: details>]>

>>> Log.objects.all().filter(user_id=14271057339).values()

<QuerySet [{'id': 1, 'created': datetime.datetime(2022, 12, 14, 11, 37, 29, 805451), 'user_id': '14271057339', 'content_id': '10121392', 'event': 'details', 'session_id': 'ac631f04-7ba3-11ed-afd2-000d3a5a3fa5'}, {'id': 2, 'created': datetime.datetime(2022, 12, 14, 11, 37, 31, 753527), 'user_id': '14271057339', 'content_id': '10121392', 'event': 'more_details', 'session_id': 'ac631f04-7ba3-11ed-afd2-000d3a5a3fa5'}, {'id': 3, 'created': datetime.datetime(2022, 12, 14, 11, 37, 31, 756146), 'user_id': '14271057339', 'content_id': '10121392', 'event': 'details', 'session_id': 'ac631f04-7ba3-11ed-afd2-000d3a5a3fa5'}, {'id': 4, 'created': datetime.datetime(2022, 12, 14, 11, 40, 38, 408286), 'user_id': '14271057339', 'content_id': '5618690', 'event': 'details', 'session_id': 'ac631f04-7ba3-11ed-afd2-000d3a5a3fa5'}, {'id': 5, 'created': datetime.datetime(2022, 12, 14, 11, 44, 13, 825325), 'user_id': '14271057339', 'content_id': '5537002', 'event': 'details', 'session_id': 'ac631f04-7ba3-11ed-afd2-000d3a5a3fa5'}, {'id': 6, 'created': datetime.datetime(2022, 12, 14, 11, 44, 15, 677044), 'user_id': '14271057339', 'content_id': '5537002', 'event': 'more_details', 'session_id': 'ac631f04-7ba3-11ed-afd2-000d3a5a3fa5'}, {'id': 7, 'created': datetime.datetime(2022, 12, 14, 11, 44, 15, 681723), 'user_id': '14271057339', 'content_id': '5537002', 'event': 'details', 'session_id': 'ac631f04-7ba3-11ed-afd2-000d3a5a3fa5'}]>

>>> Log.objects.all().filter(user_id=14271057339).values()[0]

{'id': 1, 'created': datetime.datetime(2022, 12, 14, 11, 37, 29, 805451), 'user_id': '14271057339', 'content_id': '10121392', 'event': 'details', 'session_id': 'ac631f04-7ba3-11ed-afd2-000d3a5a3fa5'}

>>> Log.objects.all().filter(user_id=14271057339).values()[:3]
<QuerySet [{'id': 1, 'created': datetime.datetime(2022, 12, 14, 11, 37, 29, 805451), 'user_id': '14271057339', 'content_id': '10121392', 'event': 'details', 'session_id': 'ac631f04-7ba3-11ed-afd2-000d3a5a3fa5'}, {'id': 2, 'created': datetime.datetime(2022, 12, 14, 11, 37, 31, 753527), 'user_id': '14271057339', 'content_id': '10121392', 'event': 'more_details', 'session_id': 'ac631f04-7ba3-11ed-afd2-000d3a5a3fa5'}, {'id': 3, 'created': datetime.datetime(2022, 12, 14, 11, 37, 31, 756146), 'user_id': '14271057339', 'content_id': '10121392', 'event': 'details', 'session_id': 'ac631f04-7ba3-11ed-afd2-000d3a5a3fa5'}]>

>>> Log.objects.all().filter(user_id=14271057339).values()[1]
{'id': 2, 'created': datetime.datetime(2022, 12, 14, 11, 37, 31, 753527), 'user_id': '14271057339', 'content_id': '10121392', 'event': 'more_details', 'session_id': 'ac631f04-7ba3-11ed-afd2-000d3a5a3fa5'}

>>> Log.objects.all().filter(user_id=14271057339).values()[:3][1]
{'id': 2, 'created': datetime.datetime(2022, 12, 14, 11, 37, 31, 753527), 'user_id': '14271057339', 'content_id': '10121392', 'event': 'more_details', 'session_id': 'ac631f04-7ba3-11ed-afd2-000d3a5a3fa5'}

>>> Log.objects.all().filter(user_id=14271057339).values()[2:5][1]
{'id': 4, 'created': datetime.datetime(2022, 12, 14, 11, 40, 38, 408286), 'user_id': '14271057339', 'content_id': '5618690', 'event': 'details', 'session_id': 'ac631f04-7ba3-11ed-afd2-000d3a5a3fa5'}

>>> Log.objects.all().filter(user_id=14271057339).values()[0]['event']
'details'

>>> Log.objects.filter(user_id=14271057339).values()[0]['event']
'details'

Thử 1 loạt các kiểu QuerySet khác nhau.

>>> Log.objects.count()
135

Thử hàm count() mà không có all() vẫn ra hết được kết quả @@. Ảo ghê.

>>> Log.objects.all()[134]
<Log: user_id: 88147736834, content_id: 12929990, event: details>

>>> Log.objects.all()[134].values
Traceback (most recent call last):
  File "<console>", line 1, in <module>
AttributeError: 'Log' object has no attribute 'values'

>>> Log.objects.all()[133]
<Log: user_id: 88147736834, content_id: 12929990, event: details>

>>> Log.objects.all()[0]
<Log: user_id: 14271057339, content_id: 10121392, event: details>

Thử lấy phần tử đầu và cuối ra.

>>> Log.objects.all().order_by('-id')

<QuerySet [<Log: user_id: 88147736834, content_id: 12929990, event: details>, <Log: user_id: 88147736834, content_id: 12929990, event: details>, <Log: user_id: 88147736834, content_id: 3228774, event: details>, <Log: user_id: 88147736834, content_id: 0, event: genre:Comedy>, <Log: user_id: 88147736834, content_id: 7230750, event: details>, <Log: user_id: 88147736834, content_id: 0, event: genre:Documentary>, <Log: user_id: 85329678214, content_id: 499097, event: more_details>, <Log: user_id: 85329678214, content_id: 499097, event:

>>> Log.objects.all().order_by('-id').values()
<QuerySet [{'id': 135, 'created': datetime.datetime(2023, 1, 2, 9, 30, 23, 624947), 'user_id': '88147736834', 'content_id': '12929990', 'event': 'details', 'session_id': '0082605a-8a80-11ed-9171-000d3a5a3fa5'}, {'id': 134, 'created': datetime.datetime(2023, 1, 2, 9, 30, 23, 626585), 'user_id': '88147736834', 'content_id': '12929990', 'event': 'details', 'session_id': '0082605a-8a80-11ed-9171-000d3a5a3fa5'}, {'id': 133, 'created': datetime.datetime(2023, 1, 2, 9, 30, 16, 154813), 'user_id': '88147736834', 'content_id': '3228774', 'event': 'details', 'session_id': '0082605a-8a80-11ed-9171-000d3a5a3fa5'}, {'id': 132, 'created': datetime.datetime(2023, 1, 2, 9, 30, 12, 930199), 'user_id': '88147736834', 'content_id': '0', 'event': 'genre:Comedy', 'session_id': '0082605a-8a80-11ed-9171-000d3a5a3fa5'}, {'id': 131, 'created': datetime.datetime(2023, 1, 2, 9, 30, 10, 801889), 'user_id': '88147736834', 'content_id': '7230750', 'event': 'details', 'session_id':

Thử hàm order_by() sắp xếp lại các phần tử hiển thị.

>>> Log.objects.all().order_by('-id').values('id')
<QuerySet [{'id': 135}, {'id': 134}, {'id': 133}, {'id': 132}, {'id': 131}, {'id': 130}, {'id': 129}, {'id': 128}, {'id': 127}, {'id': 126}, {'id': 125}, {'id': 124}, {'id': 123}, {'id': 122}, {'id': 121}, {'id': 120}, {'id': 119}, {'id': 118}, {'id': 117}, {'id': 116}, '...(remaining elements truncated)...']>

Sắp xếp các phần tử theo thứ tự giảm dần và chỉ hiển thị id thôi.

>>> Log.objects.all().order_by('-id').values('id')[4].values()
dict_values([131])

>>> Log.objects.all().order_by('-id').values('id')[:4].values()
<QuerySet [{'id': 135, 'created': datetime.datetime(2023, 1, 2, 9, 30, 23, 624947), 'user_id': '88147736834', 'content_id': '12929990', 'event': 'details', 'session_id': '0082605a-8a80-11ed-9171-000d3a5a3fa5'}, {'id': 134, 'created': datetime.datetime(2023, 1, 2, 9, 30, 23, 626585), 'user_id': '88147736834', 'content_id': '12929990', 'event': 'details', 'session_id': '0082605a-8a80-11ed-9171-000d3a5a3fa5'}, {'id': 133, 'created': datetime.datetime(2023, 1, 2, 9, 30, 16, 154813), 'user_id': '88147736834', 'content_id': '3228774', 'event': 'details', 'session_id': '0082605a-8a80-11ed-9171-000d3a5a3fa5'}, {'id': 132, 'created': datetime.datetime(2023, 1, 2, 9, 30, 12, 930199), 'user_id': '88147736834', 'content_id': '0', 'event': 'genre:Comedy', 'session_id': '0082605a-8a80-11ed-9171-000d3a5a3fa5'}]>

Hiển thị 4 phần tử cuối cùng.

>>> from moviegeeks.models import Movie,Genre

>>> help(moviegeeks)
Traceback (most recent call last):
  File "<console>", line 1, in <module>
NameError: name 'moviegeeks' is not defined

>>> help('moviegeeks')

Help on package moviegeeks:

NAME
    moviegeeks

PACKAGE CONTENTS
    admin
    apps
    models
    tests
    urls
    views

FILE
    /home/ninehealth/work/moviegeek/moviegeeks/__init__.py

Thử import moviegeeks app (package).

>>> help('moviegeeks.models')

Help on module moviegeeks.models in moviegeeks:

NAME
    moviegeeks.models

CLASSES
    django.db.models.base.Model(builtins.object)
        Genre
        Movie

    class Genre(django.db.models.base.Model)
     |  Genre(id, name)
     |  
     |  Method resolution order:
     |      Genre
     |      django.db.models.base.Model
     |      builtins.object
     |  
     |  Methods defined here:
     |  
     |  __str__(self)
     |      Return str(self).

    class Movie(django.db.models.base.Model)
     |  Movie(movie_id, title, year)
     |  
     |  Method resolution order:
     |      Movie
     |      django.db.models.base.Model
     |      builtins.object
     |  
     |  Methods defined here:
     |  
     |  __str__(self)
     |      Return str(self).
     |  

Xem thử các class có trong module moviegeeks.model trong package (app) moviegeeks.

Có 2 class là GenreMovie.

>>> Movie.objects.count()
38018

>>> Genre.objects.count()
28

Hiển thị số lượng movies và genres (thể loại phim).

>>> Genre.objects.values()

<QuerySet [{'id': 1, 'name': 'Documentary'}, {'id': 2, 'name': 'Short'}, {'id': 3, 'name': 'Horror'}, {'id': 4, 'name': 'Comedy'}, {'id': 5, 'name': 'Action'}, {'id': 6, 'name': 'Adventure'}, {'id': 7, 'name': 'Fantasy'}, {'id': 8, 'name': 'Sci-Fi'}, {'id': 9, 'name': 'Crime'}, {'id': 10, 'name': 'Western'}, {'id': 11, 'name': 'Drama'}, {'id': 12, 'name': 'Romance'}, {'id': 13, 'name': 'History'}, {'id': 14, 'name': 'Family'}, {'id': 15, 'name': 'War'}, {'id': 16, 'name': 'Sport'}, {'id': 17, 'name': 'Biography'}, {'id': 18, 'name': 'Mystery'}, {'id': 19, 'name': 'Thriller'}, {'id': 20, 'name': 'Animation'}, '...(remaining elements truncated)...']>

Hiển thị các thể loại.

>>> Movie.objects.values().order_by('-year')

<QuerySet [{'movie_id': '0293429', 'title': 'Mortal Kombat ', 'year': 2021}, {'movie_id': '0499097', 'title': 'Tom Clancy&x27;s Without Remorse ', 'year': 2021}, {'movie_id': '0870154', 'title': 'Jungle Cruise ', 'year': 2021}, {'movie_id': '0993840', 'title': 'Army of the Dead ', 'year': 2021}, {'movie_id': '1160419', 'title': 'Dune: Part One ', 'year': 2021}, {'movie_id': '1321510', 'title': 'In the Heights ', 'year': 2021}, {'movie_id': '01361336', 'title': 'Tom and Jerry ', 'year': 2021}, {'movie_id': '1361336', 'title': 'Tom and Jerry ', 'year': 2021}, {'movie_id': '1461238', 'title': 'Kurt Vonnegut: Unstuck in Time ', 'year': 2021}, {'movie_id': '1697800', 'title': 'Die in a Gunfight ', 'year': 2021}, {'movie_id': '1893273', 'title': 'The Last Letter from Your Lover ', 'year': 2021}, {'movie_id': '1924245', 'title': 'Cry Macho ', 'year': 2021}, {'movie_id': '2076822', 'title': 'Chaos Walking ', 'year': 2021}, {'movie_id': '2231874', 'title': 'You Belong to Me ', 'year': 2021}, {'movie_id': '2304637', 'title': 'Flag Day ', 'year': 2021}, {'movie_id': '2382320', 'title': 'No Time to Die ', 'year': 2021}, {'movie_id': '2397461', 'title': 'Clifford the Big Red Dog ', 'year': 2021}, {'movie_id': '2401814', 'title': 'The Loneliest Whale: The Search for 52 ', 'year': 2021}, {'movie_id': '2452150', 'title': 'Respect ', 'year': 2021}, {'movie_id': '2458948', 'title': 'Shin Evangelion Gekijôban ', 'year': 2021}, '...(remaining elements truncated)...']>

Hiển thị các phim mới nhất theo năm.

>>> Movie.objects.filter(movie_id='0293429').values()
<QuerySet [{'movie_id': '0293429', 'title': 'Mortal Kombat ', 'year': 2021}]>

Hiển thị nội dung phim Mortal Kombat.

Chú ý không còn dùng hàm all() nữa @@.

>>> Movie.objects.filter(movie_id='0293429')[0]
<Movie: Mortal Kombat >

Lấy phần tử đầu tiên ra.

>>> Movie.objects.filter(movie_id='0293429')[0].genres

<django.db.models.fields.related_descriptors.create_forward_many_to_many_manager.<locals>.ManyRelatedManager object at 0x7fe57cc03240>

Thử xem các thể loại của phim đấy.

>>> Movie.objects.filter(movie_id='0293429')[0].genres.values()
<QuerySet [{'id': 5, 'name': 'Action'}, {'id': 6, 'name': 'Adventure'}, {'id': 7, 'name': 'Fantasy'}, {'id': 8, 'name': 'Sci-Fi'}, {'id': 19, 'name': 'Thriller'}]>

Giờ mới hiển thị đúng.

>>> Movie.objects.filter(movie_id='0293429')[0].genres.values('name')
<QuerySet [{'name': 'Action'}, {'name': 'Adventure'}, {'name': 'Fantasy'}, {'name': 'Sci-Fi'}, {'name': 'Thriller'}]>

Chỉ hiện thị tên.

https://github.com/9health/moviegeek/blob/master/moviegeeks/models.py

class Genre(models.Model):
    name = models.CharField(max_length=64)

    def __str__(self):
        return self.name

class Movie(models.Model):
    movie_id = models.CharField(max_length=16, unique=True, primary_key=True)
    title = models.CharField(max_length=512)
    year = models.IntegerField(null=True)
    genres = models.ManyToManyField(Genre, related_name='movies', db_table='movie_genre')

    def __str__(self):
        return self.title

Chú ý ở đây là 2 tables này cũng khai báo trong 1 app.

Và có 1 bảng tham chiếu theo kiểu ManyToManyField.

Nếu viết SQL để hiển thị tên của các thể loại kia rất phức tạp.

Có lẽ cần join 2 bảng đấy!!!

Giờ chỉ cần 1 câu lệnh QuerySet là xong!!

Rất là tiện!!!

Thử tính năng annotateCount trong QuerySet

ninehealth@LinuxVM15:~/work/moviegeek$ nl analytics/views.py 

    63  def content(request, content_id):
    64      print(content_id)
    65      movie = Movie.objects.filter(movie_id=content_id).first()
    66      user_ratings = Rating.objects.filter(movie_id=content_id)
    67      ratings = user_ratings.values('rating')
    68      logs = Log.objects.filter(content_id=content_id).order_by('-created').values()[:20]
    69      association_rules = SeededRecs.objects.filter(source=content_id).values('target', 'type')

    70      print(content_id, " rat:", ratings)

    71      movie_title = 'No Title'   
    72      agv_rating = 0
    73      genre_names = []
    74      if movie is not None:
    75          movie_genres = movie.genres.all() if movie is not None else []
    76          genre_names = list(movie_genres.values('name'))

    77          ratings = list(r['rating'] for r in ratings)
    78          agv_rating = sum(ratings)/len(ratings)
    79          movie_title = movie.title

Code tớ tham khảo để viết QuerySet.

 |
 |
 |  annotate(self, *args, **kwargs)
 |      Return a query set in which the returned objects have been annotated
 |      with extra data or aggregations.

Có 1 hàm rất hay trong QuerySet là annotate().

   146  def clusters(request):

   147      clusters_w_membercount = (Cluster.objects.values('cluster_id')
   148                                .annotate(member_count=Count('user_id'))
   149                                .order_by('cluster_id'))

Và được dùng ở đây.

>>> Movie.objects.filter(movie_id='0293429')[0].genres.values('name').annotate(genres_count=Count('name'))
Traceback (most recent call last):
  File "<console>", line 1, in <module>
NameError: name 'Count' is not defined

>>> from django.db.models import Count

>>> help(Count)

Help on class Count in module django.db.models.aggregates:

class Count(Aggregate)
 |  An SQL function call.
 |  
 |  Method resolution order:
 |      Count
 |      Aggregate
 |      django.db.models.expressions.Func
 |      django.db.models.expressions.SQLiteNumericMixin
 |      django.db.models.expressions.Expression
 |      django.db.models.expressions.BaseExpression
 |      django.db.models.expressions.Combinable
 |      builtins.object
 |  
 |  Methods defined here:
 |  
 |  __init__(self, expression, filter=None, **extra)
 |      Initialize self.  See help(type(self)) for accurate signature.
 |  
 |  convert_value(self, value, expression, connection)
 |      Expressions provide their own converters because users have the option
 |      of manually specifying the output_field which may be a different type
 |      from the one the database returns.

Lần đầu dùng hàm Count mà không được.

Chà do chưa import đây.

>>> Movie.objects.filter(movie_id='0293429')[0].genres.values().annotate(genres_count=Count('name'))
<QuerySet [{'id': 5, 'name': 'Action', 'genres_count': 1}, {'id': 6, 'name': 'Adventure', 'genres_count': 1
}, {'id': 7, 'name': 'Fantasy', 'genres_count': 1}, {'id': 8, 'name': 'Sci-Fi', 'genres_count': 1}, {'id': 19, 'name': 'Thriller', 'genres_count': 1}]>

Lần đầu viết chưa đúng lắm.

>>> Movie.objects.filter(movie_id='0293429').values().annotate(genres_count=Count('genres'))
<QuerySet [{'movie_id': '0293429', 'title': 'Mortal Kombat ', 'year': 2021, 'genres_count': 5}]>

>>> Movie.objects.filter(movie_id='0293429')[0].genres.values('name')
<QuerySet [{'name': 'Action'}, {'name': 'Adventure'}, {'name': 'Fantasy'}, {'name': 'Sci-Fi'}, {'name': 'Thriller'}]>

Viết lại nào. Đúng là phim Mortal Kombat có 5 thể loại thật!!!

Thử tính năng __in__contains trong QuerySet

https://docs.djangoproject.com/en/4.1/ref/models/querysets/

in

In a given iterable; often a list, tuple, or queryset. It’s not a common use case, but strings (being iterables) are accepted.

Examples:

Entry.objects.filter(id__in=[1, 3, 4])
Entry.objects.filter(headline__in='abc')
SQL equivalents:

SELECT ... WHERE id IN (1, 3, 4);
SELECT ... WHERE headline IN ('a', 'b', 'c');

You can also use a queryset to dynamically evaluate the list of values instead of providing a list of literal values:

inner_qs = Blog.objects.filter(name__contains='Cheddar')
entries = Entry.objects.filter(blog__in=inner_qs)
This queryset will be evaluated as subselect statement:

SELECT ... WHERE blog.id IN (SELECT id FROM ... WHERE NAME LIKE '%Cheddar%')

Còn 1 tính năng nữa hồi trước tớ đọc trên trang tài liệu Django là hàm __in

Quên mất thuật ngữ là gì rồi =.=

Có thể hiểu in ở đây nghĩa là ở trong 1 list.

Thay vì mình dùng 3 câu lệnh select từng id thì có thể select cả 3 id đấy cùng 1 lúc luôn!!!

>>> Movie.objects.filter(movie_id__in='0000008')
<QuerySet []>

>>> Movie.objects.filter(movie_id__in='0000008').values()
<QuerySet []>

>>> Movie.objects.filter(movie_id='0000008').values()
<QuerySet [{'movie_id': '0000008', 'title': 'Edison Kinetoscopic Record of a Sneeze ', 'year': 1894}]>

>>> Movie.objects.filter(movie_id__in=['0000008']).values()
<QuerySet [{'movie_id': '0000008', 'title': 'Edison Kinetoscopic Record of a Sneeze ', 'year': 1894}]>

Thử mãi mới đúng!!!

>>> Movie.objects.filter(movie_id__contains='0000008').values()
<QuerySet [{'movie_id': '0000008', 'title': 'Edison Kinetoscopic Record of a Sneeze ', 'year': 1894}]>

Thử kiểu khác nào!

Thử hàm count() trong QuerySet

>>> Log.objects.filter(event='buy').values()
<QuerySet [{'id': 22, 'created': datetime.datetime(2022, 12, 15, 9, 34, 29, 584766), 'user_id': '33606199645', 'content_id': '10295212', 'event': 'buy', 'session_id': '87524f50-7ba8-11ed-afd2-000d3a5a3fa5'}, {'id': 23, 'created': datetime.datetime(2022, 12, 15, 9, 34, 32, 93424), 'user_id': '33606199645', 'content_id': '10295212', 'event': 'buy', 'session_id': '87524f50-7ba8-11ed-afd2-000d3a5a3fa5'}, {'id': 56, 'created': datetime.datetime(2022, 12, 15, 15, 33, 51, 35223), 'user_id': '33606199645', 'content_id': '10329614', 'event': 'buy', 'session_id': '87524f50-7ba8-11ed-afd2-000d3a5a3fa5'}, {'id': 61, 'created': datetime.datetime(2022, 12, 15, 15, 34, 13, 231585), 'user_id': '33606199645', 'content_id': '4876134', 'event': 'buy', 'session_id': '87524f50-7ba8-11ed-afd2-000d3a5a3fa5'}, {'id': 68, 'created': datetime.datetime(2022, 12, 15, 15, 34, 31, 642053), 'user_id': '33606199645', 'content_id': '13863968', 'event': 'buy', 'session_id': '87524f50-7ba8-11ed-afd2-000d3a5a3fa5'}, {'id': 101, 'created': datetime.datetime(2022, 12, 21, 0, 32, 46, 135319), 'user_id': '68159542309', 'content_id': '3480822', 'event': 'buy', 'session_id': '6079aab2-80bd-11ed-916f-000d3a5a3fa5'}, {'id': 117, 'created': datetime.datetime(2022, 12, 21, 10, 46, 57, 702927), 'user_id': '33606199645', 'content_id': '0993840', 'event': 'buy', 'session_id': '87524f50-7ba8-11ed-afd2-000d3a5a3fa5'}, {'id': 124, 'created': datetime.datetime(2022, 12, 22, 0, 31, 38, 171056), 'user_id': '85913049150', 'content_id': '3110958', 'event': 'buy', 'session_id': 'c48da1d4-818a-11ed-9170-000d3a5a3fa5'}]>

>>> Log.objects.filter(event='buy').count()
8

Thử hàm count() nào.

>>> Log.objects.values('id')

<QuerySet [{'id': 1}, {'id': 2}, {'id': 3}, {'id': 4}, {'id': 5}, {'id': 6}, {'id': 7}, {'id': 8}, {'id': 9}, {'id': 10}, {'id': 11}, {'id': 12}, {'id': 13}, {'id': 14}, {'id': 15}, {'id': 16}, {'id': 17}, {'id': 18}, {'id': 19}, {'id': 20}, '...(remaining elements truncated)...']>
>>> Log.objects.filter(user_id=33606199645).values()
<QuerySet [{'id': 8, 'created': datetime.datetime(2022, 12, 14, 12, 12, 19, 562973), 'user_id': '33606199645', 'content_id': '10152736', 'event': 'details', 'session_id': '87524f50-7ba8-11ed-afd2-000d3a5a3fa5'}, {'id': 9, 'created': datetime.datetime(2022, 12, 14, 12, 29, 42, 83685), 'user_id': '33606199645', 'content_id': '10380900', 'event': 'details', 'session_id': '87524f50-7ba8-11ed-afd2-000d3a5a3fa5'}, {'id': 10, 'created': datetime.datetime(2022, 12, 14, 12, 29, 45, 168987), 'user_id': '33606199645', 'content_id': '10380900', 'event': 'more_details', 'session_id': '87524f50-7ba8-11ed-afd2-000d3a5a3fa5'}, {'id': 11, 'created': datetime.datetime(2022, 12, 14, 12, 29, 59, 70184), 'user_id': '33606199645', 'content_id': '0', 'event': 'genre:War', 'session_id': '87524f50-7ba8-11ed-afd2-000d3a5a3fa5'}, {'id': 17, 'created': datetime.datetime(2022, 12, 15, 9, 34, 21, 84396), 'user_id': '33606199645', 'content_id': '10295212', 'event': 'details', 'session_id': '87524f50-7ba8-11ed-afd2-000d3a5a3fa5'}, {'id': 18, 'created': datetime.datetime(2022, 12, 15, 9, 34, 22, 894147), 'user_id': '33606199645', 'content_id': '10295212', 'event': 'details', 'session_id': '87524f50-7ba8-11ed-afd2-000d3a5a3fa5'}, {'id': 19, 'created': datetime.datetime(2022, 12, 15, 9, 34, 23, 45283), 'user_id': '33606199645', 'content_id': '10295212', 'event': 'details', 'session_id': '87524f50-7ba8-11ed-afd2-000d3a5a3fa5'}, {'id': 20, 'created': datetime.datetime(2022, 12, 15, 9, 34, 25, 745549), 'user_id': '33606199645', 'content_id': '10295212', 'event': 'details', 'session_id': '87524f50-7ba8-11ed-afd2-000d3a5a3fa5'}, {'id': 21, 'created': datetime.datetime(2022, 12, 15, 9, 34, 25, 747984), 'user_id': '33606199645', 'content_id': '10295212', 'event': 'more_details', 'session_id': '87524f50-7ba8-11ed-afd2-000d3a5a3fa5'}, {'id': 22, 'created': datetime.datetime(2022, 12, 15, 9, 34, 29, 584766), 'user_id': '33606199645', 'content_id': '10295212', 'event': 'buy', 'session_id': '87524f50-7ba8-11ed-afd2-000d3a5a3fa5'}, {'id': 23, 'created': datetime.datetime(2022, 12, 15, 9, 34, 32, 93424), 'user_id': '33606199645', 'content_id': '10295212', 'event': 'buy', 'session_id': '87524f50-7ba8-11ed-afd2-000d3a5a3fa5'}, {'id': 24, 'created': datetime.datetime(2022, 12, 15, 9, 34, 39, 625456), 'user_id': '33606199645', 'content_id': '0', 'event': 'genre:Music', 'session_id': '87524f50-7ba8-11ed-afd2-000d3a5a3fa5'}, {'id': 35, 'created': datetime.datetime(2022, 12, 15, 9, 57, 3, 980100), 'user_id': '33606199645', 'content_id': '5452210', 'event': 'details', 'session_id': '87524f50-7ba8-11ed-afd2-000d3a5a3fa5'}, {'id': 36, 'created': datetime.datetime(2022, 12, 15, 9, 57, 4, 153883), 'user_id': '33606199645', 'content_id': '5452210', 'event': 'details', 'session_id': '87524f50-7ba8-11ed-afd2-000d3a5a3fa5'}, {'id': 37, 'created': datetime.datetime(2022, 12, 15, 9, 57, 6, 197513), 'user_id': '33606199645', 'content_id': '0', 'event': 'genre:Comedy', 'session_id': '87524f50-7ba8-11ed-afd2-000d3a5a3fa5'}, {'id': 47, 'created': datetime.datetime(2022, 12, 15, 15, 33, 39, 103528), 'user_id': '33606199645', 'content_id': '10329614', 'event': 'details', 'session_id': '87524f50-7ba8-11ed-afd2-000d3a5a3fa5'}, {'id': 48, 'created': datetime.datetime(2022, 12, 15, 15, 33, 41, 352348), 'user_id': '33606199645', 'content_id': '10329614', 'event': 'save_for_later', 'session_id': '87524f50-7ba8-11ed-afd2-000d3a5a3fa5'}, {'id': 49, 'created': datetime.datetime(2022, 12, 15, 15, 33, 41, 361762), 'user_id': '33606199645', 'content_id': '10329614', 'event': 'details', 'session_id': '87524f50-7ba8-11ed-afd2-000d3a5a3fa5'}, {'id': 50, 'created': datetime.datetime(2022, 12, 15, 15, 33, 43, 537681), 'user_id': '33606199645', 'content_id': '10329614', 'event': 'save_for_later', 'session_id': '87524f50-7ba8-11ed-afd2-000d3a5a3fa5'}, {'id': 51, 'created': datetime.datetime(2022, 12, 15, 15, 33, 43, 578694), 'user_id': '33606199645', 'content_id': '10329614', 'event': 'details', 'session_id': '87524f50-7ba8-11ed-afd2-000d3a5a3fa5'}, '...(remaining elements truncated)...']>

>>> Log.objects.filter(user_id=33606199645).values().count()
57

Thử count xem user trên có bao nhiêu rows trong database.

Thử hàm distinct() trong QuerySet

>>> Log.objects.filter(user_id=33606199645).values('session_id')
<QuerySet [{'session_id': '87524f50-7ba8-11ed-afd2-000d3a5a3fa5'}, {'session_id': '87524f50-7ba8-11ed-afd2-000d3a5a3fa5'}, {'session_id': '87524f50-7ba8-11ed-afd2-000d3a5a3fa5'}, {'session_id': '87524f50-7ba8-11ed-afd2-000d3a5a3fa5'}, {'session_id': '87524f50-7ba8-11ed-afd2-000d3a5a3fa5'}, {'session_id': '87524f50-7ba8-11ed-afd2-000d3a5a3fa5'}, {'session_id': '87524f50-7ba8-11ed-afd2-000d3a5a3fa5'}, {'session_id': '87524f50-7ba8-11ed-afd2-000d3a5a3fa5'}, {'session_id': '87524f50-7ba8-11ed-afd2-000d3a5a3fa5'}, {'session_id': '87524f50-7ba8-11ed-afd2-000d3a5a3fa5'}, {'session_id': '87524f50-7ba8-11ed-afd2-000d3a5a3fa5'}, {'session_id': '87524f50-7ba8-11ed-afd2-000d3a5a3fa5'}, {'session_id': '87524f50-7ba8-11ed-afd2-000d3a5a3fa5'}, {'session_id': '87524f50-7ba8-11ed-afd2-000d3a5a3fa5'}, {'session_id': '87524f50-7ba8-11ed-afd2-000d3a5a3fa5'}, {'session_id': '87524f50-7ba8-11ed-afd2-000d3a5a3fa5'}, {'session_id': '87524f50-7ba8-11ed-afd2-000d3a5a3fa5'}, {'session_id': '87524f50-7ba8-11ed-afd2-000d3a5a3fa5'}, {'session_id': '87524f50-7ba8-11ed-afd2-000d3a5a3fa5'}, {'session_id': '87524f50-7ba8-11ed-afd2-000d3a5a3fa5'}, '...(remaining elements truncated)...']>

>>> Log.objects.filter(user_id=33606199645).values('session_id').distinct()
<QuerySet [{'session_id': '87524f50-7ba8-11ed-afd2-000d3a5a3fa5'}]>

Thử xem tổng cộng có bao nhiêu session từ khi bật MovieGeeks web app.

https://docs.djangoproject.com/en/4.1/ref/models/querysets/

1 link tham khảo nữa về QuerySet

>>> from datetime import date

>>> Log.objects.filter(created__contains=date(2022,12,15)).values()

<QuerySet [{'id': 12, 'created': datetime.datetime(2022, 12, 15, 9, 30, 35, 189061), 'user_id': '69551453075', 'content_id': '10290352', 'event': 'details', 'session_id': '039060a4-7c5b-11ed-96c7-000d3a5a3fa5'}, {'id': 13, 'created': datetime.datetime(2022, 12, 15, 9, 30, 39, 543351), 'user_id': '69551453075', 'content_id': '0', 'event': 'genre:Short', 'session_id': '039060a4-7c5b-11ed-96c7-000d3a5a3fa5'}, {'id': 14, 'created': datetime.datetime(2022, 12, 15, 9, 30, 44, 801273), 'user_id': '69551453075', 'content_id': '0', 'event': 'genre:Short', 'session_id': '039060a4-7c5b-11ed-96c7-000d3a5a3fa5'}, {'id': 15, 'created': datetime.datetime(2022, 12, 15, 9, 30, 47, 330768), 'user_id': '69551453075', 'content_id': '0', 'event': 'genre:Comedy', 'session_id': '039060a4-7c5b-11ed-96c7-000d3a5a3fa5'}, {'id': 16, 'created': datetime.datetime(2022, 12, 15, 9, 30, 50, 816048), 'user_id': '69551453075', 'content_id': '5164438', 'event': 'details', 'session_id': '039060a4-7c5b-11ed-96c7-000d3a5a3fa5'}, {'id': 17, 'created': datetime.datetime(2022, 12, 15, 9, 34, 21, 84396), 'user_id': '33606199645', 'content_id': '10295212', 'event': 'details', 'session_id': '87524f50-7ba8-11ed-afd2-000d3a5a3fa5'}, {'id': 18, 'created': datetime.datetime(2022, 12, 15, 9, 34, 22, 894147), 'user_id': '33606199645', 'content_id': '10295212', 'event': 'details', 'session_id': '87524f50-7ba8-11ed-afd2-000d3a5a3fa5'}, {'id': 19, 'created': datetime.datetime(2022, 12, 15, 9, 34, 23, 45283), 'user_id': '33606199645', 'content_id': '10295212', 'event': 'details', 'session_id': '87524f50-7ba8-11ed-afd2-000d3a5a3fa5'}, {'id': 20, 'created': datetime.datetime(2022, 12, 15, 9, 34, 25, 745549), 'user_id': '33606199645', 'content_id': '10295212', 'event': 'details', 'session_id': '87524f50-7ba8-11ed-afd2-000d3a5a3fa5'}, {'id': 21, 'created': datetime.datetime(2022, 12, 15, 9, 34, 25, 747984), 'user_id': '33606199645', 'content_id': '10295212', 'event': 'more_details', 'session_id': '87524f50-7ba8-11ed-afd2-000d3a5a3fa5'}, {'id': 22, 'created': datetime.datetime(2022, 12, 15, 9, 34, 29, 584766), 'user_id': '33606199645', 'content_id': '10295212', 'event': 'buy', 'session_id': '87524f50-7ba8-11ed-afd2-000d3a5a3fa5'}, {'id': 23, 'created': datetime.datetime(2022, 12, 15, 9, 34, 32, 93424), 'user_id': '33606199645', 'content_id': '10295212', 'event': 'buy', 'session_id': '87524f50-7ba8-11ed-afd2-000d3a5a3fa5'}, {'id': 24, 'created': datetime.datetime(2022, 12, 15, 9, 34, 39, 625456), 'user_id': '33606199645', 'content_id': '0', 'event': 'genre:Music', 'session_id': '87524f50-7ba8-11ed-afd2-000d3a5a3fa5'}, {'id': 25, 'created': datetime.datetime(2022, 12, 15, 9, 36, 10, 441607), 'user_id': '69551453075', 'content_id': '5164438', 'event': 'details', 'session_id': '039060a4-7c5b-11ed-96c7-000d3a5a3fa5'}, {'id': 26, 'created': datetime.datetime(2022, 12, 15, 9, 36, 13, 270063), 'user_id': '69551453075', 'content_id': '5109280', 'event': 'details', 'session_id': '039060a4-7c5b-11ed-96c7-000d3a5a3fa5'}, {'id': 27, 'created': datetime.datetime(2022, 12, 15, 9, 36, 14, 716748), 'user_id': '69551453075', 'content_id': '2953050', 'event': 'details', 'session_id': '039060a4-7c5b-11ed-96c7-000d3a5a3fa5'}, {'id': 28, 'created': datetime.datetime(2022, 12, 15, 9, 36, 16, 245302), 'user_id': '69551453075', 'content_id': '1697800', 'event': 'details', 'session_id': '039060a4-7c5b-11ed-96c7-000d3a5a3fa5'}, {'id': 29, 'created': datetime.datetime(2022, 12, 15, 9, 36, 17, 565272), 'user_id': '69551453075', 'content_id': '4733624', 'event': 'details', 'session_id': '039060a4-7c5b-11ed-96c7-000d3a5a3fa5'}, {'id': 30, 'created': datetime.datetime(2022, 12, 15, 9, 36, 20, 101001), 'user_id': '69551453075', 'content_id': '3797512', 'event': 'details', 'session_id': '039060a4-7c5b-11ed-96c7-000d3a5a3fa5'}, {'id': 31, 'created': datetime.datetime(2022, 12, 15, 9, 36, 20, 628633), 'user_id': '69551453075', 'content_id': '4513678', 'event': 'details', 'session_id': '039060a4-7c5b-11ed-96c7-000d3a5a3fa5'}, '...(remaining elements truncated)...']>

>>> Log.objects.filter(created__contains=date(2022,12,15)).values().count()
58

Thử count xem trong ngày 2022/Dec/15 có bao nhiêu event xảy ra.

>>> Log.objects.filter(created__contains=date(2022,12,14)).values()
<QuerySet [{'id': 1, 'created': datetime.datetime(2022, 12, 14, 11, 37, 29, 805451), 'user_id': '14271057339', 'content_id': '10121392', 'event': 'details', 'session_id': 'ac631f04-7ba3-11ed-afd2-000d3a5a3fa5'}, {'id': 2, 'created': datetime.datetime(2022, 12, 14, 11, 37, 31, 753527), 'user_id': '14271057339', 'content_id': '10121392', 'event': 'more_details', 'session_id': 'ac631f04-7ba3-11ed-afd2-000d3a5a3fa5'}, {'id': 3, 'created': datetime.datetime(2022, 12, 14, 11, 37, 31, 756146), 'user_id': '14271057339', 'content_id': '10121392', 'event': 'details', 'session_id': 'ac631f04-7ba3-11ed-afd2-000d3a5a3fa5'}, {'id': 4, 'created': datetime.datetime(2022, 12, 14, 11, 40, 38, 408286), 'user_id': '14271057339', 'content_id': '5618690', 'event': 'details', 'session_id': 'ac631f04-7ba3-11ed-afd2-000d3a5a3fa5'}, {'id': 5, 'created': datetime.datetime(2022, 12, 14, 11, 44, 13, 825325), 'user_id': '14271057339', 'content_id': '5537002', 'event': 'details', 'session_id': 'ac631f04-7ba3-11ed-afd2-000d3a5a3fa5'}, {'id': 6, 'created': datetime.datetime(2022, 12, 14, 11, 44, 15, 677044), 'user_id': '14271057339', 'content_id': '5537002', 'event': 'more_details', 'session_id': 'ac631f04-7ba3-11ed-afd2-000d3a5a3fa5'}, {'id': 7, 'created': datetime.datetime(2022, 12, 14, 11, 44, 15, 681723), 'user_id': '14271057339', 'content_id': '5537002', 'event': 'details', 'session_id': 'ac631f04-7ba3-11ed-afd2-000d3a5a3fa5'}, {'id': 8, 'created': datetime.datetime(2022, 12, 14, 12, 12, 19, 562973), 'user_id': '33606199645', 'content_id': '10152736', 'event': 'details', 'session_id': '87524f50-7ba8-11ed-afd2-000d3a5a3fa5'}, {'id': 9, 'created': datetime.datetime(2022, 12, 14, 12, 29, 42, 83685), 'user_id': '33606199645', 'content_id': '10380900', 'event': 'details', 'session_id': '87524f50-7ba8-11ed-afd2-000d3a5a3fa5'}, {'id': 10, 'created': datetime.datetime(2022, 12, 14, 12, 29, 45, 168987), 'user_id': '33606199645', 'content_id': '10380900', 'event': 'more_details', 'session_id': '87524f50-7ba8-11ed-afd2-000d3a5a3fa5'}, {'id': 11, 'created': datetime.datetime(2022, 12, 14, 12, 29, 59, 70184), 'user_id': '33606199645', 'content_id': '0', 'event': 'genre:War', 'session_id': '87524f50-7ba8-11ed-afd2-000d3a5a3fa5'}]>

>>> Log.objects.filter(created__contains=date(2022,12,14)).values().count()
11

Thử count xem trong ngày 2022/Dec/14 có bao nhiêu event xảy ra.

Thử tính năng __gt trong QuerySet

>>> Log.objects.filter(pk__gt=100).values()
<QuerySet [{'id': 101, 'created': datetime.datetime(2022, 12, 21, 0, 32, 46, 135319), 'user_id': '68159542309', 'content_id': '3480822', 'event': 'buy', 'session_id': '6079aab2-80bd-11ed-916f-000d3a5a3fa5'}, {'id': 102, 'created': datetime.datetime(2022, 12, 21, 9, 13, 29, 820787), 'user_id': '33606199645', 'content_id': '10121392', 'event': 'details', 'session_id': '87524f50-7ba8-11ed-afd2-000d3a5a3fa5'}, {'id': 103, 'created': datetime.datetime(2022, 12, 21, 9, 13, 44, 786031), 'user_id': '33606199645', 'content_id': '10155932', 'event': 'details', 'session_id': '87524f50-7ba8-11ed-afd2-000d3a5a3fa5'}, {'id': 104, 'created': datetime.datetime(2022, 12, 21, 9, 14, 3, 955965), 'user_id': '33606199645', 'content_id': '10155932', 'event': 'more_details', 'session_id': '87524f50-7ba8-11ed-afd2-000d3a5a3fa5'}, {'id': 105, 'created': datetime.datetime(2022, 12, 21, 9, 14, 3, 969759), 'user_id': '33606199645', 'content_id': '10155932', 'event': 'details', 'session_id': '87524f50-7ba8-11ed-afd2-000d3a5a3fa5'}, {'id': 106, 'created': datetime.datetime(2022, 12, 21, 9, 21, 57, 882967), 'user_id': '33606199645', 'content_id': '10155932', 'event': 'details', 'session_id': '87524f50-7ba8-11ed-afd2-000d3a5a3fa5'}, {'id': 107, 'created': datetime.datetime(2022, 12, 21, 10, 38, 15, 585011), 'user_id': '36314581990', 'content_id': '10243676', 'event': 'details', 'session_id': '89280a72-811b-11ed-916f-000d3a5a3fa5'}, {'id': 108, 'created': datetime.datetime(2022, 12, 21, 10, 46, 16, 994504), 'user_id': '33606199645', 'content_id': '993840', 'event': 'details', 'session_id': '87524f50-7ba8-11ed-afd2-000d3a5a3fa5'}, {'id': 109, 'created': datetime.datetime(2022, 12, 21, 10, 46, 17, 153694), 'user_id': '33606199645', 'content_id': '993840', 'event': 'details', 'session_id': '87524f50-7ba8-11ed-afd2-000d3a5a3fa5'}, {'id': 110, 'created': datetime.datetime(2022, 12, 21, 10, 46, 17, 958542), 'user_id': '33606199645', 'content_id': '993840', 'event': 'details', 'session_id': '87524f50-7ba8-11ed-afd2-000d3a5a3fa5'}, {'id': 111, 'created': datetime.datetime(2022, 12, 21, 10, 46, 20, 492223), 'user_id': '33606199645', 'content_id': '993840', 'event': 'save_for_later', 'session_id': '87524f50-7ba8-11ed-afd2-000d3a5a3fa5'}, {'id': 112, 'created': datetime.datetime(2022, 12, 21, 10, 46, 20, 502071), 'user_id': '33606199645', 'content_id': '993840', 'event': 'details', 'session_id': '87524f50-7ba8-11ed-afd2-000d3a5a3fa5'}, {'id': 113, 'created': datetime.datetime(2022, 12, 21, 10, 46, 21, 775887), 'user_id': '33606199645', 'content_id': '993840', 'event': 'save_for_later', 'session_id': '87524f50-7ba8-11ed-afd2-000d3a5a3fa5'}, {'id': 114, 'created': datetime.datetime(2022, 12, 21, 10, 46, 21, 786541), 'user_id': '33606199645', 'content_id': '993840', 'event': 'details', 'session_id': '87524f50-7ba8-11ed-afd2-000d3a5a3fa5'}, {'id': 115, 'created': datetime.datetime(2022, 12, 21, 10, 46, 23, 247371), 'user_id': '33606199645', 'content_id': '993840', 'event': 'more_details', 'session_id': '87524f50-7ba8-11ed-afd2-000d3a5a3fa5'}, {'id': 116, 'created': datetime.datetime(2022, 12, 21, 10, 46, 23, 259731), 'user_id': '33606199645', 'content_id': '993840', 'event': 'details', 'session_id': '87524f50-7ba8-11ed-afd2-000d3a5a3fa5'}, {'id': 117, 'created': datetime.datetime(2022, 12, 21, 10, 46, 57, 702927), 'user_id': '33606199645', 'content_id': '0993840', 'event': 'buy', 'session_id': '87524f50-7ba8-11ed-afd2-000d3a5a3fa5'}, {'id': 118, 'created': datetime.datetime(2022, 12, 22, 0, 6, 15, 51906), 'user_id': '85913049150', 'content_id': '0', 'event': 'genre:Game-Show', 'session_id': 'c48da1d4-818a-11ed-9170-000d3a5a3fa5'}, {'id': 119, 'created': datetime.datetime(2022, 12, 22, 0, 6, 22, 232249), 'user_id': '85913049150', 'content_id': '0', 'event': 'genre:War', 'session_id': 'c48da1d4-818a-11ed-9170-000d3a5a3fa5'}, {'id': 120, 'created': datetime.datetime(2022, 12, 22, 0, 6, 33, 199537), 'user_id': '85913049150', 'content_id': '0', 'event': 'genre:Fantasy', 'session_id': 'c48da1d4-818a-11ed-9170-000d3a5a3fa5'}, '...(remaining elements truncated)...']>

>>> Log.objects.filter(pk__gt=100).values().count()
35

Hiển thị những id có số lớn hơn 100 trong dữ liệu.

Thử một vài tính năng khác của QuerySet

>>> help('prs_project')
Help on package prs_project:

NAME
    prs_project

PACKAGE CONTENTS
    settings
    urls
    wsgi

FILE
    /home/ninehealth/work/moviegeek/prs_project/__init__.py

>>> help('prs_project.urls')
/home/ninehealth/work/moviegeek/venv_3.6.9/lib/python3.6/site-packages/requests/__init__.py:91: RequestsDependencyWarning: urllib3 (1.26.5) or chardet (3.0.4) doesn't match a supported version!
  RequestsDependencyWarning)
Help on module prs_project.urls in prs_project:

NAME
    prs_project.urls - prs_project URL Configuration

DATA
    urlpatterns = [<URLPattern '^$' [name='index']>, <URLResolver <module ...

FILE
    /home/ninehealth/work/moviegeek/prs_project/urls.py

Xem phần Help của PRS.

>>> Log.objects.values('session_id').distinct()
<QuerySet [{'session_id': 'ac631f04-7ba3-11ed-afd2-000d3a5a3fa5'}, {'session_id': '87524f50-7ba8-11ed-afd2-000d3a5a3fa5'}, {'session_id': '039060a4-7c5b-11ed-96c7-000d3a5a3fa5'}, {'session_id': '3e9ba490-7c76-11ed-a073-000d3a5a3fa5'}, {'session_id': '133225e2-7f58-11ed-a073-000d3a5a3fa5'}, {'session_id': '8c8cf902-7f59-11ed-a073-000d3a5a3fa5'}, {'session_id': '6079aab2-80bd-11ed-916f-000d3a5a3fa5'}, {'session_id': '89280a72-811b-11ed-916f-000d3a5a3fa5'}, {'session_id': 'c48da1d4-818a-11ed-9170-000d3a5a3fa5'}, {'session_id': '1e717692-8764-11ed-9171-000d3a5a3fa5'}, {'session_id': '0082605a-8a80-11ed-9171-000d3a5a3fa5'}]>

>>> Log.objects.values('session_id').distinct().count()
11

Đếm số lượng Session ID.

https://www.w3schools.com/django/django_queryset.php

1 trang web tham khảo khác về QuerySet.

>>> Log.objects.values('session_id').annotate(session_count=Count('session_id'))
<QuerySet [{'session_id': '0082605a-8a80-11ed-9171-000d3a5a3fa5', 'session_count': 6}, {'session_id': '039060a4-7c5b-11ed-96c7-000d3a5a3fa5', 'session_count': 15}, {'session_id': '133225e2-7f58-11ed-a073-000d3a5a3fa5', 'session_count': 10}, {'session_id': '1e717692-8764-11ed-9171-000d3a5a3fa5', 'session_count': 2}, {'session_id': '3e9ba490-7c76-11ed-a073-000d3a5a3fa5', 'session_count': 9}, {'session_id': '6079aab2-80bd-11ed-916f-000d3a5a3fa5', 'session_count': 10}, {'session_id': '87524f50-7ba8-11ed-afd2-000d3a5a3fa5', 'session_count': 57}, {'session_id': '89280a72-811b-11ed-916f-000d3a5a3fa5', 'session_count': 1}, {'session_id': '8c8cf902-7f59-11ed-a073-000d3a5a3fa5', 'session_count': 8}, {'session_id': 'ac631f04-7ba3-11ed-afd2-000d3a5a3fa5', 'session_count': 7}, {'session_id': 'c48da1d4-818a-11ed-9170-000d3a5a3fa5', 'session_count': 10}]>

Thêm số lượng Session trong từng Session ID!!!

>>> Log.objects.values('user_id').distinct()
<QuerySet [{'user_id': '14271057339'}, {'user_id': '33606199645'}, {'user_id': '69551453075'}, {'user_id': '30159478644'}, {'user_id': '68256497607'}, {'user_id': '73165680939'}, {'user_id': '68159542309'}, {'user_id': '36314581990'}, {'user_id': '85913049150'}, {'user_id': '85329678214'}, {'user_id': '88147736834'}]>

>>> Log.objects.values('user_id').distinct().count()
11

Tính số lượng unique users.

>>> Log.objects.values('event').distinct()
<QuerySet [{'event': 'details'}, {'event': 'more_details'}, {'event': 'genre:War'}, {'event': 'genre:Short'}, {'event': 'genre:Comedy'}, {'event': 'buy'}, {'event': 'genre:Music'}, {'event': 'genre:Action'}, {'event': 'save_for_later'}, {'event': 'genre:Adventure'}, {'event': 'genre:Talk-Show'}, {'event': 'genre:Documentary'}, {'event': 'genre:Biography'}, {'event': 'genre:Film-Noir'}, {'event': 'genre:History'}, {'event': 'genre:Game-Show'}, {'event': 'genre:Fantasy'}]>

>>> Log.objects.values('event').distinct().count()
17

Xem số lượng unique events.

>>> uniq_users = Log.objects.values('user_id').distinct()
>>> for user in uniq_users:
...   print(user)
... 
{'user_id': '14271057339'}
{'user_id': '33606199645'}
{'user_id': '69551453075'}
{'user_id': '30159478644'}
{'user_id': '68256497607'}
{'user_id': '73165680939'}
{'user_id': '68159542309'}
{'user_id': '36314581990'}
{'user_id': '85913049150'}
{'user_id': '85329678214'}
{'user_id': '88147736834'}

Hiển thị User ID.

>>> Log.objects.filter(user_id=14271057339).values('created')
<QuerySet [{'created': datetime.datetime(2022, 12, 14, 11, 37, 29, 805451)}, {'created': datetime.datetime(2022, 12, 14, 11, 37, 31, 753527)}, {'created': datetime.datetime(2022, 12, 14, 11, 37, 31, 756146)}, {'created': datetime.datetime(2022, 12, 14, 11, 40, 38, 408286)}, {'created': datetime.datetime(2022, 12, 14, 11, 44, 13, 825325)}, {'created': datetime.datetime(2022, 12, 14, 11, 44, 15, 677044)}, {'created': datetime.datetime(2022, 12, 14, 11, 44, 15, 681723)}]>

>>> Log.objects.filter(user_id=14271057339).values('created').first()
{'created': datetime.datetime(2022, 12, 14, 11, 37, 29, 805451)}

>>> Log.objects.filter(user_id=14271057339).values('created').first()
{'created': datetime.datetime(2022, 12, 14, 11, 37, 29, 805451)}

>>> Log.objects.filter(user_id=14271057339).values('created').first()['created']
datetime.datetime(2022, 12, 14, 11, 37, 29, 805451)

>>> type(Log.objects.filter(user_id=14271057339).values('created').first()['created'])
<class 'datetime.datetime'>

>>> print(Log.objects.filter(user_id=14271057339).values('created').first()['created'])
2022-12-14 11:37:29.805451

>>> print(2, Log.objects.filter(user_id=14271057339).values('created').first()['created'])
2 2022-12-14 11:37:29.805451

Làm quen với hàm date trong module datetime.

>>> for user in uniq_users:
...   user_id = user['user_id']
...   first_created_date = Log.objects.filter(user_id=user_id).values('created').first()['created']
...   print(user_id, "|", first_created_date)
... 
14271057339 | 2022-12-14 11:37:29.805451
33606199645 | 2022-12-14 12:12:19.562973
69551453075 | 2022-12-15 09:30:35.189061
30159478644 | 2022-12-15 12:45:11.904543
68256497607 | 2022-12-19 04:47:23.331939
73165680939 | 2022-12-19 04:57:11.047484
68159542309 | 2022-12-21 00:10:25.121021
36314581990 | 2022-12-21 10:38:15.585011
85913049150 | 2022-12-22 00:06:15.051906
85329678214 | 2022-12-29 11:10:33.041959
88147736834 | 2023-01-02 09:30:06.860626

Hiển thị thời gian đầu tiên user được tạo ra.

>>> Log.objects.filter(user_id=14271057339).annotate(event_count=Count('event')).values('created', 'event_count').first()
{'created': datetime.datetime(2022, 12, 14, 11, 37, 29, 805451), 'event_count': 1}

Hiển thị các event của user này cơ mà viết bị sai...

>>> uniq_users = Log.objects.values('user_id').annotate(event_count=Count('user_id'))

>>> uniq_users
<QuerySet [{'user_id': '14271057339', 'event_count': 7}, {'user_id': '30159478644', 'event_count': 9}, {'user_id': '33606199645', 'event_count': 57}, {'user_id': '36314581990', 'event_count': 1}, {'user_id': '68159542309', 'event_count': 10}, {'user_id': '68256497607', 'event_count': 10}, {'user_id': '69551453075', 'event_count': 15}, {'user_id': '73165680939', 'event_count': 8}, {'user_id': '85329678214', 'event_count': 2}, {'user_id': '85913049150', 'event_count': 10}, {'user_id': '88147736834', 'event_count': 6}]>

>>> uniq_users = Log.objects.values('user_id').annotate(event_count=Count('user_id'))

>>> for user in uniq_users:
...   user_id = user['user_id']
...   first_created_date = Log.objects.filter(user_id=user_id).values('created').first()['created']
...   event_count = user['event_count']
...   print(user_id, "|", first_created_date, "|", event_count)
... 
14271057339 | 2022-12-14 11:37:29.805451 | 7
30159478644 | 2022-12-15 12:45:11.904543 | 9
33606199645 | 2022-12-14 12:12:19.562973 | 57
36314581990 | 2022-12-21 10:38:15.585011 | 1
68159542309 | 2022-12-21 00:10:25.121021 | 10
68256497607 | 2022-12-19 04:47:23.331939 | 10
69551453075 | 2022-12-15 09:30:35.189061 | 15
73165680939 | 2022-12-19 04:57:11.047484 | 8
85329678214 | 2022-12-29 11:10:33.041959 | 2
85913049150 | 2022-12-22 00:06:15.051906 | 10
88147736834 | 2023-01-02 09:30:06.860626 | 6

Sửa lại cho đúng và hiển thị được số lượng event đi kèm với user.

>>> import moviegeeks
>>> help(moviegeeks)
Help on package moviegeeks:

NAME
    moviegeeks

PACKAGE CONTENTS
    admin
    apps
    models
    tests
    urls
    views

FILE
    /home/ninehealth/work/moviegeek/moviegeeks/__init__.py

Định thử tiếp 1 ít với app (package) moviegeeks cơ mà có lẽ QuerySet tìm hiểu thế là đủ rồi!!!

Một vài suy nghĩ khác

Thanks Quang giới thiệu cuốn sách dùng Django rất nhiều này nhé O_O.

Quả thật là QuerySet thật là mạnh đấy!!!

Ngoài ra tớ cũng hiểu hơn về class, kế thừa khi dùng Help function built-in của Python!!!

Rất là hữu ích mặc dù không có visualization gì cả O_O. Tưởng tượng trong đầu hết thôi.

Và tớ thấy mọi thứ rất gọn gàng và clean, kể cả phần Help.

Có thể thấy có được cái đấy ngoài công của bác nghĩ ra còn do cộng đồng nữa!!!

Bảo sao Google dùng Python rất nhiều ._.

Một lần nữa thanks Quang và sorry đã gửi comment muộn.

Mai chắc là tớ quay lại với Chương 5 được rồi!!! Đã study xong QuerySet rồi. Có lẽ cần 1 Wiki document nữa hix.

9health commented 1 year ago

Hello @quangvv9Life,

Tớ nghĩ task này cũng hòm hòm rùi @_@.

QuerySet hay hơn nhiều SQL cơ mà cần biết lập trình 1 xíu ^_^

Tớ sẽ chuyển task này sang trạng thái Review nhé!!!

Thanks Quang!!!

quangvv9Life commented 1 year ago

Hi Hải,

Không hiểu sao tớ bị miss mất 2 comments 3 ngày trước của Hải cho task này.

Đọc qua về querySet và help thì tớ hiểu đó là 2 công cụ để tìm hiểu về python, django và database Qua việc hiểu rõ về dữ liệu rồi và tìm hiểu thêm về các thuật toán thì mình sẽ hiểu được cách xử lí của các thuật toán đó trên dữ liệu và kết quả dữ liệu đầu ra như thế nào. Và từ việc hiểu về dữ liệu thì cũng là cơ sở để thay ruột bằng dữ liệu "foods" và "exercises" và từ đó tìm được thuật toán phù hợp và sửa lại trên bộ dữ liệu mới

BR