Django - Post to specific URL using form - python

I want to post to a specific URL. The url has the scope of deleting a database row. The URL is composed by the address + the pk of the file selected in the form catched from a model.
select_file_deletion.html
{% extends "index.html" %}
{% block content %}
<!--Here the number 2 in "/App/delete/2/" needs to be replaced with the pk of the file. The logic is working. -->
<form action="/App/delete/{{ myfile.pk }}/" method="post" enctype="multipart/form-data">
{% csrf_token %}
{{ form.as_p }}
<h5>Please select one file at a time from the list below to delete it from the server.</h5>
{% for myfile in filename %}
<input type="checkbox" name="file_name" value="{{ myfile }}">
<label>
{{ myfile }}
<input type="hidden" value="{{ myfile.pk }}" name="pk">
</label>
<br>
{% endfor %}
<br>
<button type="submit" class="btn btn-primary">Delete</button>
</form>
{% endblock %}
Project urls.py
url(r'^delete/(?P<pk>\d+)/$', FileDeleteView.as_view(), name='APIdelete')
views.py
class SelectFileDelView(TemplateView):
"""
This view is used to select a file from the list of files in the server.
After the selection, it will send the file to the server.
The server will then delete the file.
"""
template_name = 'select_file_deletion.html'
parser_classes = FormParser
queryset = FileModel.objects.all()
def get_context_data(self, **kwargs):
"""
This function is used to render the list of files in the MEDIA_ROOT in the html template.
"""
context = super().get_context_data(**kwargs)
media_path = settings.MEDIA_ROOT
myfiles = [f for f in listdir(media_path) if isfile(join(media_path, f))]
context['filename'] = myfiles
return context
class FileDeleteView(DeleteView):
"""
This class contains the method to delete a file interacting directly with the API.
DELETE requests are accepted.
"""
# TODO: Fix, still not working
model = FileModel
fields = ['file']
template_name = 'delete_success.html'
success_url = '/delete_success/'
App/urls.py
# Url to select a file to be deleted and confirm the upload
url('filedelete/', SelectFileDelView.as_view(), name='file_delete'),
url('delete_success/', FileDeleteView.as_view(), name='delete_success')
ERROR: the request URL row is not catching the address including the pk, not replacing the variable with the pk of the selected file.
Page not found (404)
Request Method: POST
Request URL: http://127.0.0.1:8000/App/delete//
Using the URLconf defined in DjangoRestDeepLearning.urls, Django tried these URL patterns, in this order:
^App/ ^predict/$ [name='APIpredict']
^App/ ^upload/$ [name='APIupload']
^App/ ^delete/(?P<pk>\d+)/$ [name='APIdelete']
filedelete/ [name='file_delete']
delete_success/ [name='delete_success']
The current path, App/delete//, didn't match any of these.
Question I checked before opening this one without solving the issue:
1) Delete object with form in django
2) Django How to pass object id via form action?

Im assuming you have the myfile.pk in your template.
The url in your form action isnt working as the pk is missing. Replace the action of the form with this:
<form action="{% url 'APIdelete' pk=myfile.pk %}" method="post" enctype="multipart/form-data">

Related

I cant update an object in Django?

Ive created a Django application where you add jobs and Im fully able to add new jobs but I can update them for some reason? The update feature isn't working and I don't know why??
<form action='/update_job/{{job.id}}' method="POST">
<ul>
{% for message in messages %}
<li>{{message}}</li>
{% endfor %}
</ul>
{% csrf_token %}
Title: <input type='text' value="{{job.job}}" name='job'>
Description: <input type='text' value="{{job.description}}" name='description'>
Location: <input type='text' value="{{job.location}}" name='location'>
<input type='submit'>
</form>
def update_job(request, job_id):
errors = Job.objects.job_validator(request.POST, job_id)
if job.creator.id != request.session['user_id']:
messages.error(request, "This isn't yours to edit!")
if len(errors):
for key, value in errors.items():
messages.error(request, value)
return redirect(f'/edit_job/{job_id}')
job = Job.objects.get(id=job_id)
job.job = request.POST['job']
job.description = request.POST['description']
job.location = request.POST['location']
job.save()
return redirect('/main')
Page not found (404)
Request Method: POST
Request URL: http://localhost:8000/update_job/2
Using the URLconf defined in Python_Exam.urls, Django tried these URL patterns, in this order:
register
login
logout
main
job_link
job/create
jobs/<int:job_id>/view
jobs/<int:job_id>/delete
jobs/<int:job_id>/edit
jobs/<int:job_id>/update_job
The current path, update_job/2, didn't match any of these.
You swapped the primary key and the update_job, it is:
<form action="/jobs/{{ job.id }}/update_job" method="POST">
…
</form>
You however might want to use the {% url … %} template tag [Django-doc] to determine the URL.

Django - How to edit and submit multiple forms individually then render back to the same page?

So I'm building this learning log app where users can create multiple topics. I'm trying to create a single page where users can edit/save changes/delete their topic names. My logic in the edit_topic view function is to display the original topics in forms with save and delete button, code below or feel free to check GitHub Repo:
views.py
def edit_topics(request, topic_pk=None):
'''edit existing topics mainly the names'''
# modify the model data according to the request method and name
if request.method == 'POST' and topic_pk != None:
if 'save' in request.POST:
topic_to_change = get_object_or_404(Topic, pk=topic_pk)
form = TopicForm(instance=topic_to_change, data=request.POST)
if form.is_valid():
form.save()
elif 'delete' in request.POST:
topic_to_delete = get_object_or_404(Topic, pk=topic_pk)
topic_to_delete.delete()
return redirect('learning_logs:edit_topics')
# get the original/modified data passing to render
topics = Topic.objects.all()
topic_lst = []
for topic in topics:
form = TopicForm(instance=topic)
topic_lst.append(form)
context = {'topics': topics, 'topic_lst': topic_lst}
return render(request, 'learning_logs/edit_topics.html', context)
edit_topics.html
{% extends 'learning_logs/base.html' %}
{% block content %}
<section class="container">
<h3>Topics you have created</h3>
<ul class="">
{% for form in topic_lst %}
<li class="mb-5">
<form class="d-flex align-items-center"
action="{% url 'learning_logs:edit_topics' form.instance.pk %}" method="POST">
{% csrf_token %}
{{ form.as_p }}
<button class="btn btn-primary" name="submit">save</button>
<button class="btn btn-danger" name="delete">delete</button>
</form>
</li>
{% endfor %}
</ul>
<a class="btn btn-info" href="{% url 'learning_logs:topics' %}">Done</a>
</section>
{% endblock content %}
url.py
from django.urls import path
from . import views
app_name="learning_logs"
urlpatterns = [
path('', views.index, name='index'),
path('topics/', views.topics, name='topics'),
path('topics/edit/', views.edit_topics, name='edit_topics'),
path('new_topic/', views.new_topic, name='new_topic'),
path('topic_<int:topic_pk>/', views.topic, name='topic'),
path('topic_<int:topic_pk>/new_entry/', views.new_entry, name='new_entry'),
path('topic_<int:topic_pk>/entry_<int:entry_pk>/', views.entry, name='entry'),
path('topic_<int:topic_pk>/entry_<int:entry_pk>/edit_entry/', views.edit_entry, name='edit_entry'),
]
However, I think there might be some logic error, it keeps raising NoReverseMatch(msg) django.urls.exceptions.NoReverseMatch: Reverse for 'edit_topics' with arguments '(1,)' not found. 1 pattern(s) tried: ['topics/edit$']
If I delete form.instance.pk in edit_topics.html file, no error is raised. But consequently, the if logic in the view function wouldn't take action... I'm fairly new to programming, I'm sure there're some logic errors as well --
I'm struggling with the topic_pk optional argument in the view function because I'm not sure how to pass it in correctly.
Ideally, I hope the users can edit, save or delete the topics on this page one by one, and after they click save or delete the page will redirect back to this view and render the updated topic text. At the end, when they are done, they can click the Done button at the end...
Please help! Thanks!!
Feel free to check GitHub Repo for Learning_Log app
Update your url like this:
path('topics/edit/', views.edit_topics, name='edit_topics'),
path('topics/edit/<int:topic_pk>/', views.edit_topics, name='edit_topic'),
And in html, change this line:
<form class="d-flex align-items-center" action="{% url 'learning_logs:edit_topic' form.instance.pk %}" method="POST">
^^^^^^^^^^^
Here, what I did is that, have 2 urls point to same view, one with topic_pk and another is without it.

Using Django FormPreview the right way

My Goal
I have a django project with a form, and I want to display a preview page before the user submits.
The problem
I can display a preview page using a Django FormPreview, but not all form data is displayed properly. Specifically, if I have a field with choices, the string values of these choices aren't displayed. I'm also having problems applying template filters to date fields. The end result is that some data on the preview page is visible but other data is blank:
However, if I display the same data for posts that have actually been submitted, then everything displays properly:
My Code
models.py:
class Game(models.Model):
# Game Choices
FOOTBALL = 0
BASKETBALL = 1
TENNIS = 2
OTHER = 3
GAME_CHOICES = (
(FOOTBALL, 'Football'),
(BASKETBALL, 'Basketball'),
(TENNIS, 'Tennis'),
(OTHER, 'Other')
)
game_id = models.AutoField(primary_key=True)
location = models.CharField(max_length=200, verbose_name="Location")
game = models.IntegerField(choices=GAME_CHOICES, default=FOOTBALL)
game_date = models.DateField(verbose_name='Game Date')
forms.py
class GameForm(ModelForm):
class Meta:
model = Game
fields = (
'location',
'game',
'game_date'
)
I'm pretty sure that the problem is in my views.py: I'm not sure that I'm processing the POST request the right way to feed all data to the preview page.
views.py
def form_upload(request):
if request.method == 'GET':
form = GameForm()
else:
# A POST request: Handle Form Upload
form = GameForm(request.POST) # Bind data from request.POST into a GameForm
# If data is valid, proceeds to create a new game and redirect the user
if form.is_valid():
game = form.save()
return render(request, 'games/success.html', {})
return render(request, 'games/form_upload.html', {
'form': form,
})
preview.py
class GameFormPreview(FormPreview):
form_template = 'games/form_upload.html'
preview_template = 'games/preview.html'
def done(self, request, cleaned_data):
# Do something with the cleaned_data, then redirect
# to a "success" page.
return HttpResponseRedirect('/games/success')
form_upload.html
...
<form method="post">
{% csrf_token %}
<ul><li>{{ form.as_p }}</li></ul>
<button type="submit">Preview your post</button>
</form>
...
preview.html
{% load humanize %}
...
<h1>Preview your submission</h1>
<div>
<p>Location: {{ form.data.location }}</p>
<p>Game Date: {{ form.data.game_date|date:"l, F d, Y" }}</p>
<p>Game Type: {{ form.data.get_game_display }}</p>
</div>
<div>
<form action="{% url 'form_upload' %}" method="post">
{% csrf_token %}
{% for field in form %}
{{ field.as_hidden }}
{% endfor %}
<input type="hidden" name="{{ stage_field }}" value="2" />
<input type="hidden" name="{{ hash_field }}" value="{{ hash_value }}" />
<!-- Submit button -->
<button type="submit">Submit your post</button>
<!-- Go back button -->
<button type="submit">
<a href="{% url 'form_upload' %}"
onClick="history.go(-1);return false;" >
Go back and edit your post
</a>
</button>
</div>
</form>
</div>
...
Two issues
Essentially, I'm having these two issues:
String values for choices are not displayed. If I use the get_FOO_display() method in my preview.html template, it returns blank. However, if I use this in a page after the post has been submitted, it displays properly.
The humanize date filter doesn't work. If I apply a humanize filter ({{ form.data.game_date|date:"l, F d, Y" }}) in preview.html, it also displays blank. Again, this works for submitted posts.
My question essentially is: what's the right way to use the FormPreview here?
form.data does not have get_FOO_display attributes. When you access {{ form.data.get_game_display }} in the template, it fails silently and doesn't display anything.
The get_FOO_display are methods of the instance, so try this instead.
{{ form.instance.get_game_display }}
Wherever possible you should access data from form.cleaned_data (which is validated and 'cleaned') instead of form.data, which is the raw data submitted to the form.
The filters don't work with form.data.game_date because it's a raw string. They should work with form.cleaned_data.game_date, which has been converted to a python date object.
Finally, you haven't implemented anything in your done method, you've just copied the comment from the docs. You could create a new game using cleaned_data as follows:
def done(self, request, cleaned_data):
game = Game.objects.create(**cleaned_data)
return HttpResponseRedirect('/games/success')

Unable to update CharField - Django

First of all I'm glad to be here, I read you lately and i found useful answers here.
This is my first post so please be kind with me, I'm a newbie in programming.
So, I'm writing my 1st web application in Django - a todo app and I don't know how to write the function that does this this. I found something in Django docs and in other related discussions but it doesn't work.
Here's my code:
#models.py
class Task(models.Model):
user = models.ForeignKey(User)
task = models.CharField(max_length=200)
initialized_at = models.DateTimeField(auto_now_add=True)
due_date = models.DateField(default=datetime.now)
done = models.BooleanField(default=False)
def __unicode__(self):
return self.task
#views.py
def edit_task(request, id):
if request.method == 'POST':
task_to_edit = Task.objects.get(pk=task_id)
form = TaskForm(request.POST, instance=task_to_edit)
form.save()
if form.is_valid():
task_to_edit = form.save()
return HttpResponseRedirect('/')
else:
form = TaskForm()
return render(request, 'todo/edit_task.html', {'form': form})
#urls.py
url(r'^edit_task/(?P<task_id>\w+)/$', 'todo.views.edit_task')
#edit_task.html
{% block content %}
<form action="/edit_task/" method="post">{% csrf_token %}
{{ form.as_p }}
<input type="submit" value="Submit" />
</form>
{% endblock content %}
When I submit the updated form I get this error:
Page not found (404)
Request Method: POST
Request URL: hxxp://127.0.0.1:8000/edit_task/
Using the URLconf defined in jbz.urls, Django tried these URL patterns, in this order:
^admin/
^$ [name='index']
^(?P<task_id>\d+)/$
^(?P<task_id>\d+)/$
^add-task/$
^delete-task/(?P<task_id>\w+)/$
^edit_task/(?P<id>\w+)/$
^done/(?P<task_id>\d*)/$
The current URL, edit_task/, didn't match any of these.
and the root urls.py looks like:
url(r'', include('todo.urls'))
#edit_task.html
{% block content %}
<form action="/edit_task/{{task.id}}" method="post">{% csrf_token %}
{{ form.as_p }}
<input type="submit" value="Submit" />
</form>
{% endblock content %}
Notice how I added {{task.id}} expression in <form action="/edit_task/{{task.id}}" method="post">
IMPORTANT NOTE: Substitute {{task.id}} to whatever variable accomplishes this in your template.
The reason why you get the error is because edit_task/ is not getting the other part, task_id to match the regular expression:
url(r'^edit_task/(?P<task_id>\w+)/$', 'todo.views.edit_task')
UPDATE: Also your edit_task view has potential errors as well>
def edit_task(request, id):
task_to_edit = Task.objects.get(pk=id)
if request.method == 'POST':
form = TaskForm(request.POST, instance=task_to_edit)
form.save()
if form.is_valid():
task_to_edit = form.save()
return HttpResponseRedirect('/')
else:
form = TaskForm(instance=task_to_edit)
# you don't pass any task variable to the view so the form view
# won't know which task to edit, you'll have to handle that
return render(request, 'todo/edit_task.html', {'form': form, 'task':task_to_edit})
Note: I corrected the code in the view a little. Now the task_to_edit is passed also to the Form to fill the fields when the view is requested via GET. Notice that in order to access to this view, the url in the browser should look like this http://www.example.com/edit_task/2
If other wise you try to access http://www.example.com/edit_task without passing the id you'll get Error 404.
Hope this helps!
I think your pattern for edit task expects an id - task name. Try changing your URL pattern:
'^edit_task/(?P<task_id>\w+)/$'
to
'^edit_task/$'
or providing the task id that you want to edit.
Just add name space to your url and according update your template.
#urls.py
url(r'^edit_task/(?P<task_id>\w+)/$', 'todo.views.edit_task', name= "edit_task")
#edit_task.html
{% block content %}
<form action="{% url 'edit_task' task_id %}" method="post">{% csrf_token %}
{{ form.as_p }}
<input type="submit" value="Submit" />
</form>
{% endblock content %}

google app engine with django upload file error

i am using django with google app engine . i am trying to upload images.
i made a form
<form enctype="multipart/form-data" action="addImage" method="post">
<p>Title of the Image:
<input type="text" name="title" /></p>
<p>Please select image to upload:
<input type="file" name="img" required="True"/></p>
<p><input type="submit" value="Upload" /></p>
</form>
mapping it to this view
def addImage(request):
image = Image()
image.title = request.POST.get("title")
img = images.resize(request.POST.get('img'),50,50)
image.blob = db.Blob(img)
image.put()
return HttpResponse('<html><head><meta HTTP-EQUIV="REFRESH" content="2; url=/"></head><body>One item added successfuly </body></html>')
its giving me this error in the debugging session
Exception Type: NotImageError
Exception Value:Empty image data.
WHY?????
I haven't used Google App Engine, but this is how I would do it on a pure Django 1.3 installation:
forms.py:
from django import forms
from django.forms import fields
class UploadImageForm(forms.Form):
image_file = fields.ImageField()
views.py:
from django.shortcuts import render_to_response
from django.template import RequestContext
from NAME_OF_YOUR_APP.forms import UploadImageForm
def addImage(request):
if request.method == 'POST':
upload_image_form = UploadImageForm(data=request.POST, files=request.FILES)
if upload_image_form.is_valid():
image_file = request.cleaned_data['image_file']
# do something with the image...
return ...
else:
upload_image_form = UploadImageForm()
context = {'form':upload_image_form}
return render_to_response('path/to/upload_template.html', context, context_instance=RequestContext(request))
upload_template.html:
<form enctype="multipart/form-data" action="" method="post">
{% csrf_token %}
<table>
<tr>
<td>{{ form.image_file.label_tag }}</td>
<td>{{ form.image_file }}</td>
<td>{% if form.image_file.errors %}{% for error in form.image_file.errors %}{{ error }}{% endfor %}{% endif %}</td>
</tr>
</table>
<input type="submit" value="Submit"/>
</form>
Your template code looks good (it's missing {% csrf_token %}, which I'm not sure if GAE needs or not). Your view code should check to see if the request is a POST request or not.
In my example, I created a form called UploadImageForm, which accepts a single image_file to be uploaded. Logic works like so:
User visits example.com/upload_image
addImage() runs. Since this is a GET and not a POST request, it makes an empty UploadImageForm(), and renders it inside upload_template.html.
User is displayed the form.
User fills out the form and Submits an image.
Server receives POST request, and addImage() is called again.
We bind the uploaded file data to UploadImageForm.
If there are no errors (e.g. upload_image_form.is_valid() is True), we capture the image_file out of cleaned_data, and we can then do something with it.
If there are errors (upload_image_form.is_valid() is False), the template is re-displayed with error messages.
really simple ,
edit this line:
img = images.resize(request.POST.get('img'),50,50)
with this one:
img = request.FILES['img'].read()
make sure that you are using django 1.2
Try this.. it work for me... :)
def addImage(request):
image = Image()
image.title = request.POST.get("title")
image.blob = db.Blob(str(request.FILES['img']['content']))
image.put()
return HttpResponse('<html><head><meta HTTP-EQUIV="REFRESH" content="2; url=/"></head><body>One item added successfuly </body></html>')

Categories

Resources