I have a listing system on my website and am currently creating a page which allows the user to edit their listing, I've got most of it working however I am stuck on saving their updated form. Currently if they save the edited form rather than updating the model it creates a whole new listing entry and still leaves the old one there. If anyone could please look at my code that would be great, I've been stuck on this problem for so long!
View -
#login_required(redirect_field_name='login')
def editlisting(request, pk):
post = JobListing.objects.get(pk=pk)
if str(request.user) != str(post.user):
return redirect("index")
if request.method == "POST":
print("test")
form = JobListingForm(request.POST, instance=post, force_update=True)
if form.is_valid():
form.save()
return redirect('index')
else:
print("else")
form = JobListingForm(instance=post)
context = {
"form": form
}
return render(request, "editlisting.html", context)
Model -
class JobListing(models.Model):
region_choice = (
('Auckland', 'Auckland'),
('Wellington', 'Wellington'),
('Christchurch', 'Christchurch')
)
industry_choice = (
('Accounting', 'Accounting'),
('Agriculture, fishing & forestry', 'Agriculture, fishing & forestry'),
('Automotive', 'Automotive'),
('Banking, finance & insurance', 'Banking, finance & insurance'),
('Construction & Architecture', 'Construction & Architecture'),
('Customer service', 'Customer service'),
)
employment_type_choice = (
('Full Time', 'Full Time'),
('Part Time', 'Part Time'),
('One-off', 'One-off'),
('Other', 'Other')
)
user = models.CharField(max_length=50)
job_title = models.CharField(max_length=30)
pay_rate = models.DecimalField(max_digits=10, decimal_places=2)
employment_type = models.CharField(max_length=10, choices=employment_type_choice)
job_description = models.CharField(max_length=2000)
business_address_region = models.CharField(max_length=50, choices=region_choice)
business_address_suburb = models.CharField(max_length=50)
business_industry = models.CharField(max_length=50, choices=industry_choice)
email = models.EmailField(max_length=50, blank=True, null="True")
telephone = models.IntegerField(blank=True, null='True')
active_listing = models.BooleanField(default=True)
class Meta:
verbose_name = 'Job Listing'
def clean(self):
if not (self.email or self.telephone):
raise ValidationError("You must specify either email or telephone")
if not self.email:
self.email = "Not Provided"
def __unicode__(self):
return "%s" % self.job_title
Piece of code from my registration app which could be affecting it?
def signup(self, request, user):
SignUpProfile.objects.create(
user=user,
account_type=self.cleaned_data['account_type'],
contact_number=self.cleaned_data['contact_number']
)
Form -
class JobListingForm(forms.ModelForm):
class Meta:
model = JobListing
fields = ['job_title', 'pay_rate', 'employment_type', 'job_description', 'business_address_region',
'business_address_suburb', 'business_industry', 'telephone', 'email']
widgets = {
'job_title': forms.TextInput(attrs={'class': 'form-input', 'placeholder': 'Job Title'}),
'pay_rate': forms.NumberInput(attrs={'class': 'form-input', 'placeholder': 'Hourly Rate or One Off Amount'}),
'employment_type': forms.Select(attrs={'class': 'form-input'}),
'job_description': forms.Textarea(attrs={'class': 'form-textarea',
'placeholder': 'Tell us additional information about your job listing e.g. Times, Business Info, Number of positions etc. (2000 Character Limit)'}),
'business_address_region': forms.Select(attrs={'class': 'form-input'}),
'business_address_suburb': forms.TextInput(attrs={'class': 'form-input', 'placeholder': 'Business Suburb'}),
'business_industry': forms.Select(attrs={'class': 'form-input'}),
'email': forms.EmailInput(attrs={'class': 'form-input', 'placeholder': 'Email'}),
'telephone': forms.NumberInput(attrs={'class': 'form-input', 'placeholder': 'Contact Numnber'}),
}
Form HTML -
<div id="createjoblisting">
<h1 class="pageheader">Edit Your Job Listing</h1>
<form class="createjoblisting" id="createjoblisting_form" method="post" action="{% url 'createjoblisting' %}">
{% csrf_token %}
{{ form.non_field_errors }}
<p> <label for="id_username" class="form-input-label">Job Title</label><br>
{{ form.job_title }}<br><p>{{ form.job_title.errors }}
<p><label for="id_username" class="form-input-label">Pay Rate</label><br>
{{ form.pay_rate }}<br></p>{{ form.pay_rate.errors }}
<p><label for="id_username" class="form-input-label">Employment Type</label><br>
{{ form.employment_type }}<br><p>{{ form.employment_type.errors }}
<p><label for="id_username" class="form-input-label">Job Description</label><br>
{{ form.job_description }}<br><p>{{ form.job_description.errors }}
<p><label for="id_username" class="form-input-label">Business Region</label><br>
{{ form.business_address_region }}<br><p>{{ form.business_address_region.errors }}
<p><label for="id_username" class="form-input-label">Business Suburb</label><br>
{{ form.business_address_suburb }}<br><p>{{ form.business_address_suburb.errors }}
<p><label for="id_username" class="form-input-label">Business Industry</label><br>
{{ form.business_industry }}<br><p>{{ form.business_industry.errors }}
<p><label for="id_username" class="form-input-label">Contact Number (Must provide either Contact Number or Email)</label><br>
{{ form.telephone }}<br><p>{{ form.telephone.errors }}
<p><label for="id_username" class="form-input-label">Email</label><br>
{{ form.email }}<br><p>{{ form.email.errors }}
<button type="submit" class="form-button">Update Job Listing</button>
</form>
</div>
URLS -
urlpatterns = [
url(r'^createjoblisting/', views.createjoblisting, name='createjoblisting'),
url(r'^(?P<pk>[0-9]+)/editprofile/', views.editprofile, name='editprofile'),
url(r'^(?P<pk>[0-9]+)/editlisting/', views.editlisting, name='editlisting'),
url(r'^editlistingportal/', views.editlistingportal, name='editlistingportal'),
]
Your form's action is wrong. Change it to:
<form action="{% url 'editlisting' %}" class="createjoblisting" id="createjoblisting_form" method="post" >
As you have copied the creation template, your form posts your data to the view which creates the listing instead of editing it.
Related
I have a django form like this:
class AddUserGroupFrom(forms.ModelForm):
class Meta:
model = UsersGroups
fields = (
'tag',
)
widgets = {
'tag': forms.TextInput(attrs={'class': 'form-control', 'placeholder': 'Work, home, etc..'}),
}
def __init__(self, *args, **kwargs):
super(AddUserGroupFrom, self).__init__(*args, **kwargs)
self.fields['city'] = forms.ModelChoiceField(
queryset=Group.objects.values_list('city').all().distinct(),
widget=forms.Select(attrs={
'class': 'form-select form-select-sm mb-3',
'aria-label': '.form-select-sm example',
}),
label='Choose city name',
empty_label='Select city',
)
self.fields['group'] = forms.ModelChoiceField(
queryset=Group.objects.values_list('group_number').all(),
widget=forms.Select(attrs={
'class': 'form-select form-select-sm mb-3',
'aria-label': '.form-select-sm example',
}),
label='Choose group number',
empty_label='Select group',
)
The problem that in my select field options displayed as tuples
Form representation
Templates look like this:
<form action="" method="post">
{% csrf_token %}
<div class="mb-3">
<label for="{{ add_group_form.tag.id_for_label }}" class="form-label">{{ add_group_form.tag.label }}</label>
{{ add_group_form.tag }}
</div>
<label for="{{ add_group_form.city.id_for_label }}">{{ add_group_form.city.label }}</label>
{{ add_group_form.city }}
<label for="{{ add_group_form.group.id_for_label }}">{{ add_group_form.group.label }}</label>
{{ add_group_form.group }}
<input type="submit" value="Save changes" class="btn btn-success">
</form>
How can I remove tuple-style representation in options inside the select field?
I tried to iterate within indexes in templates:
{{ add_group_form.city[0] }}
But it throws error:
Could not parse the remainder: '[0]' from 'add_group_form.city[0]'
You can create a tuple with the city values and assign it to the choices of the form field. Normally you do not define the form fields in the init method. It looks like city is not a model field. That's why I changed it to a ChocieField.
(code is not tested, change it if needed)
class AddUserGroupFrom(forms.ModelForm):
city = forms.ChoiceField(
choices=[],
empty_label='Select city',
label='Choose city name',
widget=forms.Select(attrs={
'class': 'form-select form-select-sm mb-3',
'aria-label': '.form-select-sm example',
}),
)
group = forms.ModelChoiceField(
queryset=Group.objects.all(),
empty_label='Select group',
label='Choose group number',
widget=forms.Select(attrs={
'class': 'form-select form-select-sm mb-3',
'aria-label': '.form-select-sm example',
}),
)
class Meta:
model = UsersGroups
fields = ('tag',)
widgets = {
'tag': forms.TextInput(attrs={'class': 'form-control', 'placeholder': 'Work, home, etc..'}),
}
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
city_list = Group.objects.values_list('city', flat=True)
city_choices = [(city, city) for city in city_list]
self.fields['city'].choices = city_choices
I currently want to send some data to my database by doing the following: Sending a document to the database and each document has a foreign key from the user table i.e. each document is a reference to an author(from another table) but it will be bad for the user to get all the users in the system and choosing one of them, I want the author assignment to be performed in the views. So as a summary I want to get fields from the form in views. I found a corresponding question and tip at this link, but the only issue here being that a file was not inlcuded in his model but on mine yes. Snipets of my files below;
models.py
class UploadedDocuments(models.Model):
user = models.ForeignKey(
TheUsers,
on_delete=models.CASCADE,
)
document = models.FileField(
verbose_name='Document',
upload_to=f'documents/%Y/',
null=True,
)
plagiarism_status = models.CharField(max_length=100, null=True)
serialised_content = models.CharField(null=True, max_length=255)
date_uploaded = models.DateTimeField(
verbose_name='Uploaded On',
auto_now_add=True
)
def __str__(self):
return self.document.name
class Meta:
verbose_name = "Document"
verbose_name_plural = 'Documents'
Views.py
def upload(request):
form = UploadedDocumentsForm(request.POST, request.FILES)
if request.POST:
if form.is_valid():
form_stack = form.save(commit = False)
form.user = request.user
form_stack.serialised_content = "bala"
form_stack.plagiarism_status = 'Hello'
form_stack.save()
return redirect("results")
function which is constantly telling me invalid.
forms.py
class UploadedDocumentsForm(forms.ModelForm):
class Meta:
model = UploadedDocuments
fields = ['document', 'user', 'plagiarism_status', 'serialised_content']
widgets = {
'document': forms.FileInput(
attrs = {
'class': 'drop-zone__input',
'id': 'file',
'accept': '.doc, .docx, .txt',
'required': True,
}
),
'user': forms.Select(
attrs = {
}
),
'plagiarism_status': forms.TextInput(
attrs = {
'hidden': True,
}
),
'serialised_content': forms.TextInput(
attrs = {
'hidden': True,
}
)
}
my template file
<form action="{% url 'upload' %}" method="POST" enctype='multipart/form-data'>
{% csrf_token %}
<div class="drop-zone w-50">
<span class="drop-zone__prompt text-center h3">
Drops file here
</span>
{{ form.document }}
{{ form.user }}
{{ form.serialised_content }}
{{ form.plagiarism_status }}
</div>
<div class="d-flex justify-content-center">
<button type="submit" class="btn btn-white btn-outline-success
p-4 px-5 w-lg-25 w-md-50 w-sm-50 text-capitalize5 my-5">
<i class="fa fa-2x fa-sync px-3"></i>
Upload
</button>
</div>
</form>
Any suggestion on how this could be done will be helpful.
add blank and none to your user of UploadedDocuments model:
class UploadedDocuments(models.Model):
user = models.ForeignKey(
TheUsers,
null=True,
blank=True,
default=None,
on_delete=models.CASCADE,
)
...
I am trying to save po_id as a unique key of the "Order table". So I am generating a random number in the Order Form. But the issue is that somehow I can not save the form, even though all the fields are filled up.
models.py
def random_string():
return str(random.randint(10000, 99999))
class Order(models.Model):
po_id = models.CharField(max_length=4, default = random_string)
supplier = models.ForeignKey(Supplier, on_delete=models.CASCADE)
product = models.ForeignKey(Product, on_delete=models.CASCADE)
forms.py
class OrderForm(forms.ModelForm):
class Meta:
model = Order
fields = ['supplier', 'product', 'po_id']
widgets = {
'supplier': forms.Select(attrs={'class': 'form-control', 'id': 'supplier'}),
'product': forms.Select(attrs={'class': 'form-control', 'id': 'product'}),
}
views.py
def create_order(request):
from django import forms
form = OrderForm()
if request.method == 'POST':
forms = OrderForm(request.POST)
if forms.is_valid():
po_id = forms.cleaned_data['po_id']
supplier = forms.cleaned_data['supplier']
product = forms.cleaned_data['product']
order = Order.objects.create(
po_id=po_id,
supplier=supplier,
product=product,
)
return redirect('order-list')
context = {
'form': form
}
return render(request, 'store/addOrder.html', context)
Order.html
<form action="#" method="post" novalidate="novalidate">
{% csrf_token %}
<div class="form-group">
<label for="po_id" class="control-label mb-1">ID</label>
{{ form.po_id }}
</div>
<div class="form-group">
<label for="supplier" class="control-label mb-1">Supplier</label>
{{ form.supplier }}
</div>
<div class="form-group">
<label for="product" class="control-label mb-1">Product</label>
{{ form.product }}
</div>
<div>
<button id="payment-button" type="submit" class="btn btn-lg btn-success btn-block">
<span id="payment-button-amount">Save</span>
</button>
</div>
Can help me with how I can solve the issue?
Without widgets form works correctly. It must be simple solution without calling super.init. In documentation it is exactly as I wrote here...
My views.py:
class ForumForm(ModelForm):
class Meta:
model = Forum
fields = ['publisher', 'topic', 'text', 'date']
widgets = {
'publisher': TextInput(attrs={'class': 'form-control'}),
'topic': TextInput(attrs={'class': 'form-control'}),
'text': Textarea(attrs={'class': 'form-control'}),
'date': DateTimeInput(attrs={'class': 'form-control'})
}
My model.py:
class Forum(models.Model):
publisher = models.CharField('Публикатор', max_length=50, default='Anonymous')
topic = models.CharField('Название', max_length=50)
text = models.TextField('Текст')
date = models.DateField(default=timezone.now)
comment = models.CharField('Комментарий', max_length=100, default='Комментарий')
# slug = models.SlugField(max_length=200, unique=True, default='default')
class Meta:
verbose_name = 'Пост'
verbose_name_plural = 'Посты'
def __str__(self):
return self.topic
My template:
{% extends 'main/layout.html' %}
{% block title %}New form{% endblock %}
{% block content %}
<form method="post">
<div class="form-group">
{% csrf_token %}
{{ form.as_p }}
<button type="submit" class="btn btn-info">Send</button>
</div>
</form>
{% endblock %}
The html file just shows the name of publisher: 'Публикатор'
Hi you should stat the "forms." in front of each line.
For example:
forms.TextInput(attrs=...
Also use forms.ModelForm
I had a form with some fields and it was working fine. But when adding new field in the Model django raise an error
when I run the server and click on submit then it shows error for the new field This field is required although I am providing data for this field in the form.
Model.py
class UserInformation(models.Model):
firstName = models.CharField(max_length=128)
lastName = models.CharField(max_length=128)
userName = models.CharField(max_length=128)
institution = models.CharField(choices = [("#xyz.org","XYZ"), ("#abc.edu","ABC")], max_length=128)
userEmail = models.CharField(default="N/A", max_length=128)
phoneNumber = models.CharField(max_length=128)
orchidNumber = models.CharField(max_length=128)
PI = models.CharField(max_length=128)
PIUsername = models.CharField(max_length=128)
PIInstitution = models.CharField(default="N/A",choices = [("#xyz.org","XYZ"), ("#abc.edu","ABC")], max_length=128)
PIEmail = models.CharField(default="N/A", max_length=128)
PIPhoneNumber = models.CharField(max_length=128)
In this model
PIEmail is the field which I have added.
forms.py
class UserInformationForm(ModelForm):
firstName = forms.CharField(max_length=254,
widget=forms.TextInput({
'class': 'form-control',
}))
lastName = forms.CharField(
widget=forms.TextInput({
'class': 'form-control',
}))
userName = forms.CharField(
widget=forms.TextInput({
'class': 'form-control',
}))
institution = forms.ChoiceField( choices = [("#xyz.org","XYZ"), ("#abc.edu","ABC")]
,widget=forms.Select({
'class': 'form-control',
}))
phoneNumber = forms.CharField( required=False,
widget=forms.TextInput({
'class': 'form-control',
}))
orchidNumber = forms.CharField( required=False,
widget=forms.TextInput({
'class': 'form-control',
}))
PI = forms.CharField(
widget=forms.TextInput({
'class': 'form-control',
}))
PIUsername = forms.CharField(
widget=forms.TextInput({
'class': 'form-control',
}))
ctsaPIInstitution = forms.ChoiceField( choices = [("#xyz.org","XYZ"), ("#abc.edu","ABC")]
,widget=forms.Select({
'class': 'form-control',
}))
PIPhoneNumber = forms.CharField(
widget=forms.TextInput({
'class': 'form-control',
}))
userEmail = forms.CharField( required=False,
widget=forms.TextInput({
'class': 'form-control',
}))
PIEmail = forms.CharField( required=False,
widget=forms.TextInput({
'class': 'form-control',
}))
class Meta:
model = UserInformation
exclude = ()
and here is my register.html
<div class="row">
<section id="registerForm">
<div style="font-size:15px; color:red;">
The fields marked with an asterisk (*) are mandatory.
</div><br/>
<form method="post" action=".">{% csrf_token %}
<div class="form-group">
<label for="id_firstName" >First Name (*)</label>
{{ form.firstName }}
</div>
<div class="form-group">
<label for="id_lastName" >Last Name (*)</label>
{{ form.lastName }}
</div>
<div class="form-group">
<label for="id_email">Username (*)</label>
{{ form.userName }}
</div>
<div class="form-group">
<label for="id_intitution">Institution (*)</label>
{{ form.institution }}
</div>
<div class="form-group">
<label for="id_phone" >Contact Number</label>
{{ form.phoneNumber }}
</div>
<div class="form-group">
<label for="id_orcid">Orcid ID (Get Orcid ID)</label>
{{ form.orchidNumber }}
</div>
<div class="form-group">
<label for="id_ctsaPI">Prinicipal Investigator (*)</label>
{{ form.PI }}
</div>
<div class="form-group">
<label for="id_PI">CTSA Prinicipal Investigator Username (*)</label>
{{ form.PIUsername }}
</div>
<div class="form-group">
<label for="id_ctsaPI">Prinicipal Investigator Institute (*)</label>
{{ form.PIInstitution }}
</div>
<div class="form-group">
<label for="id_PIName"> Prinicipal Investigator Phone Number (*)</label>
{{ form.PIPhoneNumber }}
</div>
<div class="form-group">
<label for="id_UserEmail">User Email (*)</label>
{{ form.userEmail }}
</div>
<div class="form-group">
<label for="id_PI">PI Email (*)</label>
{{ form.PIEmail }}
</div>
<div class="form-group" >
<br/>
<input type="submit" value="Submit" class="btn btn-primary" />
</div>
</form>
</section>
view.py
#csrf_protect
def register(request):
if request.method == 'POST':
form = UserInformationForm(request.POST)
if form.is_valid(): //// here it is breaking
form.save()
else:
form = UserInformationForm()
variables = { 'form': form }
return render(request, 'registration/register.html',variables)
I am not sure what is wrong in this code
I'm not sure if this helps but sometimes I find the errors returned look like a bit of a red herring and end up driving me mad for hours on end. I am no expert and from where I am sitting the code for your form looks fine to me which is probably why it was working before. However in your html file you have two labels specified with the same id, the second one just happens to be on the PIEmail field that you have recently added. Coincidence? Maybe! It's a long shot but perhaps change that initially and see if it makes any difference.
Change:
<div class="form-group">
<label for="id_PI">PI Email (*)</label>
{{ form.PIEmail }}
</div>
to:
<div class="form-group">
<label for="id_PIEmail">PI Email (*)</label>
{{ form.PIEmail }}
</div>
Note: The other instance is on the PIUsername field.