2015-01-01 14 views
13

Tôi đã làm việc trên phiên bản ngoại tuyến của ứng dụng web Django của mình và đã xóa các phiên bản mô hình thường xuyên đối với một ModelX nhất định.Trường hợp mô hình Django các khóa chính không được đặt lại thành 1 sau khi tất cả các trường hợp bị xóa

Tôi đã thực hiện việc này từ trang quản trị và không gặp phải sự cố nào. Mô hình chỉ có hai trường: tên và thứ tự và không có mối quan hệ nào khác với các mô hình khác.

Các phiên bản mới được cung cấp cho pk có sẵn tiếp theo, và khi tôi đã xóa tất cả các trường hợp, thêm một phiên bản mới tạo ra giá trị pk = 1, mà tôi mong đợi.

Chuyển mã trực tuyến sang cơ sở dữ liệu thực của tôi Tôi nhận thấy rằng đây không phải là trường hợp. Tôi cần phải thay đổi các trường hợp mô hình vì vậy tôi đã xóa tất cả các trường hợp đó nhưng tôi đã bất ngờ khi các phím chính được giữ lại mà không cần đặt lại trở lại 1.

Đi vào cơ sở dữ liệu bằng API Django tôi đã kiểm tra và các phiên bản cũ đã biến mất, nhưng thậm chí thêm các phiên bản mới mang lại khóa chính mà chọn lên trường hợp phiên bản đã xóa cuối cùng còn lại, thay vì 1.

Tự hỏi liệu có ai biết vấn đề ở đây không.

Trả lời

14

Như những người khác đã nêu, điều này hoàn toàn là trách nhiệm của cơ sở dữ liệu.

Nhưng bạn nên nhận ra rằng đây là hành vi mong muốn. Một ID xác định duy nhất một thực thể trong cơ sở dữ liệu của bạn. Như vậy, nó chỉ nên đề cập đến một hàng. Nếu hàng đó sau đó bị xóa, không có lý do gì bạn nên muốn một hàng mới sử dụng lại ID đó: nếu bạn đã làm điều đó, bạn sẽ tạo ra sự nhầm lẫn giữa thực thể đã bị xóa trước đây đã từng có ID đó và mới được tạo ra đã tái sử dụng nó. Không có điểm nào trong việc này và bạn không nên làm như vậy.

+0

Điều tôi không hiểu là tại sao phiên bản ngoại tuyến không hoạt động theo cách tương tự như phiên bản trực tuyến. – pj2452

+0

sử dụng các bài kiểm tra đơn vị cần tạo ra dữ liệu thử nghiệm nhất định trong cơ sở dữ liệu sẽ là một trường hợp, trừ khi bạn muốn tạo một bảng mới với mọi thử nghiệm. – Mehdi

+0

Bạn đang sử dụng cùng một cơ sở dữ liệu trong phát triển như trong sản xuất? Trong sqlite cụ thể giải phóng các phím của các đối tượng đã xóa để tái sử dụng (không may, nếu bạn phụ thuộc vào tính duy nhất của khóa). https://sqlite.org/autoinc.html – DylanYoung

3

Bạn đã thực sự thả chúng từ cơ sở dữ liệu của mình hay bạn đã xóa chúng bằng cách sử dụng Django? Django sẽ không thay đổi AUTO_INCREMENT cho bảng của bạn chỉ bằng cách xóa các hàng từ nó, vì vậy nếu bạn muốn thiết lập lại từ khóa chính của bạn, bạn có thể phải đi vào db của bạn và:

ALTER TABLE <my-table> AUTO_INCREMENT = 1; 

(Điều này giả định bạn đang sử dụng MySQL hoặc tương tự).

+0

Cảm ơn. Tôi đã xóa các trường hợp thông qua trang quản trị Django. Điều này có thể không được thực hiện thông qua API Django? – pj2452

+0

Không xa như tôi biết - nhưng hãy xem câu trả lời của @ knbk để xóa và tạo lại bảng bằng cách sử dụng 'manage.py'. Trừ khi bạn thực sự cần các khóa chính để có giá trị cụ thể, tốt hơn là không lo lắng về chúng, không bắt đầu từ 1. – xnx

+0

Như đã nói ở trên, chính sách thế hệ pk ít liên quan đến Django, trừ khi DB không hỗ trợ tăng tự động gốc . Phần cuối của cơ sở dữ liệu sẽ xác định cách các phím được tái chế. – DylanYoung

17

Tôi sẽ không gọi đây là vấn đề. Đây là hành vi mặc định cho nhiều hệ thống cơ sở dữ liệu. Về cơ bản, bộ đếm tự động tăng cho một bảng là liên tục và việc xóa các mục không ảnh hưởng đến bộ đếm. Giá trị thực tế của khóa chính không ảnh hưởng đến hiệu suất hoặc bất kỳ thứ gì, nó chỉ có giá trị thẩm mỹ (nếu bạn đạt đến giới hạn 2 tỷ bạn sẽ có nhiều khả năng phải lo lắng).

Nếu bạn thực sự muốn đặt lại bộ đếm, bạn có thể thả và tạo lại bảng:

python manage.py sqlclear <app_name> > python manage.py dbshell 

Hoặc, nếu bạn cần phải giữ cho dữ liệu từ các bảng khác trong ứng dụng, bạn có thể tự thiết lập lại bộ đếm :

python manage.py dbshell 
mysql> ALTER TABLE <table_name> AUTO_INCREMENT = 1; 

lý do có thể xảy ra nhất mà bạn nhìn thấy hành vi khác nhau trong ẩn của bạn và các ứng dụng trực tuyến, đó là giá trị auto-increment chỉ được lưu trữ trong bộ nhớ, không phải trên đĩa. Nó được tính toán lại là MAX(<column>) + 1 mỗi khi máy chủ cơ sở dữ liệu được khởi động lại. Nếu bảng trống, nó sẽ được đặt lại hoàn toàn khi khởi động lại. Điều này có thể rất thường xuyên đối với môi trường ngoại tuyến của bạn và không gần với môi trường trực tuyến của bạn.

+0

Cảm ơn. Tôi đã chỉ tò mò tại sao tôi thấy chức năng khác nhau giữa các phiên bản trực tuyến/ngoại tuyến của tôi. – pj2452

+0

@ pj2452 Bạn đang sử dụng công cụ cơ sở dữ liệu nào ngoại tuyến? – knbk

+0

@ pj2452 Nvm, có thể vì máy chủ cơ sở dữ liệu trong môi trường ngoại tuyến của bạn thường được khởi động lại. Tôi đã cập nhật câu trả lời của mình để phản ánh điều đó. – knbk

3

Không có vấn đề gì, đó là cách cơ sở dữ liệu hoạt động. Django không có bất cứ điều gì để làm với id tạo ra nó chỉ nói với cơ sở dữ liệu để chèn một hàng và nhận được id trong phản ứng từ cơ sở dữ liệu. Id bắt đầu từ 1 cho mỗi bảng và gia số mỗi khi bạn chèn một hàng. Việc xóa các hàng không khiến id quay trở lại. Bạn không nên thường xuyên quan tâm đến điều đó, tất cả những gì bạn cần biết là mỗi hàng có một id duy nhất.
Tất nhiên, bạn có thể thay đổi bộ đếm tạo id cho bảng của bạn bằng lệnh cơ sở dữ liệu và tùy thuộc vào hệ thống cơ sở dữ liệu cụ thể mà bạn đang sử dụng.

+0

Như đã nhận xét ở trên, tôi hiểu rằng đây là hành vi mặc định nhưng tôi không hiểu lý do tại sao ngoại tuyến/trực tuyến khác nhau. – pj2452

+0

Cơ sở dữ liệu cục bộ của bạn sẽ hoạt động giống hệt nhau và sẽ không gán lại id. Bạn có thể đã tạo lại toàn bộ cơ sở dữ liệu của bạn. – nima

+0

sqlite có id + 1 cao nhất hiện có để câu trả lời này không hoàn toàn chính xác. Việc xóa hàng có id cao nhất sẽ khiến cùng một id được sử dụng cho hàng được tạo tiếp theo. – DylanYoung

0

Tôi không chắc chắn khi điều này đã được bổ sung, nhưng lệnh quản lý sau đây sẽ xóa tất cả dữ liệu từ tất cả các bảng và sẽ thiết lập lại các quầy tự động tăng đến 1.

./manage.py sqlflush | psql DATABASE_NAME 
+1

Hầu như: nó xóa tất cả dữ liệu từ tất cả các bảng * ngoại trừ * bảng di chuyển, được lưu giữ vì các lý do rõ ràng (lệnh này tồn tại đặc biệt để bảo toàn bảng di chuyển. cần được bảo quản sau đó bạn không cần phải tuôn ra, bạn chỉ cần một dropdb + createdb, tiếp theo là 'quản lý di chuyển') –

+0

Điểm tốt, cảm ơn cho làm rõ! –

1

Nếu bạn đang sử dụng SQLite bạn có thể đặt lại khóa chính bằng các lệnh shell sau:

XÓA TỪ bạn; XÓA TỪ SQLite_sequence WHERE name = 'your_table';

Các vấn đề liên quan