2015-02-16 7 views
9

Nesnenin silinmesinden önce bir nesneyi silme işleminin ele alınması için en iyi yaklaşım nedir? Örneğin, kurulumumda iki model var - Game ve Team (ki bunlar açıkça alakalı). Kullanıcılar sadece herhangi bir oyuna bağlı olmayan takımları silebilmelidir. Örnek silme işlemini gerçekleştirmeden önce DeleteView kullanarak doğrulama

Bir takım silme (herhangi bir alanlar olmadan) bir form ...

class TeamDeleteForm(ModelForm): 
    class Meta: 
     model = Team 
     fields = [] 

    def clean(self): 
     # Check to see if this team is tied to any existing games 
     if self.instance.gameteams_set.exists(): 
      raise ValidationError("This team is tied to 1 or more games") 
     return super().clean() 

oluşturulan Ama sonra sınıf temelli bakış DeleteView form_valid() yöntemi her türlü sahip olmadığını fark etti. DeleteView yerine genel FormView'i uzatmalı mıyım yoksa eksik olduğum daha iyi bir yaklaşım mı var?

+0

Aşağıdaki cevabıma bir göz attınız mı? –

+0

@SimonCharette Yaptım teşekkürler. Ancak, FormView kullanarak daha iyi bir çözüm olduğunu düşünüyorum. Hala ideal değil ve çözümümüzü göndermeden önce başka birinin cevap vereceğini görmek için bekliyorum. – Ben

cevap

8

En iyi yaklaşımın modelin silme yöntemini geçersiz kılacağını düşünüyorum.Örneğin,

class Team(models.Model): 
    ... 
    def delete(self, *args, **kwargs): 
     if Game.objects.filter(team__pk= self.pk).exists(): 
      raise Exception('This team is related to a game.') 
     super().delete(*args, **kwargs) 
+4

Bu kabul edilen çözüm nasıl olabilir? Bu işlenmemiş bir istisna yükselttiğiniz için 500 hatasıyla sonuçlanacaktır ... –

+1

Anlaşılan, bence @Esteban'ın verdiği cevap en iyisidir. En doğrudan soruyu cevaplıyor. – jaywhy13

+0

Daha iyi bir kullanıcı deneyimi için, İstisna() yerine, HttpResponseForbidden() öğesini döndürebilirsiniz – acidjunk

6

Özel durumunuz için, s ile ilgili Game s ürününü hariç tutmak için görünümünüzün queryset özniteliğini geçersiz kılmş olurdum.

class TeamDeleteView(DeleteView): 
    queryset = Team.objects.distinct().exclude(games__isnull=False) 

Orada bir Django ticket opened to make the DeleteView behave like other form views ama the proposed patch kadar (Bu 1.8 bunu yapmaz) tamamen aşağıdaki gibi bakış delete yöntemini geçersiz gerekecek birleşti ve serbest bırakılır:

class TeamDeleteView(DeleteView): 
    model = Team 

    def delete(request, *args, **kwargs): 
     self.object = self.get_object() 
     if self.object.gameteams_set.exists(): 
      # Return the appropriate response 
     success_url = self.get_success_url() 
     self.object.delete() 
     return HttpResponseRedirect(success_url) 

Düzenleme:

Kabul ettiğiniz çözümden, model düzeyinde silmeyi önlemeye çalıştığınız anlaşılıyor. Bu yaptırım, bir PROTECTon_delete işleyicisi kullanılarak yapılmalıdır.

from django.db import models 

class Team(models.Model): 
    pass 

class Game(models.Model): 
    team = models.ForeignKey(Team, on_delete=models.PROTECT) 

Hala görünümünde kaldırdı ProtectedError uğraşmak gerekecek: yönetici yaptığı gibi daha anlamlı bir hata iletisi görüntülemek için

from django.db import models 
from django.http.response import HttpResponseForbidden 

class TeamDeleteView(DeleteView): 
    model = Team 

    def delete(request, *args, **kwargs): 
     try: 
      return super(TeamDeleteView, self).delete(
       request, *args, **kwargs 
      ) 
     except models.ProtectedError as e: 
      # Return the appropriate response 
      return HttpResponseForbidden(
       "This team is tied to 1 or more games" 
      ) 

Hatta e ait protected_objects özelliğini kullanabilirsiniz .

+0

Ya bunu Django'nun Yöneticisiyle yapmak istersen? – Gocht

+0

Django'nun yöneticisi bu hatalarla otomatik olarak ilgilenir: [1.10+] (https://github.com/django/django/commit/a7c813ba045044ec23bb656ef9a23a0e38e36514) ancak 'ModelAdmin' alt sınıfınızın 'delete_selected' yöntemini, eğer yapabiliyorsanız benzer şekilde geçersiz kılabilirsiniz ' Bu sürümü kullanmayın. –

6

Bu senaryo için hem DeleteView hem de FormView kullandım. Her ikisinin de artıları ve eksileri var.

DeleteView, SingleObjectMixin'i temel aldığından ve silmek istediğiniz nesneye kolayca erişebildiğiniz için güzeldir. Bunu yapmanın iyi bir yolu, get_object'de bir istisnayı yükseltmektir. Bu, hem alın hem de yayınlamak için istisna oluşturabilmenizi sağlar. Eğer form_invalid kaldıraç ve temiz yöntemler, ama o zaman yine nesneyi, kurulum (değil deleteview gerekli) formun çeşit olsun iş yapmak zorunda çünkü

def get_object(self, qs): 
    obj = super(FooView, self).get_object(qs) 
    if obj.can_delete(): 
    return obj 
    raise PermissionDenied 

FormView güzel.

Gerçekten bununla nasıl başa çıkmak istediğinizi sorun. Diğer bazı sorular şunlardır: GET'de bir istisna oluşturuyor musunuz, yoksa kullanıcıya nesneyi silemediklerini bildiren güzel bir sayfa göstermek ister misiniz? Bu, her iki Görünüm türünde de yapılabilir.

Eğer gözden geçirmek için daha fazla puanınız varsa sorunuzu güncelleyin ve cevabımı güncelleyeceğim.