I am trying to do exercise 7 in tango with django where i must save new page to specific category by adding information to forms.
So I write new code to forms.py
class PageForm(forms.ModelForm):
title = forms.CharField(max_length=128, help_text="Please enter the title of the page.")
url = forms.CharField(max_length=200, help_text="Please enter the url of the page.")
views = forms.IntegerField(widget=forms.HiddenInput(), initial=0)
class Meta:
model = Page
def clean(self):
cleaned_data = self.cleaned_data
url = cleaned_data.get('url')
if url and not url.startswith('http//'):
url = 'http://' + url
cleaned_data['url'] = url
return cleaned_data
fields = ('title', 'url', 'views')
def save_form(self):
if self.is_valid():
page = self.save(commit=False)
try:
cat = Category.objects.get(name=category_name)
page.category = cat
except:
return render_to_response('rango/add_category.html', {}, context)
page.views = 0
page.save()
return True
else:
return False
Then I edit views.py
def add_page(request, category_name_url):
context = RequestContext(request)
category_name = decode_url(category_name_url)
if request.method == 'POST':
form = PageForm(request.POST)
if form.save_form():
return category(request, category_name_url)
else:
print form.errors
else:
form = PageForm()
return render_to_response( 'rango/add_page.html',
{'category_name_url': category_name_url,
'category_name': category_name,
'form': form},
context)
def decode_url(element):
return element.replace(' ', '_')
def encode_url(element):
return element.replace('_', '')
Then I created template:
Rango
<body>
<h1>Add page to category</h1>
<form id="page_form" method="post" action="/">
{% csrf_token %}
{% for hidden in forms.hidden_fields %}
{{ hidden }}
{% endfor %}
{% for field in form.visible_fields %}
{{ field.errors }}
{{ field.help_text }}
{{ field }}
{% endfor %}
<input type="submit" name="Submit" value="Add a page" />
</form>
</body> </html>
I have made reference to new page in category.html
Add page to this category
And of course a edit urls.py
> url(r'^rango/category/(?P<category_name_url>\w+)/add_page/$',
> views.add_page, name='add_page'),
Everything is visible and I am able to fill form. But when i confirm data by clicking on button, page is return to home and not in category and new page is not save in database. So please someone, where a have error?
Your <form> element has the action set to action="/". This makes the form submit send a POST request to the homepage not the current page. You can correct this by making the form action empty action="" to submit to the current URL or be explicit and use the {% url %} template tag for the required form action.
Related
After displaying my posts, I don't manage to Edit any of them.
When I print the instance variable which is in views.py in my terminal, it displays only the title and the author like this title - author, which is the method defined in models.py.
Help please!
Views.py
#login_required(login_url='login_view')
def update_post_view(request, post_id, slug=None):
instance = Article.objects.get(id = post_id)
if request.method == 'POST':
form = UpdatePostForm(request.POST, request.FILES, instance=instance)
if form.is_valid():
form.save()
return redirect('posts_view')
else:
form = UpdatePostForm(instance=instance)
return render(request,'update_post.html', {'form':form})
forms.py
class UpdatePostForm(forms.ModelForm):
class Meta:
model = Article
fields = ('author',)
title = forms.CharField(max_length=255, label='username',
widget= forms.TextInput(attrs= {'placeholder':'Title...', 'class': 'title'}))
body = forms.CharField(max_length=255, label='body', required=True, widget=forms.Textarea(attrs={'placeholder':'Start writing your post...'}))
urls.py
path('update_post/<int:post_id>/<slug:slug>', views.update_post_view, name='update_post_view')
update_post.html
{% extends 'base.html' %}
{% block title %}Update Post{% endblock %}
{% block content %}
<h2>Update Posts...</h2>
<form action="" method="POST">
{% csrf_token %}
<div>
<h3>{{form.title}}</h3>
<small>{{form.author}}</small>
<p>{{form.body}}</p>
</div>
<button class="btn btn-secondary">Update</button>
</form>
{% endblock %}
Good Day,
I have a delete btn for each created Title. When you click on the delete button, the model will be delete with the url localhost:8000/delete/OBJECT_ID
models.py
class NewTitle(models.Model):
user = models.ForeignKey(
settings.AUTH_USER_MODEL,
default=None,
null=True,
on_delete=models.CASCADE,
)
title = models.CharField(max_length=200)
creator_adress = models.GenericIPAddressField(null=True)
id = models.BigAutoField(primary_key=True)
def __str__(self):
return str(self.title)
views.py
def title_view(request):
custom_title_id = random.randint(1111, 1111111111111)
titles = # What to here, maybe NewTitle.pk?
if request.method == 'POST':
form = NewTitleForm(request.POST, instance=NewTitle(user=request.user))
if form.is_valid():
obj = form.save(commit=False)
obj.creator_adress = get_client_ip(request)
obj.id = custom_title_id
while NewTitle.objects.filter(id=obj.id).exists():
obj.id = random.randint(111, 11111111111)
obj.save()
return redirect('/another')
else:
form = NewTitleForm()
return render(request, 'test.html', {'form': form, 'titles': titles})
def title_delete(request, title_id):
user_title = NewTitle.objects.filter(id=title_id,
user=request.user)
if user_title:
user_title.delete()
else:
return redirect('https://example.com')
return HttpResponseRedirect('/another')
test.html
{% for i in request.user.newtitle_set.all %}
<p> {% if i.user == request.user %} {{ i.title }} {% endif %} <form action="delete/ #THE CURRENT OBJECT ID" method="POST">{% csrf_token %}<button type="submit">Delete Title</button></form> </p>
{% endfor %}
Every 'Title' is displayed in the template. Next to each title there is a Delete button that leads to delete/OBJECT_ID. How can I set the action="" to the correct delete URL. So that I get the current ID of the title (object).
The interesting part is in views.py the titles variable and in test.html the second form action=""
Thank you very much! :-)
You can use url template filter, but first you need to give the url which leads to title_delete a name (for example "delete_title").
Then for the button you can write action={% url 'delete_title' i.id %} .
It will automatically create the url which leads to title_delete view and will also put the id in the request path.
Good day, I have a page to test where tickets are created and where all created tickets (titles) are listed. Now you should be able to click on the title of a created ticket.
The button then redirects to an extra page where all the information of the specific ticket is.
I've always had trouble displaying user specific stuff, so what needs to be done so that the href="" of each link redirects in HTML to the specific ticket?
I did the following
\\forms.py
{% for i in request.user.addtitle_set.all %}
<div>
{% if i.user == request.user %} {{ i.title }} {% endif %}
<form action="{% url SOMETHING_HERE i.id}" style="display: inline">
<button type="submit">View Ticket</button>
</form>
</div>
<br />
{% endfor %}
\\urls.py
path('dashboard/user/ticket', ticket_view),
path('dashboard/user/ticket/<int:id>/',
ticket_system_view, name="view_ticket"),
\\ models.py
class Ticket(models.Model):
user = models.ForeignKey(
settings.AUTH_USER_MODEL,
default=None,
null=True,
on_delete=models.CASCADE,
)
title = models.CharField(max_length=200)
description = models.TextField()
creator_adress = models.GenericIPAddressField(null=True)
start_date = models.DateTimeField(default=timezone.now)
def __str__(self):
return str(self.title)
\\views.py
#login_required
def ticket_view(request, id, *args, **kwargs):
try:
obj = Ticket.objects.get(id=id)
except Ticket.DoesNotExist:
return redirect('/')
if request.method == 'POST':
form = TicketForm(request.POST, instance=Ticket(user=request.user))
if form.is_valid():
obj = form.save(commit=False)
obj.creator_adress = get_client_ip(request)
obj.save()
return redirect('/dashboard/user/ticket')
else:
form = TicketForm()
return render(request, 'ticket.html', {'form': form})
def ticket_system_view(request, id, *args, **kwargsw):
# Here I will put all the stuff for the specific ticket page
return render(request, 'ticket_system.html', {})
Edit:
I can not even access the page because of the error
TypeError at /dashboard/user/ticket
ticket_views() missing 1 required positional argument: 'id'
Edit 2.0:
Solution:
path('dashboard/user/ticket/', ticket_view),
path('dashboard/user/ticket/<int:id>/',
ticket_system_view, name="view_ticket"),
{% for i in request.user.ticket_set.all %}
<a href="{% url 'view_ticket' i.id %}"
>{% if i.user == request.user %} {{ i.title }} {% endif %}</a
>
<br />
{% endfor %}
Your urls.py
path('dashboard/user/ticket', ticket_view),
path('dashboard/user/ticket/<int:id>/',
ticket_system_view, name="view_ticket"),
Should be
path('dashboard/user/ticket/<int:id>', ticket_view, name="some_name"),
path('dashboard/user/ticket/<int:id>/',
ticket_system_view, name="view_ticket"),
As ticket_view expects an id
ticket_views() missing 1 required positional argument: 'id'
In your views.py you are getting argument id so it must be passed.
Change your urls.py as
path('dashboard/user/ticket/<int:pk>', ticket_view, name='ticket_view'),
path('dashboard/user/ticket/<int:id>/',
ticket_system_view, name="view_ticket"),
Also your urlnamespace in your form as
<form action="{% url 'ticket_view' i.id %}" style="display: inline">
There must be spaces before and after % in your url template tag. You were missing ending % add that too.
I have the following models, and as you can see they are related to each other
class Leads(models.Model):
project_id = models.BigAutoField(primary_key=True, serialize=False)
created_at = models.DateTimeField(auto_now_add=True)
expected_revenue = MoneyField(decimal_places=2,max_digits=14, default_currency='USD')
expected_licenses = models.IntegerField()
country = CountryField(blank_label='(select_country)')
status = models.CharField(choices=[('Open', 'Open'), ('Closed', 'Closed'), ('Canceled', 'Canceled'),
('Idle', 'Idle')
], max_length=10)
estimated_closing_date = models.DateField()
services = models.CharField(choices=[('Illumination Studies', 'Illumination Studies'),
('Training', 'Training'),('Survey Design Consultancy', 'Survey Design Consultancy'),
('Software License', 'Software License'),
('Software Development','Software Development')], max_length=40)
agent = models.ForeignKey(Profile, default='agent',on_delete=models.CASCADE)
company = models.ForeignKey(Company,on_delete=models.CASCADE)
point_of_contact = models.ForeignKey(Client, default='agent',on_delete=models.CASCADE)
updated_at = models.DateTimeField(auto_now=True)
application = models.CharField(choices=[('O&G','O&G'),('Renewables','Renewables'),('Mining','Mining'),
('Other','Other'),('CSS','CSS')],
default='O&G',max_length=20)
sub_category = models.CharField(choices=[('Wind','Wind'),('Geo-Thermal','Geo-Thermal'),('Solar','Solar'),
('Tidal','Tidal')], max_length=20, blank=True)
#property
def age_in_days(self):
today = date.today()
result = self.estimated_closing_date - today
return result.days
def __str__(self):
return f'{self.project_id}'
class LeadEntry(models.Model):
revenue = MoneyField(decimal_places=2,max_digits=14, default_currency='USD',blank=True)
date = models.DateField()
lead_id = models.ForeignKey(Leads,on_delete=models.CASCADE)
id = models.BigAutoField(primary_key=True, serialize=False)
probability = models.DecimalField(max_digits=2, decimal_places=2, default=0, blank=True)
#property
def est_revenue(self):
result = self.revenue * probabiity
return result
Essentially a lead entry is related to the lead, and I'm using HTMX to essentially add data to LeadEntry database using a form.
Form
class LeadEntryForm(forms.ModelForm):
class Meta:
model = LeadEntry
fields = ('lead_id','date','revenue','probability')
widgets = {'date': DateInput()}
I have 2 views, one that will simply pass an HTML with a button for the user to add entries to the database, and another view with the actual form
views
#login_required
def add_to_forecast(request):
id = request.GET.get('project_id')
request.session['lead_id'] = id
return render(request, 'account/lead_forecast.html')
#login_required
def forecast_form(request):
if request.method=='POST':
form = LeadEntryForm(data=request.POST or None)
if form.is_valid():
form.save(commit=False)
messages.success(request,"Successful Submission")
return redirect('add_to_forecast')
lead_id = request.session['lead_id']
data = {'lead_id':lead_id}
context = {
"form":LeadEntryForm(initial=data)
}
return render(request, 'account/lead_entry_forecast.html', context)
Lastly, there are 2 HTML pages, the first one is associated with add_to_forecast and renders a simple page, this is where the HTMX happens and this adds the form from the next HTML page
{% extends "base.html" %}
{% load crispy_forms_tags %}
{% load static %}
{% block title %}Client Information {% endblock %}
{% block content %}
<h1> Add Lead to Sales Forecast </h1>
<p>Click the Button below to add a Payment Date</p>
<button type="button" hx-get="{% url 'lead_entry_forecast' %}" hx-target="#leadform" hx-swap="beforeend" >
Add Lead </button>
<div id="leadform">
<br>
</div>
{% endblock %}
The form that is added by the user as many times they want to do so
{% load crispy_forms_tags %}
{% load static %}
{% block content %}
<div class="container-fluid">
<form method="post" enctype="multipart/form-data" action=".">
{% csrf_token %}
<div class="row justify-content-center">
<div class="col-sm-1">
{{ form.lead_id|as_crispy_field }}
</div>
<div class="col-sm-2">
{{ form.date|as_crispy_field }}
</div>
<div class="col-sm-2">
{{ form.revenue|as_crispy_field }}
</div>
<div class="col-sm-1">
{{ form.probability|as_crispy_field }}
</div>
<div class="col-sm">
<input type="submit" value="Submit" >
</div>
</div>
</form>
</div>
<hr>
{% endblock %}
The problem I have is that after submitting the form, everything seems to be working, obviously, at the moment you can only submit one lead, as I still have to add more logic, but at the moment the form is not sending data to the DB, after some debugging, I was not able to pass the POST, it seems like is just not submitting anything.
Any help will be highly appreciated
Update - 12/4/2021
I have tried to submit data using the form and it actually works, so there is nothing wrong with the form submitted the POST.request, if I go directly to the URL, it works fine, so the form is submitted correctly and the database is updated.
I still don't understand why is not working when the form is rendered by the htmx, so it has something to do with that.
When you are designing an HTMX page, you have to be careful with the post request, so I was processing the form in the wrong view, please see below the views:
#login_required
def add_to_forecast(request):
form = LeadEntryForm(data=request.POST or None)
if request.method == 'POST':
if form.is_valid():
form.save()
return HttpResponse("Success")
else:
return render(request, 'account/lead_entry_forecast.html', {"form": form})
id = request.GET.get('project_id')
request.session['lead_id'] = id
return render(request, 'account/lead_forecast.html')
#login_required
def forecast_form(request):
lead_id = request.session['lead_id']
data = {'lead_id':lead_id}
context = {
"form":LeadEntryForm(initial=data)
}
return render(request, 'account/lead_entry_forecast.html', context)
Now it works as it should
The Django project that I am working on lists patient details and lets the user edit the details. I have been able to list it out but views.py is not getting linked to the url for updating the list.
views.py:
def update_patient(request, patient_id):
patient = Patient.objects.get(id=patient_id)
if request.method != 'POST':
form = PatientForm(instance=patient)
else:
# POST data submitted; process data.
form = PatientForm(instance=patient, data=request.POST)
if form.is_valid():
form.save()
return HttpResponseRedirect(reverse('patient:patient',
args=[patient.id]))
context = { 'patient': patient, 'form': form}
return render(request, 'patient/update_patient.html', context)
models.py:
class Patient(models.Model):
patientID = models.CharField(max_length=20)
firstName =models.CharField(max_length=20)
lastName = models.CharField(max_length=20)
age = models.IntegerField(max_length=None)
SSN = models.CharField(max_length=15)
address = models.CharField(max_length=200)
date_added = models.DateTimeField(auto_now_add=True)
urls.py:
url(r'^patients/(?P<patient_id>\update\d+)/$', views.update_patient, name='update'),
update_patient.html:
{% extends "patient/base.html" %} {% block content %}
<p>{{ patient }}
</p>
<p>Update Patient:</p>
<form action="{% url 'patient:update' patient.id %}" method='post'>
{% csrf_token %} {{ form.as_p }}
<button name='submit'>add entry</button>
</form>
{% endblock content %}
Your URL pattern is wrong, you have \update within capturing group, it shouldn't be, change the pattern to this:
url(r'^patients/(?P<patient_id>\d+)/update/$', views.update_patient, name='update')