pythondjangodjango-class-based-viewscreate-view

Django: Object is not saved to DB when submitting form with CreateView


I have a CreateView to create artists but when submitting the form, nothing happens.

models.py

class Artist(models.Model):
    name = models.CharField(max_length=222, unique=True)
    slug = models.SlugField(unique=True, null=True)
    age = models.PositiveIntegerField(null=True,blank=True)
    location = models.CharField(max_length=222, null=True, blank=True)
    bio = models.TextField(null=True,blank=True)
    booking_fee_per_hour = models.PositiveIntegerField(verbose_name="Booking Fee per hour")

    def __str__(self):
        return self.name

views.py

class ArtistsAddView(views.CreateView):
    template_name = 'add_artist.html'
    model = Artist
    fields = '__all__'
    success_url = '/'

templates -> add-artist.html

<form method="post" action="{% url 'artist add' %}">
    <p>{{ form.name.label_tag }} {{ form.name }}</p>
    <p>{{ form.age.label_tag }} {{ form.age }}</p>
    <p>{{ form.location.label_tag }} {{ form.location }}</p>
    <p>{{ form.bio.label_tag }} {{ form.bio }}</p>
    <input type="hidden" name="next" value="{{ next }}">
    <button>Submit</button>
    {% csrf_token %}
</form>

I intentionally hid 2 of the fields: slug and booking_fee_per_hour. I would like to make them available only for admins.

If I write:

<form method="post" action="{% url 'artist add' %}">
    {{ form.as_p }}
    <input type="hidden" name="next" value="{{ next }}">
    <button>Submit</button>
    {% csrf_token %}
</form>

then the artist is saved to the DB but also the normal user can see slug and booking_fee_per_hour.

Could you please help me?


Solution

  • I think that as the add-artist.html template does not include some fields that are mandatory like slug & booking_fee_per_hour (no blank=True, null = True), the generic CreateView cannot saves the model.

    Here are several workarounds depending on your app concerns and what is easy to do for you:

    1. Make fields optional in the model (blank=True, null = True) & populate them later with the correct values

    2. Provide default values for those fields in the model (default=...)

    3. provide default values in the template with hidden fields <input type="hidden" name="booking_fee_per_hour" value="????">

    4. provide default values in the view. For example you can override the post method of the class and providing values on the fly when saving. https://docs.djangoproject.com/en/4.1/ref/class-based-views/mixins-editing/#django.views.generic.edit.ProcessFormView

    class ArtistsAddView(views.CreateView):
        template_name = 'add_artist.html'
        model = Artist
        fields = '__all__'
        success_url = '/'
        
        def post(request, *args, **kwargs)
            post_data = request.POST.copy()  # make post data mutable
            # Add the needed data
            post_data['booking_fee_per_hour'] = ...
            ... 
            # save
            request.POST = post_data
            super().post(request,  *args, **kwargs)