Tony
Tony

Reputation: 2482

Django - Limiting the amount of objects created to 3 and being able to update them.

My goal is to be able to limit the amount of models created to 3 and being able to UPDATE them.

my model.py is as follows:

class FeatureteImage(models.Model):
    park = models.ForeignKey(Park)
    header = models.CharField(max_length=50, blank=True)
    body = models.TextField(max_length=250, blank=True)
    image = models.ImageField(upload_to='featureteimages')

def get_absolute_url(self):
    return reverse('park-features', kwargs={'pk': self.park.pk,})


def save(self, *args, **kwargs):
    park = Park.objects.get(id=self.park.id)
    if park.featurete >= 3:
        pass
    else:
        park.featurete += 1
        park.save()
    super(FeatureteImage, self).save(*args, **kwargs) 

def delete(self, *args, **kwargs):
    park = Park.objects.get(id=self.park.id)
    if park.featurete > 0:
        park.featurete -= 1
        park.save()
        super(FeatureteImage, self).delete(*args, **kwargs)
    else:
        pass

def get_absolute_url(self):
    park = Park.objects.get(id=self.park.id)
    return reverse('park-features', kwargs={'pk': self.park.pk})

As you can see I am trying to limit the amount of featurete's park. So just 3 of them. I overwrote the custom save() so that if a park has 3 featuretes they can't add more.

But this still passes and still saves the new Featurete model. But it does update the model.

First I tried:

def save(self, *args, **kwargs):
    park = Park.objects.get(id=self.park.id)
    if park.featurete >= 3:
        pass
    else:
        park.featurete += 1
        park.save()
        super(FeatureteImage, self).save(*args, **kwargs) 

my views.py:

class AddFeaturete(generic.CreateView):
    template_name = 'images/addfeaturete.html'
    model = FeatureteImage
    fields = ['header', 'body', 'image']

    def form_valid(self, form):
        self.venue = get_object_or_404(Park, pk=self.kwargs['pk'])
        form.instance.park = self.park
        return super(AddFeaturete, self).form_valid(form)

class UpdateFeaturete(generic.UpdateView):
    template_name = 'images/updatefeaturete.html'
    model = FeatureteImage
    fields = ['header', 'body', 'image']

    def get_object(self):
        return get_object_or_404(FeatureteImage, pk=self.kwargs['f_pk'])

    def form_valid(self, form):
        return super(UpdateFeaturete, self).form_valid(form)

But when I tried to update the model it did not save the changes because the park had already 3 features and it just passes.

What do you think is the best way to work through this? I appreciate all your answers.

Upvotes: 0

Views: 229

Answers (3)

Alex Polekha
Alex Polekha

Reputation: 1700

def save(self, *args, **kwargs):
    if self.park.featureteimage_set.exclude(pk=self.pk).count() >= 3:
        raise ValidationError('too much featuretes')
    super(FeatureteImage, self).save(*args, **kwargs) 

Upvotes: 1

NEOatNHNG
NEOatNHNG

Reputation: 934

The problem is that if you do reference counting then you have to act only if the park attribute of the Featurette was changed, not if the object was updated in some other way. You can solve that in two ways:

  1. You get rid of the reference counting all together and just use the power of your relational data base to see how many objects there are
  2. You detect whether the park attribute was changed by retrieving the version from the data base and comparing to that

I think the first version would be more elegant if you do not need the count very often as it saves the whole delete logic.

Note: currently your code has the additional problem that the reference counter doesn't only need to be decremented on deletion, but also when an update changes the park. I don't know if that could be a problem in your use case.

The save() method with the first solution would look like this and you could get rid of the delete logic:

def save(self, *args, **kwargs):
    count = self.objects.filter(park=self.park).exclude(pk=self.pk).count()
    if not count < 3:
        raise ValidationError('A park may not contain more than 3 featuretes')
    super(FeatureteImage, self).save(*args, **kwargs) 

Upvotes: 0

Vahid Msm
Vahid Msm

Reputation: 1082

Your code will pass in if condition and then call super of the model that is normal behavior of save function. Simply just say:

def save(self, *args, **kwargs):
    park = Park.objects.get(id=self.park.id)
    if self.pk: #update if it exists
        super(FeatureteImage, self).save(*args, **kwargs) 
    elif park.featurete < 3:
        park.featurete += 1
        park.save()
        super(FeatureteImage, self).save(*args, **kwargs) 
    else:
        return

Upvotes: 0

Related Questions