Tổng hợp 84 câu hỏi phỏng vấn Django kèm đáp án chi tiết, song ngữ Việt–Anh — sắp xếp từ cơ bản đến nâng cao. Ôn luyện miễn phí, tự động lưu tiến độ.
Django là web framework Python kiểu "batteries-included" — ORM, admin, auth, form, template, migration đều có sẵn. Cài xong là gần như đủ đồ để dựng một app production, không phải đi gom 5–7 thư viện rời rồi tự ráp lại. Hợp với: app server-rendered…
Django dùng MVT (Model–View–Template) — bản chất giống MVC nhưng đổi tên cho khớp vai trò thực tế. Model = bảng + business logic, View = function/class nhận request trả response (đóng vai Controller trong MVC), Template = file HTML render dữ liệu (đóng vai…
Project là toàn bộ website — 1 settings, 1 deployment. App là một module nghiệp vụ nằm trong project, đóng gói riêng models.py, views.py, urls.py, migrations/, có thể bê đi cài lại ở project khác. Một project chứa nhiều app. Ví dụ một shop: project…
Cách phổ biến nhất là tách settings thành package theo môi trường, đọc secret qua biến môi trường, và tuyệt đối không commit file .env thật vào repo: Khi chạy thì chỉ định bằng DJANGOSETTINGSMODULE=config.settings.prod. Mấy thứ secret như SECRETKEY, DATABASEURL, API key đọc qua…
manage.py là CLI wrapper quanh django-admin, set sẵn DJANGOSETTINGSMODULE cho project hiện tại. Nhờ đó python manage.py <cmd luôn chạy đúng config dev/test/prod đang chọn, không cần khai báo lại. Mấy lệnh dùng nhiều: Hai thứ hay quên: runserver chỉ dành cho dev (production phải…
Model là Python class kế thừa models.Model, định nghĩa bảng + field + quan hệ. Migration là file Python ghi lại thay đổi schema — Django đọc để biết cần ALTER TABLE gì khi migrate. Sau khi sửa model (thêm field, đổi type), chạy lại…
QuerySet lazy nghĩa là Django chưa chạy SQL khi bạn tạo query, chỉ chạy khi evaluate — tức là iterate, list(), len(), bool(), slicing có step, hoặc serialize. Nhờ vậy bạn có thể .filter().exclude().orderby() nối nhiều bước mà cuối cùng vẫn chỉ chạy đúng một…
Cả hai đều dùng để chống N+1 query, nhưng cho 2 loại quan hệ khác nhau. selectrelated(...) dành cho ForeignKey / OneToOneField (quan hệ single) — Django ghép JOIN vào 1 câu SQL, trả về object kèm related đã load. Còn prefetchrelated(...) dành cho ManyToMany…
transaction.atomic() bọc một khối code thành transaction theo nguyên tắc all or nothing. Bên trong raise exception → mọi INSERT/UPDATE/DELETE đã chạy trong khối đó được rollback hết. Dùng khi nhiều bước nghiệp vụ phải nhất quán với nhau: tạo đơn hàng + trừ kho…
Có 3 cách để tái dùng hoặc định nghĩa lại model mà không phải tạo bảng mới không cần thiết. Meta.abstract = True biến class thành template — không tạo bảng, class con kế thừa field + method nhưng mỗi class có bảng riêng. Hay…
FBV (Function-Based View) là một function nhận request trả HttpResponse — đọc một mạch từ trên xuống, rất trực quan. CBV (Class-Based View) là class kế thừa từ View hoặc generic class (ListView, DetailView...), tổ chức theo HTTP method (get(), post()) và cho phép gắn…
Khi request đến, Django duyệt request.path với danh sách urlpatterns theo thứ tự khai báo, dùng path() hoặc repath(). Match xong thì capture group được pass vào view tương ứng. Mỗi app giữ urls.py riêng và khai appname namespace, sau đó reverse URL qua reverse('blog:post-detail',…
Generic CBV đóng gói sẵn pattern CRUD: lấy object/list, render template, xử lý form, redirect — bạn chỉ phải override những phần thực sự khác. ListView lo phân trang, DetailView lo lookup theo pk/slug, CreateView/UpdateView lo form + save + redirect. Đủ dùng cho phần…
Đây là 3 decorator dán lên FBV để chặn request trước khi vào logic — tương đương với mixin tương ứng trên CBV (LoginRequiredMixin, PermissionRequiredMixin). Ngắn gọn từng cái: @loginrequired chưa login thì redirect về LOGINURL. @permissionrequired('app.codename', raiseexception=True) thiếu perm thì raise PermissionDenied (403) thay…
Cả 3 đều là response object, chọn cái nào tuỳ vào kiểu dữ liệu và kích thước. HttpResponse(content, contenttype=...) buffer toàn bộ body trong RAM rồi trả — hợp với HTML, text, binary nhỏ. JsonResponse({...}) là wrapper quanh HttpResponse với contenttype='application/json' cộng json.dumps — hợp…
Django Template Language (DTL) là engine mặc định, an toàn ngay từ thiết kế: không cho gọi function tuỳ ý từ template, auto-escape HTML, cú pháp {{ var }} / {% tag %}. Jinja2 linh hoạt hơn — gọi được Python expression đầy đủ, có…
Form khai báo field thủ công, không gắn với model — hợp với search, filter, contact form, multi-step wizard. ModelForm sinh field tự động từ model và có sẵn save() ghi DB — hợp với CRUD trực tiếp một model. Quy tắc đơn giản: input…
CSRF (Cross-Site Request Forgery) là kiểu tấn công khi site độc hại lừa trình duyệt người dùng (đã đăng nhập site của bạn) gửi request thay đổi dữ liệu thay họ. Token CSRF là chuỗi ngẫu nhiên per-session: server phát ra → client gửi lại…
Khi gọi form.isvalid(), Django chạy validation theo 3 tầng nối tiếp nhau. Tầng 1 (per-field): chạy topython() → built-in validator của field (maxlength, EmailValidator...) → custom validator trong validators=[...]. Tầng 2 (clean<fieldname()): method tự viết để clean 1 field, có thể raise ValidationError hoặc trả…
Middleware là callable bọc quanh pipeline request → view → response, chạy trước/sau view cho mọi request. Hợp với các cross-cutting concern: auth, session, CSRF, logging, GZip, security header, gắn tenant context vào request. Register vào MIDDLEWARE setting; thứ tự khai báo rất quan trọng…
Hình dung request đi qua một stack middleware rồi quay ngược lại như đi vào hang rồi đi ra. Dịch ra code: server gọi application(request) → MIDDLEWARE[0] → MIDDLEWARE[1] → ... → resolve URL → gọi view → có response → middleware unwind theo chiều…
Thứ tự MIDDLEWARE quyết định thứ tự bao bọc — middleware ở top chạy đầu tiên khi request đi vào và cuối cùng khi response đi ra. Đặt sai thì middleware sau không thấy thứ middleware trước đã set, hoặc tệ hơn là check security…
django.contrib.auth là module auth built-in: model User, hash password (PBKDF2 mặc định), session-based login/logout, decorator @loginrequired, hệ thống permission (group, permission), template tag {% if user.isauthenticated %}, view sẵn cho login/logout/password reset. Session lưu trong DB (bảng djangosession) hoặc Redis nếu set SESSIONENGINE = 'django.contrib.sessions.backends.cache'.…
Cả 2 đều cho phép thay auth.User mặc định, khác nhau ở mức độ phải tự viết. AbstractUser giữ nguyên schema của User (username, firstname, lastname, email, isstaff, isactive...), bạn chỉ thêm field hoặc tinh chỉnh nhẹ — dùng khi vẫn muốn giữ username và…
Django built-in chỉ có model-level permission — tức là quyền làm hành động X trên toàn bộ model Y, chứ không có object-level out-of-the-box. Mỗi model tự sinh 4 permission khi migrate: addpost, changepost, deletepost, viewpost. Muốn thêm custom thì khai báo trong Meta.permissions =…
DRF là thư viện trên Django chuyên cho REST API: serializer (validate + parse JSON), viewset (gom logic CRUD), router (sinh URL tự động), authentication/permission/throttling/pagination, và browsable API UI để test. Không có DRF bạn vẫn có thể trả JsonResponse từ Django view, nhưng phải…
Serializer khai báo field thủ công — dùng khi input/output không map trực tiếp 1-1 với model (multi-source, computed field, action không tạo entity). ModelSerializer sinh field tự động từ model và có sẵn create(), update() — dùng cho CRUD chuẩn. Validation chạy theo thứ…
ViewSet gom logic CRUD vào một class, mỗi method ứng với một action (list, retrieve, create, update, partialupdate, destroy). Router đọc viewset rồi sinh URL tự động kèm name tương ứng. Khi cần custom queryset riêng cho từng action (ví dụ list filter theo user,…
DRF chạy 2 lớp trước view: Authentication xác định bạn là ai (set request.user), Permission xác định bạn có được làm hành động này không. Custom permission là class chỉ cần 1-2 method: DRF gọi haspermission() cho list/create, và hasobjectpermission() cho retrieve/update/delete một cách tự…
DRF cho 3 style pagination, mỗi cái tối ưu cho một kiểu UI/dataset khác nhau. PageNumberPagination (?page=2&pagesize=20) hiển thị "Page 1 / 2 / 3 ..." — hợp với UI có số trang. Đơn giản, nhưng OFFSET càng lớn càng chậm. LimitOffsetPagination (?limit=20&offset=40) linh hoạt…
Signals là cơ chế observer của Django: gắn listener vào một sự kiện (model lưu, xoá, request bắt đầu) — sender phát signal, mọi receiver chạy đồng bộ ngay sau đó, trừ khi bạn tự đẩy qua task queue. Mấy signal built-in hay dùng: presave,…
Celery là task queue chạy ngoài request cycle — request handler đẩy task vào broker (Redis/RabbitMQ), worker process pick lên xử lý. Dùng cho gửi email, sinh thumbnail, export file, sync 3rd-party API. Chạy worker: celery -A config worker -l info. Cần cron-like schedule thì…
N+1 xảy ra khi bạn chạy 1 query lấy N object, rồi với mỗi object lại chạy thêm 1 query để lấy related → tổng 1 + N query. Fix bằng selectrelated (FK/OneToOne) hoặc prefetchrelated (M2M, reverse FK) — xem [[9207]]: Bắt sớm trong dev…
Có 2 cách khai báo index trong Django model: Đặt index ở cột thường xuyên xuất hiện trong WHERE, JOIN, ORDER BY. Composite index đi từ trái sang phải — (author, createdat) phục vụ tốt query WHERE author=? ORDER BY createdat, nhưng không giúp gì…
Django có 4 level cache, đi từ thô-rộng đến mịn-hẹp. Per-site cache (cặp UpdateCacheMiddleware + FetchFromCacheMiddleware) cache toàn bộ page response — hợp với site mostly-read như blog, landing. Per-view cache (decorator @cachepage(60 15) hoặc cachepage() ở URLconf) chỉ cache một view cụ thể. Template…
ORM mặc định dùng parameterized query — giá trị truyền vào không bao giờ string-format vào SQL, mà gửi riêng qua driver: Lỗ hổng SQL injection vẫn lọt qua 3 đường: Cách đúng: extra() đã deprecated, tránh hoàn toàn. Func(), Expression, Subquery mới là cách…
WSGI (Web Server Gateway Interface) là interface đồng bộ giữa Python web app và server (Gunicorn, uWSGI) — mỗi request một worker thread/process, request xong worker rảnh. Đơn giản, ổn định, là mặc định của Django. ASGI (Asynchronous Server Gateway Interface) là interface bất đồng…
Gunicorn có 3 worker type chính, mỗi cái hợp một loại workload. sync (mặc định) một request một worker, blocking I/O — đơn giản, hợp CPU-bound hoặc app I/O nhanh. gthread dùng pool thread cho mỗi worker — tốt cho I/O-bound (DB query nhiều, gọi…
Loop instance.save() cho 10k row = 10k INSERT round-trip → tốn vài chục giây và ép DB ngộp connection. Bulk operations gom thành 1-N câu SQL, nhanh hơn 10–100 lần. Model.objects.bulkcreate(objs, batchsize=1000) chạy 1 INSERT cho mỗi batch, có ignoreconflicts=True (skip duplicate) và updateconflicts=True (upsert…
Cả 4 đều giảm lượng dữ liệu kéo về từ DB, dùng khi không cần object đầy đủ. .values('id', 'name') trả về QuerySet của dict chỉ chứa field liệt kê — không khởi tạo model instance nên nhanh và tiết kiệm RAM. .valueslist('id', 'name') giống…
Đây là 4 helper hay dùng nhất trong view, làm code ngắn và nhất quán. getobjector404(Model, lookup) gọi .get(), nếu DoesNotExist thì raise Http404 → Django tự trả 404 page, đỡ phải try/except lặp đi lặp lại. Http404 là exception built-in; raise ở đâu thì…
Django có sẵn 3 lớp test khác nhau ở cách xử lý DB và mức độ isolation. TestCase wrap mỗi test trong transaction.atomic() rồi rollback khi xong — DB sạch giữa các test, rất nhanh, là lựa chọn mặc định. TransactionTestCase không wrap transaction nên…
DRF có 3 filter backend chuẩn, bật ở DEFAULTFILTERBACKENDS rồi khai báo trên viewset là xong, không phải tự viết logic query param. Cần filter phức tạp (range, custom lookup) thì khai báo FilterSet class riêng: SearchFilter mặc định dùng icontains trên field liệt kê…
DRF cho 5 strategy, khác nhau ở nơi đặt version trong request: Đừng version chỉ vì có thể sau này sẽ thay đổi — chỉ version khi thật sự breaking. Chiến lược phổ biến hơn nhiều team đang dùng: giữ field cũ, thêm field mới,…
CORS (Cross-Origin Resource Sharing) là cơ chế browser bắt server xác nhận đồng ý trước khi cho domain khác gọi API. Khi SPA ở app.example.com fetch tới api.example.com, browser sẽ gửi preflight OPTIONS rồi check header Access-Control-Allow- trong response — không pass là không cho…
Ngoài DEBUG = False và ALLOWEDHOSTS (xem [[9244]]), Django có nhóm setting SECURE cần bật cho production. Cách nhanh nhất để biết còn thiếu gì: chạy python manage.py check --deploy — Django liệt kê hết. Hai thứ phải cẩn thận. HSTS preload là cam kết…
Admin là một trong những thứ "miễn phí" giá trị nhất của Django — vừa migrate xong, non-dev đã có chỗ nhập liệu và audit. Customize bằng cách viết ModelAdmin class rồi register cho mỗi model. Mấy option hay dùng: listdisplay chọn cột hiện trên…
- filter(kwargs): trả về một QuerySet (0..n bản ghi), lazy (chỉ chạy SQL khi được duyệt), và chain được tiếp. - get(kwargs): trả về đúng một object. Không có → ném DoesNotExist; nhiều hơn một → ném MultipleObjectsReturned. Dùng get() khi chắc chắn truy vấn…
Hai thứ ở hai tầng khác nhau, độc lập với nhau: - null=True: tầng database — cho phép cột chứa NULL. - blank=True: tầng validation (form/admin) — cho phép để trống khi nhập. Quy ước của Django: - Field text/char: nên blank=True mà không null=True.…
Chọn theo tính chất quan hệ: - ForeignKey — quan hệ nhiều-một: nhiều bản ghi trỏ về một. VD nhiều Order thuộc một User. Cột khoá nằm ở phía "nhiều". - OneToOneField — một-một, mỗi bên tối đa một. VD Profile mở rộng User. Bản…
Django gọi mô hình của mình là MTV/MVT (Model–Template–View) — cùng bản chất MVC nhưng đổi tên cho khớp vai trò thực tế: Django MVC cổ điển Vai trò --------- Model Model dữ liệu + business logic Template View lớp hiển thị (render HTML) View…
Là một hàm nhận request và trả về một dict; dict đó được trộn vào context của mọi template render qua RequestContext. Đăng ký trong TEMPLATES['OPTIONS']['contextprocessors']. Dùng để inject biến toàn cục vào mọi template mà không phải truyền tay ở từng view — user…
Một template cha (base.html) định nghĩa khung chung và các "lỗ trống" bằng {% block ten %}{% endblock %}. Template con mở đầu bằng {% extends "base.html" %} rồi override từng block. Block nào con không định nghĩa thì giữ nội dung mặc định của…
aggregate() thu cả QuerySet về một dict duy nhất; annotate() gắn thêm một cột tính toán vào từng dòng và vẫn trả về QuerySet. Về SQL: aggregate() sinh một SELECT AVG(...) không GROUP BY; annotate() sinh JOIN + GROUP BY theo khoá chính của model…
Chọn theo việc bạn sẽ làm tiếp với dữ liệu, vì QuerySet chỉ chạy query khi bị evaluate và cache kết quả sau lần evaluate đầu tiên. - Chỉ cần biết có hay không → qs.exists(). SQL sinh ra là SELECT 1 ... LIMIT 1,…
Chỉ truyền id (primary key), rồi để task tự query lại. Tham số của task phải đi qua broker nên bị serialize (mặc định JSON). Một model instance vừa không serialize được bằng JSON, vừa là snapshot dữ liệu tại thời điểm đẩy task —…
Ba mức trừu tượng chồng lên nhau, chọn theo mức độ "chuẩn CRUD" của endpoint. - APIView — gần nhất với view viết tay: bạn tự viết get(), post(). Dùng khi endpoint không phải CRUD trên một model: /auth/login, /reports/export, endpoint gọi service ngoài. -…
Không, nếu thiếu ràng buộc unique ở tầng database. getorcreate() thực chất là try get → except DoesNotExist → create. Hai request đồng thời có thể cùng get hụt, rồi cùng create → hai bản ghi trùng. Django dựa vào database làm trọng tài: nếu…
Dùng đối tượng Prefetch để chỉ định QuerySet con, thay vì chuỗi string. prefetchrelated('comments') luôn kéo toàn bộ comment. Nếu chỉ cần comment đã duyệt, sắp mới nhất trước: Ba tham số cần biết: - lookup — tên quan hệ, hỗ trợ đi sâu ('commentsauthor').…
Khi gọi serializer.isvalid(), DRF chạy lần lượt: 1. tointernalvalue() — ép kiểu từng field (IntegerField sang int...) và chạy validator cấp field (maxlength, UniqueValidator...). Field nào lỗi thì bị loại khỏi bước sau. 2. validate<fieldname(self, value) — kiểm tra riêng từng field, nhận giá trị…
Vì postsave bắn ngay sau khi save() chạy xong, nhưng transaction chưa commit. Worker Celery là tiến trình khác, dùng connection khác, nên nó SELECT vào lúc dữ liệu còn nằm trong transaction chưa commit — kết quả là DoesNotExist, hoặc tệ hơn là đọc…
Data migration dùng operation RunPython, và phải lấy model qua apps.getmodel() chứ không import từ models.py. Vì sao không import trực tiếp: migration chạy trên bảng ở trạng thái lịch sử của thời điểm đó, còn models.py là phiên bản mới nhất. Nếu sau này…
Có ba chiến lược, chọn theo mức độ chấp nhận dữ liệu cũ. 1. TTL ngắn (đơn giản nhất) — chấp nhận dữ liệu cũ vài chục giây, không cần invalidate. 2. Xoá key khi dữ liệu đổi — chính xác nhất nhưng phải nhớ…
Retry phải đi kèm idempotency, vì Celery mặc định là at-least-once: worker chết giữa chừng, hoặc ackslate bật, đều dẫn tới task chạy lại. Retry có kiểm soát: - Chỉ retry lỗi tạm thời (timeout, 5xx, mất kết nối). Lỗi nghiệp vụ (thẻ bị từ…