I have the following form to create new clients on a database on Django and rendered using crispyforms. However, even thoug it is rendered correctly, it's not creating new entries.
models.py
class Client (models.Model):
def __str__(self):
return self.name + ' '+ self.surname
name = models.CharField(max_length=120)
surname = models.CharField(max_length=120, null=True)
phone = models.PositiveIntegerField(null=True)
mail = models.EmailField(null=True)
sport = models.TextField(blank=True, null=True)
gender_options=(
("F", "femenino"),
("M", "masculino"),
)
gender = models.CharField(max_length=120, null=True, choices=gender_options)
birth = models.DateField(null=True)
def get_absolute_url(self):
return reverse("clientes:cliente", kwargs={"client_id": self.id})
pass
forms.py
from django import forms
from .models import Client
class NewClientForm(forms.Form):
name = forms.CharField(label='Nombres')
surname = forms.CharField(label='Apellidos')
phone = forms.CharField(label='Teléfono')
mail = forms.EmailField(label='Correo electrónico')
gender = forms.ChoiceField(label='Género', choices= Client.gender_options)
birth = forms.DateField(label='Fecha de nacimiento', widget=forms.TextInput(attrs={
'id': "datepicker",
}))
sport = forms.CharField(label='Deportes')
views.py
def new_client_view(request):
new_client_form = NewClientForm()
if request.method == "POST":
new_client_form = NewClientForm(request.POST)
if new_client_form.is_valid():
Client.objects.create(**new_client_form.cleaned_data)
else:
print(new_client_form.errors)
context = {
"form": new_client_form
}
return render (request, 'clients/new-client.html', context)
html
{% extends 'base.html' %}
{% load bootstrap4 %}
{% load crispy_forms_tags %}
{% block content %}
<h1>Nuevo cliente</h1>
<section class="container">
<form action="." method="POST" class="form-floating mb-3"> {%csrf_token%}
<div class="form-row">
<div class="form-group col-md-6 mb-0">
{{ form.name|as_crispy_field }}
</div>
<div class="form-group col-md-6 mb-0">
{{ form.surname|as_crispy_field }}
</div>
<div class="form-group col-md-6 mb-0">
{{ form.phone|as_crispy_field }}
</div>
<div class="form-group col-md-6 mb-0">
{{ form.mail|as_crispy_field }}
</div>
<div class="form-group col-md-6 mb-0">
{{ form.sport|as_crispy_field }}
</div>
<div class="form-group col-md-6 mb-0">
{{ form.gender|as_crispy_field }}
</div>
<div class="form-group col-md-6 mb-0">
{{ form.birth|as_crispy_field }}
</div>
</div>
<input class="btn btn-primary" type="submit" name="Save">
</form>
</section>
{% endblock content %}
Form is correctly rendered, but when the form is sent, no new entry is created. I can't get why. For me everything should be working.
I tried replicating your project twice, both times I had no issue copying your code directly. It works fine for me. I set up a couple of print statements in the view:
from django.shortcuts import render
from .forms import NewClientForm
from .models import Client
# Create your views here.
def new_client_view(request):
new_client_form = NewClientForm()
print('request method: ', request.method)
if request.method == "POST":
new_client_form = NewClientForm(request.POST)
if new_client_form.is_valid():
Client.objects.create(**new_client_form.cleaned_data)
print('new client created')
else:
print(new_client_form.errors)
context = {
"form": new_client_form
}
return render (request, 'clients/new-client.html', context)
This is what I see on the new client form page:
This is what I see on the command line as I visit the page and submit the form:
As you can see, once I visit the page, the view receives a GET request, which makes sense, and which I see from your comment that you're seeing too. Once I hit "Submit" the view receives a POST request, which then creates a new Client object.
I used the Django shell to confirm that the Client object was indeed created:
So your code is fine, it may have something to do with the way you're filling up your form, or maybe a browser issue, I can't really tell.
Related
I have a contact form in Django, and I use crispy in my template, but in both the Class base view and Function base view, my submit button is not working, and I have no errors.
here is my fbv code. I also tried it with cbv
my template is using jquery,bootstrap,moment.js
here is my code:
models.py
class ContactUs(models.Model):
fullname = models.CharField(max_length=150, verbose_name="Full Name")
email = models.EmailField(max_length=150, verbose_name="Email")
message = models.TextField(verbose_name="Message")
is_read = models.BooleanField(default=False)
class Meta:
verbose_name = "contact us"
verbose_name_plural = "Messages"
forms.py:
class CreateContactForm(forms.Form):
fullname = forms.CharField(widget=forms.TextInput(attrs={"placeholder": "Full Name"}),
validators=[
validators.MaxLengthValidator(150,
"Your name should be less than 150 character")
],
)
email = forms.EmailField(widget=forms.EmailInput(attrs={"placeholder": "Email address"}),
validators=[
validators.MaxLengthValidator(150,
"Your email should be less than 150 character")
],
)
message = forms.CharField(widget=forms.Textarea(attrs={"placeholder": "Your Message"}))
views.py:
def contact_page(request):
contact_form = CreateContactForm(request.POST or None)
if contact_form.is_valid():
fullname = contact_form.cleaned_data.get('fullname')
email = contact_form.cleaned_data.get('email')
message = contact_form.cleaned_data.get('message')
ContactUs.objects.create(fullname=fullname, email=email, message=message, is_read=False)
# todo : show user a success message
contact_form = CreateContactForm(request.POST or None)
context = {"contact_form": contact_form}
return render(request, 'contact_page.html', context)
Template:
<form id="contact-form" class="contact-form" data-toggle="validator" novalidate="true" method="post" action="">
{% csrf_token %}
<div class="row">
<div class="form-group col-12 col-md-6">
{{ contact_form.fullname|as_crispy_field }} {% for error in contact_form.fullname.errors %}
<div class="help-block with-errors">{{ error }}</div>
{% endfor %}
</div>
<div class="form-group col-12 col-md-6">
{{ contact_form.email|as_crispy_field }} {% for error in contact_form.email.errors %}
<div class="help-block with-errors">{{ error }}</div>
{% endfor %}
</div>
<div class="form-group col-12 col-md-12">
{{ contact_form.message|as_crispy_field }} {% for error in contact_form.message.errors %}
<div class="help-block with-errors">{{ error }}</div>
{% endfor %}
</div>
</div>
<div class="row">
<div class="col-12 col-md-6 order-2 order-md-1 text-center text-md-left">
<div id="validator-contact" class="hidden"></div>
</div>
<div class="col-12 col-md-6 order-1 order-md-2 text-right">
<button type="submit" name="submit" class="btn"><i class="font-icon icon-send"></i> Send Message</button>
</div>
</div>
</form>
Try adding "save" to the submit button class.
Also your contact_page view does nothing after saving the contact data to the db. If you'll do a pop-up confirmation in JS you don't need to instantiate contact_form the second time. Or if you want to redirect the user:
def contact_page(request):
contact_form = CreateContactForm(request.POST or None)
if contact_form.is_valid():
fullname = contact_form.cleaned_data.get('fullname')
email = contact_form.cleaned_data.get('email')
message = contact_form.cleaned_data.get('message')
ContactUs.objects.create(
fullname=fullname,
email=email,
message=message,
is_read=False
)
return redirect('some-view')
context = {"contact_form": contact_form}
return render(request, 'contact_page.html', context)
im new to Django. Im creating a bidding site, where users should be able to visit a page to create a new listing (item that they are going to put up).The form that they are required to submit has a few common fields and when valid, the said form should be saved.
Problem is, my listingcreateview() is not doing that. I submit a correct form but it wont save, it just redirects to the same form page and No errors are shown.
This because the submitted form is validated as invalid every time. I know this because of the two functions i added inside listingcreateview(), the second one is called.
It was working properly before, dont know what changes messed it up. If i add in the admin interface information by hand, it is saved successfully.
views.py:
class ListingCreateView(CreateView):
model = Listing
fields = ['title', 'content', 'image', 'min_bid', 'categories']
def form_valid(self, form):
form.instance.seller = self.request.user
return super().form_valid(form)
def form_invalid(self, form):
return HttpResponseRedirect(reverse("index"))
models.py:
class User(AbstractUser):
pass
class Listing(models.Model):
id = models.IntegerField(primary_key=True)
title = models.CharField(max_length=100)
image = models.ImageField(blank=False, upload_to='media')
content = models.TextField()
date_posted = models.DateTimeField(default=timezone.now)
categories = models.CharField(max_length=25, choices = category)
seller = models.ForeignKey(User, on_delete=models.CASCADE) ##
min_bid = models.FloatField(blank=False)
image_thumbnail = ImageSpecField(source='image', processors=[ResizeToFill(300, 150)], format='JPEG', options={'quality':100})
def get_absolute_url(self):
return reverse('listing-detail', kwargs={'pk': self.pk})
listing_form.html:
{% extends "auctions/layout.html" %}
{% block body %}
<h2> Create Listing </h2>
{% if message %}
<div>{{ message }}</div>
{% endif %}
{% if messages %}
<div class="alert alert-warning" role="alert">
{{ messages }}
</div>
{% endif %}
<div class="container">
<form method="POST" action="">
{% csrf_token %}
<label class="label">{{ form.title.label }}</label>
<div class="input">{{ form.title }}</div>
<label class="label">{{ form.content.label }}</label>
<div class="input">{{ form.content }}</div>
<label class="label">{{ form.image.label }}</label>
<div class="input">{{ form.image }}</div>
<label class="label">Minimal bid</label>
<div class="input">{{ form.min_bid }}</div>
<label class="label">{{ form.categories.label }}</label>
<div class="input">{{ form.categories }}</div>
<input type="submit" value="Submit">
</form>
</div>
{% endblock %}
urls.py:
path("create-listing", login_required(ListingCreateView.as_view()), name="create-listing")
Your form is invalid because form is missing
enctype="multipart/form-data" which is needed for file uploads
I'm trying to create reservation create view that allows to break down the reservation process into 3 stages for handling all the database queries and displaying relevant choices accordingly to linkage between models (Personnel Profile has many to many key on Service)
1st stage - allows user to select service
2nd stage - displays available staff members (PersonnelProfile) who are handling this service
3rd stage - displays all the free dates / times based on staff member schedule / existing reservations, POST creates the reservation
I got stuck at the 2nd stage as my form doesn't validate. I would appreciate any advise how to overcome this issue or how to handle the idea differently. Sorry for the long post :)
UPDATE
My goal is following:
1. User selects a service
2. Backend checks which personnel profiles are offering this service and returns from to select relevant user
3. Based on selected user backend checks availability (Schedule) of user, his existing reservations and returns form for date / hour selection
4. Reservation is created after user submits from with selected hour and time
I tried to do it with additional forms to split the process in stages, as I have no idea (unfortunately I'm still a newbie) how to handle such behaviour with one form and if it's possible or not. I would appreciate any tips / guidance on how to handle this.
Reservation
class Reservation(models.Model):
user = models.ForeignKey(PersonnelProfile, on_delete=models.PROTECT)
client = models.ForeignKey(ClientProfile, on_delete=models.PROTECT)
service = models.ForeignKey(Service, on_delete=models.PROTECT)
date = models.DateField()
start_time = models.TimeField()
Service
class Service(models.Model):
name = models.CharField(max_length=100)
description = models.TextField()
price = models.IntegerField()
duration = models.IntegerField()
def __str__(self):
return self.name
PersonnelProfile
class PersonnelProfile(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
birth_date = models.DateField(default=None, null=True)
address = models.CharField(max_length=200)
services = models.ManyToManyField(Service)
image = models.ImageField(default='profile_pics/default.jpg', upload_to='profile_pics')
def __str__(self):
return f'{self.user.first_name} {self.user.last_name}'
Schedule Model
class Schedule(models.Model):
user = models.OneToOneField(PersonnelProfile, on_delete=models.CASCADE)
availability_days = models.ManyToManyField(WorkDay)
start_hour = models.TimeField()
end_hour = models.TimeField()
def __str__(self):
return f'Schedule of {self.user.user.first_name} {self.user.user.last_name}'
WorkDay Model
class WorkDay(models.Model):
day_choices = [(str(i), calendar.day_name[i]) for i in range(7)]
name = models.CharField(max_length=9, choices=day_choices, default='1', unique=True)
def __str__(self):
return self.get_name_display()
Reservation CreateView
class ReservationCreate(LoginRequiredMixin, UserPassesTestMixin, ModelFormWidgetMixin, CreateView):
model = Reservation
success_url = '/reservations'
#staticmethod
def get(request):
form = ServiceSelection()
return render(request, 'reservations/reservation_service_selection.html', context={'form': form})
#staticmethod
def post(request):
if 'service_selection' in request.POST:
form = ServiceSelection(request.POST)
if form.is_valid():
service = form.cleaned_data['select_service']
available_personnel = PersonnelProfile.objects.filter(services=service)
personnel_names = [prs.user for prs in available_personnel]
form = PersonSelection(personnel_names)
context = {
'form': form,
'service': service
}
"""
Selected service data should be saved for the 3rd stage
"""
return render(request, 'reservations/reservation_person_selection.html', context)
return HttpResponse('Service incorrect', 404)
if 'person_selection' in request.POST:
form = PersonSelection(request.POST)
if form.is_valid():
"""
Check the schedule and existing reservations
Return last form with available dates and times for service selected in stage 1
and staff member selected in 3rd stage.
3rd stage will create Reservation with all the selected details in all 3 stages
"""
return HttpResponse('Good choice', 200) #response just for tests
return render(request, 'reservations/reservation_person_selection.html', {'form': form})
def test_func(self):
if self.request.user.is_staff:
return True
return False
Forms
class ServiceSelection(forms.ModelForm):
select_service = forms.ModelChoiceField(
queryset=Service.objects.all(),
widget=forms.Select(),
empty_label='Please select a service',
to_field_name='price'
)
class Meta:
model = Service
fields = ('select_service',)
class PersonSelection(forms.ModelForm):
def __init__(self, personnel_names, *args, **kwargs):
super(PersonSelection, self).__init__(*args, **kwargs)
self.fields['user'] = forms.ChoiceField(
choices=tuple([(name, name) for name in personnel_names]),
label='Select a person'
)
class Meta:
model = PersonnelProfile
fields = 'user',
Templates :
reservation_service_selection
{% extends 'website/home.html' %}
{% load crispy_forms_tags %}
{% block content %}
<div class="content-section">
<div class="media">
<img class="rounded-circle account-img" src="/media/profile_pics/default.jpg">
<div class="media-body">
<h2 class="account-heading">Select a service</h2>
</div>
</div>
</div>
<div class="content-section">
<form method="POST" enctype="multipart/form-data">
{% csrf_token %}
<fieldset class="form-group">
{{ form|crispy }}
</fieldset>
<div class="form-group">
<button class="btn btn-outline-info" type="submit" name="service_selection">Update</button>
<input type="button" value="Go back" class="btn btn-outline-info" onclick="history.back()">
</div>
</form>
</div>
{% endblock %}
reservation_person_selection
{% extends 'website/home.html' %}
{% load crispy_forms_tags %}
{% block content %}
<div class="content-section">
<div class="media">
<img class="rounded-circle account-img" src="/media/profile_pics/default.jpg">
<div class="media-body">
<h2 class="account-heading">Select a person</h2>
</div>
</div>
</div>
<div class="content-section">
<form method="POST" enctype="multipart/form-data">
{% csrf_token %}
{% if form.errors %}
{% for field in form %}
{% for error in field.errors %}
<div class="alert alert-danger">
<strong>{{ error|escape }}</strong>
</div>
{% endfor %}
{% endfor %}
{% for error in form.non_field_errors %}
<div class="alert alert-danger">
<strong>{{ error|escape }}</strong>
</div>
{% endfor %}
{% endif %}
<fieldset disabled>
<fieldset class="form-group">
<div class="form-group">
<label for="disabledSelect">Select a service*</label>
<select id="disabledSelect" class="form-control">
<option>{{ service }}</option>
</select>
</div>
</fieldset>
</fieldset>
{{ person_form|crispy }}
<div class="form-group">
<button class="btn btn-outline-info" type="submit" name="person_selection">Update</button>
<input type="button" value="Go back" class="btn btn-outline-info" onclick="history.back()">
</div>
</form>
</div>
I am trying to use a ModelForm to save objects to the database. I have also added an ImageField. Through the admin panel, I am easily able to add objects with an image but every time I submit the ModelForm with the same image it doesn't get saved and returns an error saying "This field is required" (screenshot and code attached).
How do I fix this?
Here's a screenshot of the error:
The models file:
from django.db import models
from django.conf import settings
class Book(models.Model):
rel_user = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE, verbose_name="Posted By")
image = models.ImageField(verbose_name="Image", upload_to="static/Books/img")
title = models.CharField(max_length=256, verbose_name="Title")
description = models.TextField(verbose_name="Description")
price = models.IntegerField(verbose_name="Price")
state = models.CharField(max_length=256, verbose_name="State")
city = models.CharField(max_length=256, verbose_name="City")
neighbourhood = models.CharField(max_length=256, verbose_name="Neighbourhood")
phone = models.IntegerField(verbose_name="Phone Number")
def __str__(self):
return self.title + f" ({self.rel_user.username})"
The forms file:
from django.forms import ModelForm
from Books.models import Book
class BookForm(ModelForm):
class Meta:
model = Book
fields = ['image', 'title', 'description', 'price', 'state', 'city', 'neighbourhood', 'phone']
The views file:
from django.shortcuts import render, redirect
from Books.forms import BookForm
from django.contrib import messages
from Books.models import Book
def sell(request):
if request.method == "GET":
form = BookForm()
else:
form = BookForm(request.POST)
form.instance.rel_user = request.user
if form.is_valid():
form.save()
messages.success(request, "Successfully added!")
return redirect('sell')
else:
messages.error(request, "Please fill in all the fields.")
return render(request, 'Books/sell.html', {"form": form})
The HTML code:
<div class="container" style="padding: 2%">
<div class="row">
<div class="col-md-4 col-sm-4 col-xs-12"></div>
<div class="col-md-4 col-sm-4 col-xs-12" style="background-color: rgba(256, 256, 256, 0.8);">
{% if messages %}
{% for message in messages %}
<div class="alert alert-primary" role="alert" style="margin-top: 2%;">
{{ message }}
</div>
{% endfor %}
{% endif %}
<form method="POST" action="{% url 'sell' %}">
{% csrf_token %}
<fieldset class="form-group">
<legend class="border-bottom mb-4">Sell A Book</legend>
{{ form|crispy }}
</fieldset>
<div class="form-group">
<button class="btn btn-outline-info" type="submit">Submit
</button>
</div>
</form>
</div>
<div class="col-md-4 col-sm-4 col-xs-12"></div>
</div>
</div>
from Books.forms import BookForm
from django.contrib import messages
from Books.models import Book
def sell(request):
if request.method == "GET":
form = BookForm()
else:
form = BookForm(request.POST,request.FILES)
form.instance.rel_user = request.user
if form.is_valid():
form.save()
messages.success(request, "Successfully added!")
return redirect('sell')
else:
messages.error(request, "Please fill in all the fields.")
return render(request, 'Books/sell.html', {"form": form})```
<div class="container" style="padding: 2%">
<div class="row">
<div class="col-md-4 col-sm-4 col-xs-12"></div>
<div class="col-md-4 col-sm-4 col-xs-12" style="background-color:rgba(256, 256, 256, 0.8);">
{% if messages %}
{% for message in messages %}
<div class="alert alert-primary" role="alert" style="margin-top: 2%;">
{{ message }}
</div>
{% endfor %}
{% endif %}
<form method="POST" action="{% url 'sell' %}"enctype="multipart/form-data">
{% csrf_token %}
<fieldset class="form-group">
<legend class="border-bottom mb-4">Sell A Book</legend>
{{ form|crispy }}
</fieldset>
<div class="form-group">
<button class="btn btn-outline-info" type="submit">Submit
</button>
</div>
</form>
</div>
<div class="col-md-4 col-sm-4 col-xs-12"></div>
</div>
</div>
I work in a postproduction company, we have our media files on a server. Through the site running on a second server, the user would point to a file, perform some operations (calculating checksums for example) and save the results in the database.
I'm looking for a "best practices" example on how to use FilePathField to get the size of a file. I've read tutorials and searched in the docs, but I'm having trouble putting the pieces together for my needs.
Some relevant code (EDIT: corrected the views, #1 and #3 are printed):
models.py
class AssetTest(models.Model):
file_path = models.FilePathField(path=r"", default="")
file_name = models.CharField(max_length=250, default="")
file_size = models.IntegerField(default=0)
def __str__(self):
return self.file_path
forms.py
class AssetTestForm(forms.ModelForm):
class Meta:
model = AssetTest
fields = ("file_name", "file_size")
views.py
def asset_select(request):
if request.method == 'POST':
print("1")
form = AssetTestForm(request.POST)
if form.is_valid():
print("2")
form.save(commit=False)
form.file_name = request.FILES['file'].name
form.file_size = request.FILES['file'].size
form.save()
return HttpResponseRedirect('/assetmanage/assets/')
print("3")
else:
print("4")
form = AssetTestForm()
return render(request, 'assetmanage/asset_select.html', {'form': form})
asset_select.html
{% extends "assetmanage/base.html" %}
{% block title %}Add Asset{% endblock %}
{% block body %}
<div class="container-fluid">
<div class="row">
<div class="col-sm-12 col-md-7">
<div class="panel panel-default">
<div class="panel-body">
<form class="form-horizontal" name="asset_select" action="/assetmanage/asset/test/" method="post" enctype="multipart/form-data">
{% csrf_token %}
<div class="form-group">
<label class="control-label col-sm-2">Select a file:</label>
<input type="file" name="asset_file">
</div>
<div class="form-group">
<div class="col-sm-offset-2 col-sm-10">
<button type="submit" class="btn btn-success">Submit</button>
</div>
</div>
</form>
</div>
</div>
</div>
</div>
</div>
{% endblock %}
In your FilePathField give the correct path name
FilePathField(path="/home/simon/",..)
cleaned_data of FilePathField will give you the exact path so using that to get the file name and file size of it...
form = AssetTestForm(request.POST)
if form.is_valid():
form.save(commit=False)
temp_file_obj = TemporaryFileUploadHandler(form.cleaned_data['file_path'])
form.instance.file_size = temp_file_obj.chunk_size
form.instance.file_name = form.cleaned_data['file_path'].split("/")[-1]
form.save()