2010-02-13 50 views
6

Tôi có một phương pháp vào mẫu đăng ký người dùng của tôi trông như thế này:Django thác tiết kiệm?

def save(self): 
    user = User(
     username = self.cleaned_data['username'], 
     email = self.cleaned_data['email1'], 
     first_name = self.cleaned_data['first_name'], 
     last_name = self.cleaned_data['last_name'], 
    ) 
    user.set_password(self.cleaned_data['password1']) 
    user.profile = Profile(
     primary_phone = self.cleaned_data['phone'], 
    ) 
    user.profile.address = Address(
     country = self.cleaned_data['country'], 
     province = self.cleaned_data['province'], 
     city = self.cleaned_data['city'], 
     postal_code = self.cleaned_data['postal_code'], 
     street1 = self.cleaned_data['street1'], 
     street2 = self.cleaned_data['street2'], 
     street3 = self.cleaned_data['street3'], 
    ) 
    user.save() 
    return user 

Vấn đề là khi tôi gọi form.save() nó tạo ra đối tượng user như mong đợi, nhưng không lưu hồ sơ hoặc địa chỉ của mình. Tại sao nó không xếp và lưu tất cả các mô hình phụ? Tôi nghi ngờ tôi có thể gọi user.profile.save()user.profile.address.save() theo cách thủ công, nhưng tôi muốn toàn bộ điều để thành công hoặc thất bại cùng nhau. Cách tốt nhất để làm điều này là gì?


giải pháp hiện tại:

def save(self): 
    address = Address(
     country = self.cleaned_data['country'], 
     province = self.cleaned_data['province'], 
     city = self.cleaned_data['city'], 
     postal_code = self.cleaned_data['postal_code'], 
     street1 = self.cleaned_data['street1'], 
     street2 = self.cleaned_data['street2'], 
     street3 = self.cleaned_data['street3'], 
    ) 
    address.save() 

    user = User(
     username = self.cleaned_data['username'], 
     email = self.cleaned_data['email1'], 
     first_name = self.cleaned_data['first_name'], 
     last_name = self.cleaned_data['last_name'], 
    ) 
    user.set_password(self.cleaned_data['password1']) 
    user.save() 

    profile = Profile(
     primary_phone = self.cleaned_data['phone'], 
    ) 
    profile.address = address 
    profile.user = user 
    profile.save() 

tôi bị buộc phải profile các "trung tâm" đối tượng. Cần thiết để thiết lập profile.user = user thay vì user.profile = profile để làm cho nó hoạt động (tôi đoán bởi vì khóa là trên mô hình hồ sơ, không phải trên mô hình người dùng). giải pháp


Mới hơn:

Tôi mất một gợi ý từ this article đề xuất trong this answer.

Bây giờ tôi đã tách ra hình thức mô hình của tôi và chuyển logic vào xem:

def register(request): 
    if request.POST: 
     account_type_form = forms.AccountTypeForm(request.POST) 
     user_form = forms.UserForm(request.POST) 
     profile_form = forms.ProfileForm(request.POST) 
     address_form = forms.AddressForm(request.POST) 

     if user_form.is_valid() and profile_form.is_valid() and address_form.is_valid(): 
      user = user_form.save() 
      address = address_form.save() 
      profile = profile_form.save(commit=False) 
      profile.user = user 
      profile.address = address 
      profile.save() 
      return HttpResponseRedirect('/thanks/') 
    else: 
     account_type_form = forms.AccountTypeForm() 
     user_form = forms.UserForm() 
     profile_form = forms.ProfileForm() 
     address_form = forms.AddressForm() 

    return render_to_response(
     'register.html', 
     {'account_type_form': account_type_form, 'user_form': user_form, 'address_form': address_form, 'profile_form': profile_form}, 
     context_instance=RequestContext(request) 
    ) 

Tôi không quá ngây thơ của chuyển gánh nặng để xem, nhưng tôi đoán tôi có được một cách linh hoạt hơn chút này đường?

+0

Chương trình vui vẻ tuyệt vời! – jathanism

Trả lời

5

Nó không xếp tầng tiết kiệm vì nó không thực sự biết có hay không các đối tượng khác cần để được lưu.

Để làm điều đó chỉ trong một bước, đầu tiên start a transaction:

@transaction.commit_on_success 
def save(self): 
    .... 

Sau đó lưu subobjects theo thứ tự:

user.profile.address.save() 
    user.profile.save() 
    user.save() 
+0

Tại sao nó không thể tìm ra nếu chúng cần được lưu?Họ thậm chí không có 'id' nào được nêu ra ... đó là một kiểm tra dễ dàng. Có thực sự cần thiết để sử dụng các giao dịch cho một cái gì đó rất đơn giản? Tôi đã có tất cả các loại vấn đề với các giao dịch che dấu các lỗi khác. – mpen

+0

Việc thiết lập PK không đủ để xác định rằng một đối tượng không nên được lưu. Hoặc PK có thể bị ép buộc hoặc đối tượng có thể cần cập nhật, cả hai đều yêu cầu một cuộc gọi đến 'save()'. –

+0

Ồ ... và vấn đề lớn hơn là 'profile.user_id' không thể rỗng. 'profile.user_id' không bao giờ được thiết lập, mặc dù' profile' là một thuộc tính của 'user' ... – mpen

1

Vấn đề là bạn đang cố gắng để tạo ra hoặc các lĩnh vực cập nhật trong một Đối tượng người dùng chưa tồn tại. Vì vậy, các trường khác không thực sự được cập nhật vì chúng không được liên kết với bất kỳ khóa chính nào của các trường con.

Mỗi khi bạn khởi tạo trường mô hình mới, bạn phải đảm bảo bạn đang lưu để trường mô hình con có id (khóa chính) để liên kết.

Bạn cần một cái gì đó như thế này:

def save(self): 
    user = User(
     username = self.cleaned_data['username'], 
     email = self.cleaned_data['email1'], 
     first_name = self.cleaned_data['first_name'], 
     last_name = self.cleaned_data['last_name'], 
    ) 
    ## save user so we get an id 
    user.save() 

    ## make sure we have a user.id 
    if user.id: 
     ## this doesn't save the password, just updates the working instance 
     user.set_password(self.cleaned_data['password1']) 
     user.profile = Profile(
      primary_phone = self.cleaned_data['phone'], 
     ) 
     ## save the profile so we get an id 
     user.profile.save() 

    ## make sure we have a profile.id 
    if user.profile.id: 
     user.profile.address = Address(
      country = self.cleaned_data['country'], 
      province = self.cleaned_data['province'], 
      city = self.cleaned_data['city'], 
      postal_code = self.cleaned_data['postal_code'], 
      street1 = self.cleaned_data['street1'], 
      street2 = self.cleaned_data['street2'], 
      street3 = self.cleaned_data['street3'], 
     ) 
     ## save the profile address 
     user.profile.address.save() 

    ## final save to commit password and profile changes 
    user.save() 
    return user 

này tầng save() điều bạn đã xảy ra ở đây chỉ không cảm thấy đúng. Bạn dễ bị quá nhiều lỗi ở đó, nếu bất kỳ trường nào không lưu, bạn sẽ kết thúc với một cá thể người dùng hoàn thành một phần và kết thúc một cách posisbly với các bản sao nếu người dùng phải quay lại và thử lại. Không vui!

Chỉnh sửa: Xóa nửa thứ hai của điều này vì nó không chính xác.

+0

Có vẻ tốt hơn bởi vì bạn đã không đăng nội bộ của UserFormSet, bạn đã đăng phương thức xem, trông giống hệt với những gì tôi có bây giờ. Tôi sẽ phải nhìn vào các formets sâu hơn để xem chúng có phải là lựa chọn đúng đắn hay không. Tôi luôn nghĩ về chúng như đang được sử dụng để tạo ra nhiều đối tượng cùng một lúc, không có nhiều hình thức để tạo ra một đối tượng. Ý tưởng xếp tầng của tôi nhằm mục đích ngăn chặn các bản sao bằng cách lưu tất cả hoặc không cùng nhau, do đó chỉ có một cuộc gọi đến 'save()'. – mpen

+0

Vâng, bạn đúng về điều đó. Tôi không biết mình đang nghĩ gì! Tôi sẽ loại bỏ nửa sau khỏi câu trả lời. – jathanism

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