Can't delete an object in delete_view, in Django - python-3.x

I'm trying to create a delete view for my product form, my problem is with the submit button, it doesn't delete my object, it just redirects me to previous page.
This a Windows 7 machine, Python 3.7.1, Anaconda 2018.12
I've tried eliminating the line: if request.method == "POST"
And without that line the object is eliminated, so I think the problem is with the if statement or the POST method, but couldn't solve it
views.py:
from django.shortcuts import render, get_object_or_404, redirect
from .forms import ProductForm, RawProductForm
from .models import Product
def product_delete_view(request, id):
obj = get_object_or_404(Product, id=id)
if request.method == "POST":
obj.delete()
return redirect('../')
context = {
"object": obj
}
return render(request, "products\\product_delete.html", context)
product_delete.html:
{% extends 'base.html' %}
{% block try %}
<form action='.' method='POST'>{% csrf_token %}
<h1>Do you want to delete the product "{{ object.title }}"?</h1>
<p>
<input type="submit" value="Yes" />
Cancel
</p>
</form>
{% endblock %}
The idea is that when I click "Yes", the object disappears, but instead I am redirected to the page of the actual object I wanted to delete

Related

Display images one by one when user clicks next in Django

I have created a django app where user uploads multiple pdf files and it converts to png and displays the images. I am using ModelForms for this purpose. The upload and the convert part is working fine but how do I display the Images sequentially?
What I want is to display one image and when the user clicks next, the next image should be displayed. Below is my app code:
models.py
from django.db import models
from django.contrib.auth.models import User
# Create your models here.
class UserUploadModel(models.Model):
user = models.ForeignKey(User, on_delete = models.CASCADE, null = True)
file = models.FileField(upload_to = 'file_uploads/%d%m%Y')
views.py
from django.shortcuts import render, redirect
from app1.forms import UserUploadForm
from app1.models import UserUploadModel
from app1.convert import convert_file
from app1.transfer import move_dir
import os
from project1 import settings
# Create your views here.
def home(request):
if request.method == 'POST':
form = UserUploadForm(request.POST, request.FILES)
if form.is_valid():
f = form.save()
f.user = request.user
f.save()
ff = request.FILES.getlist('file')
f_list = []
for i in ff:
file_instance = UserUploadModel(file = i)
file_instance.save()
f_list.append(file_instance.file.path)
[convert_file(j) for j in f_list]
src_dir = os.getcwd()
dest_dir = os.path.join(src_dir, 'media/converted_files')
move_dir(src_dir, dest_dir, '*.png')
return redirect('app1-display')
else:
form = UserUploadForm()
return render(request, 'app1/home.html', {'form' : form})
def display(request):
return render(request, 'app1/display.html')
home.html
{%extends "app1/base.html"%}
{%block content%}
<form method="POST" enctype="multipart/form-data">
{%csrf_token%}
{{form.as_p}}
<input type="submit">
</form>
{%endblock content%}
You can display all user's image in your template and then use javascript to hide and show images :
app1/display.html
{% extends "app1/base.html" %}
{% block content %}
{% for image in request.user.useruploadmodel_set.all %}
<image src={{ image.url }} style="width: 100%{% if not forloop.first %}; display: none{% endif %}" />
{% endfor %}
<button id="nextBtn">Next</button
<script>
$(() => {
$("#nextBtn").click(() => {
$('image:visible').hide().next().show()
})
})
</script>
{% endblock %}
I've used jquery because I'm more used to it but that could be done with another framework or vanilla JS.
Why not using a JS carousel library ?

Best way to filter on data belonging to the logged in user (Django)

First of all; I'm fairly new to Django.
Right now, I'm trying to create a very simple webpage with links (just to learn). The idea right now is, that a user (which is logged in) can add links to the database/model, and only see the links of which he has added.
I'm strugling to figure out what the best practice is for that - is it to store the user.username in the model, and then make a .filter(username=user) each time or..? I would assume Django has some (faster way) of handling this.
I have the following
models.py
from django.db import models
from django.contrib.auth.models import User
class links(models.Model):
link = models.URLField()
#user = <something_here>
views.py
def add_link(request):
if request.method == "POST":
form = add_link_form(request.POST)
if form.is_valid():
messages.success(request, "Link is added!")
form.save()
return redirect("my_links")
else:
form = add_link_form()
context = {
"links":links.objects.all(),
"form":form
}
return render(request, "django_project/my_links.html",context=context)
my_links.html
{% extends "django_project/base.html" %}
{% load crispy_forms_tags %}
{% block content %}
<div class="content-section">
<form method="POST">
{% csrf_token %}
{{form|crispy}}
<div class="form-group">
<button class="btn btn-outline-info" type="submit">Add link</button>
</div>
</form>
{% for l in links%}
{{l.link}}
{% endfor%}
{% endblock content %}
You can define Link as:
class Link(models.Model):
link = models.URLField()
user = models.ForeignKey(settings.AUTH_USER_MODEL, related_name="links")
where, when adding you could do:
logged_in_user.links.create(...)
or if adding an already existing link:
logged_in_user.links.add(link)
or if you know that links will forever remain as as strings without any other data related to it, and you use postgresql as your DB, you could add this field to the user model:
from django.contrib.postgres.fields import ArrayField
from django.db import models
class UserModel(models.Model):
...
links = ArrayField(models.URLField(), default=list)
and when adding, treat it exactly as you would do with an array:
logged_in_user.links.append("google.com")
logged_in_user.save()
Both of these approaches, in essence, provide you a filtered list when calling logged_in_user.links, but in the first case it is a queryset of Link objects, whereas the second is an array of strings.

Delete all task related to User

I am creating a todo app. I want to delete all task related to a particular user from Tasklist table after login but i got an error ' deleteAll() missing 1 required positional argument: 'id' ". How can i delete all task. Thanks in advance.
Model.py
from django.contrib.auth.models import User
from django.db import models
class TaskList(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE)
task = models.CharField(max_length=100, null=False, blank=False)
complete = models.BooleanField(default=False)
taskCreate = models.DateTimeField(auto_now=True)
Views.py
def deleteAll(request, id):
TaskList.objects.filter(id=request.user.tasklist_set.filter(id)).delete()
return redirect('todolist')
Html
{% extends 'home.html' %}
{% block content %}
{%if user.is_authenticated%}
<h2>Welcome {{ user.get_username| title }}</h2>
<button type="submit">Logout</button>
<form method="post">
{% csrf_token %}
<label for="task">
<input name="task" placeholder="add today's task" id="task" required>
<button type="submit">add</button>
</label>
</form>
<form method="get" >
{% csrf_token %}
<div>
{% for todo in task %}
{% if todo.complete %}
<li class="list-group-item todo-completed"><h6>{{ todo.task|linebreaks}} </h6></li>
{% else %}
<h6 class="list">{{ todo.task|linebreaks}}</h6>
{% endif %}
{% endfor %}
<button> Delete All </button>
<button> Delete Completed </button>
</div>
</form>
{% endif %}
{% endblock %}
First Change in your template Delete All button. Because your view requires a user id.
<button type="button"> Delete All </button>
Then simplify the deleteAll functions db query. You need to filter all tasks of current user. so you can just use user__id__exact = id:
def deleteAll(request, id):
TaskList.objects.filter(user__id__exact = id).delete()
return redirect('todolist')
Alternative Solution:
You don't need to send id. because you can get the current user id in request argument.
You just need to change the filter:
# view
#login_required
def deleteAll(request):
TaskList.objects.filter(user = request.user).delete()
return redirect('todolist')
# In template use:
<button type="button"> Delete All </button>
# urlpattern
path('delete/', deleteAll, name='delete')
I hope this will help you. Thank you. Happy Coding :)
This is a very common mistake that people do. :)
You have defined a function which takes request and an argument named as id as shown here:
def deleteAll(request, id):
TaskList.objects.filter(id=request.user.tasklist_set.filter(id)).delete()
return redirect('todolist')
But you have to pass an argument into deleteAll. To do that you have to type in the argument value.
You can do so by entering the value after {% url 'delete' %} in the line
Delete All
For example:
Delete All
I hope this helped, if not, feel free to comment and clarify the query.
I suppose "id" refers to the user's id, that is request.user.pk.
There are two issues, or two solutions:
About the Error
You have specified that your view expects the argument id, therefore you would need to add it to the URL in the template.
def deleteAll(request, id): # <<<< "id" is specified as argument
Delete All <!-- no "id" is specified -->
If you have an argument in a view, you need to specify it in the urls.py (which you obviously did) and subsequently whereever you need it reversed:
Delete All
You need the request template processor to have the request in your template context.
However, you actually don't need the ID because you know it in the view already. This is the "other solution".
About the ID
def deleteAll(request, id):
TaskList.objects.filter(id=request.user.tasklist_set.filter(id)).delete()
return redirect('todolist')
can be rewritten to
from django.contrib.auth.decorators import login_required
#login_required
def deleteAll(request):
TaskList.objects.filter(id=request.user.pk).delete()
return redirect('todolist')
You need to remove the id argument in the url in your urls.py, as well.

ModelForm Fields are not pre-populated with existing data during updating in Django

I want to update the User and Lab model. I am able to see the form but it is not pre-populated with existing database information even after setting the instance parameter. If I submit a blank form then all fields are reset to blank values in the database. I have tried several solutions available online but nothing works.
My queries -
How do I pre-populate my form with existing data?
If the user doesnt fill out a particular field, I want the previous information to be stored as it is and not as a blank value. How do I achieve this?
I have the following models.py
class Lab(models.Model):
uid = models.OneToOneField(User, on_delete=models.CASCADE)
company=models.CharField(max_length=200,blank=True)
#receiver(post_save, sender=User)
def create_lab_profile(sender, instance, created, **kwargs):
if created:
Lab.objects.create(uid=instance)
#receiver(post_save, sender=User)
def save_lab_profile(sender, instance, **kwargs):
instance.lab.save()
Forms.py
class UserForm(forms.ModelForm):
email=forms.EmailField(max_length=300)
class Meta:
model = User
fields = ('first_name', 'last_name', 'email',)
class LabForm(forms.ModelForm):
class Meta:
model = Lab
fields = ('company',)
views.py
#login_required
def update_user_details(request,pk):
if request.method == 'POST':
user_form = UserForm(request.POST,instance=request.user)
lab_form = LabForm(request.POST,instance=request.user.lab)
if user_form.is_valid() and lab_form.is_valid():
user_form.save()
lab_form.save()
messages.success(request,'Your profile was successfully updated!')
return redirect('user_details')
else:
messages.error(request,('Please correct the error below.'))
else:
user_form = UserForm(instance=request.user)
lab_form = LabForm(instance=request.user.lab)
return render(request, 'update_user_details.html', {'user_form': user_form,'lab_form': lab_form})
template -
{% extends 'base.html' %}
{% block content %}
{% csrf_token %}
<H3> Update Personal information - </H3>
<br>
<form method="post" enctype="multipart/form-data">
{% csrf_token %}
{{ user_form.as_p }}
{{ lab_form.as_p }}
<button type="submit" class="btn btn-primary">Save changes</button>
</form>
{% endblock %}
Any help/suggestions will be appreciated!

Kept getting werkzeug.routing.BuildError

I tried running the code and got this werkzeug.routing.BuildError: Could not build url for endpoint 'book'. Did you mean 'sign_in' instead?
Also, if i try to access the /main route, it says URL not found on server. Can somebody please help me.
import os
import csv
from flask import Flask, session, render_template, request
from flask_session import Session
from sqlalchemy import create_engine
from sqlalchemy.orm import scoped_session, sessionmaker
app = Flask(__name__)
# Check for environment variable
if not os.getenv("DATABASE_URL"):
raise RuntimeError("DATABASE_URL is not set")
# Configure session to use filesystem
app.config["SESSION_PERMANENT"] = False
app.config["SESSION_TYPE"] = "filesystem"
Session(app)
# Set up database
engine = create_engine(os.getenv("DATABASE_URL"))
db = scoped_session(sessionmaker(bind=engine))
f = open("books.csv")
reader = csv.reader(f)
for isbn, title, author, year in reader:
db.execute("INSERT INTO books (ISBN, title, author, year) VALUES (:ISBN, :title, :author, :year)",
{"ISBN": isbn, "title": title, "author": author, "year": year})
print(f"Added flight from {isbn} to {year} lasting {title} minutes.")
db.commit()
#app.route("/")
def sign_in():
return render_template("Sign.html")
#app.route("/main" method = "POST")
def book():
name = request.form.get("name")
return render_template("books.html", username=name)
This is the sign.html document
{% extends "layout.html" %}
{% block title %}Sign in{% endblock %}
{% block body %}
<div class="main">
<p class="sign" align="center">Sign in</p>
<form action= "{{ url_for('book') }}" class="form1" method="post">
<input name = "name" class="un " type="text" align="center" placeholder="Username">
<input class="pass" type="password" align="center" placeholder="Password">
<button class="submit" align="center">Sign in</button>
</form>
</div>
{% endblock %}
This is the books.html document
{% extends "layout.html" %}
{% block title %} {{username}} {% end block%}
{% block body%}
{% end block %}
#app.route("/main" method = "POST")
There are two things wrong with this line:
no comma after "/main" (it should cause syntax error, so I assume it just got lost in the snippet)
allowed methods for an endpoint are defined with keyword argument methods, as a iterable of strings, so in your code it should go like methods = ["POST"] instead of method = "POST".
However, in newest version of Flask (1.1.2), the second issue should cause TypeError, so maybe you're using some older version which doesn't handle such case and the result is that the endpoint doesn't exist.

Resources