One Object per User in a Model

Sometimes, just sometimes, we want our users to add only one object per user per model. As in, when they add an object to a model, the can only add another object, ONLY after their first object is deleted.

Let’s jump right into some code. Let’s use this model as an example:

class Package(TimeStampedModel):
    name = models.CharField(max_length=500)
    weight = models.IntegerField()
    createdBy = models.ForeignKey(User, on_delete=models.CASCADE)

At any point in time, I want to ensure a user only has only a single Package object in the model.

Check my article about Extending the Django User Model like a Pro.

A Possible Approach

class PackageAdd(LoginRequiredMixin, CreateView):
  model = Travel
  fields = ['name', 'weight']

  def form_valid(self, form):
    form.instance.createdBy = self.request.user
    return super(PackageAdd, self).form_valid(form)

  def get_context_data(self):
    context = super(PackageAdd, self).get_context_data()
    context['is_having_package'] = Package.objects.filter(createdBy=self.request.user).exists()
    return context

Here’s the logic behind the approach above:

This context variable can, therefore, be checked in the template and used in rendering the template for sending to the client.

So, in the template, we can trap and make a decision with the context data in a way like this:

    <!-- Using Bootstrap 4 -->
    <div class="card">
        <div class="card-block">
          {{ is_having_package|yesno:"How about a package at a time?,Add your Package" }}

          {% if not is_having_package %}
          <form class="" method="POST" action="">
            {% csrf_token %} {% bootstrap_form form %}
            <div class="form-group">
              <input type="submit" role="button" name="Save" value="Add Package" class="btn btn-primary">
            </div>
          </form>
          {% else %}
            <p class="lead">
              You have a package listed already. Clear it first before adding another package.
            </p>
          {% endif %}
        </div>
      </div>
    </div>

If you’re wondering what all that yesno magic was about, well, you can think of it as same as:

<h4 class="card-title">
{% if not is_travel_pending %}
   How about a travel a time?
{% else %}
   Add your Travel
{% endif %}</h4>

except the yesno built-in Django tag is just too clean to not use! However, it ain’t a magic bullet for all if/else scenarios, since it is designed for strings.

“Maps values for True, False, and (optionally) None, to the strings “yes”, “no”, “maybe”, or a custom mapping passed as a comma-separated list, and returns one of those strings according to the value”

Downsides to Approach

Conclusion

I hope you found this straightforward approach useful. I hope to catch you in the next one.

Exit mobile version