Delete all task related to User - python-3.x

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.

Related

How do I update Django database from field choices?

I'm developing a CRM using django and for my lead details I am trying to display my choices in the html form but also have it update the database when a new choice is selected and saved. Currently, I am able to display the choice that was selected upon lead creation, but I don't know how to allow the agent to change the choice and have that new choice update the database. I am still in the process of learning Django so theres still a lot i'm learning as i go.
views.py
class LeadDetailView(LoginRequiredMixin, DetailView):
template_name = "lead-details.html"
queryset = Lead.objects.all()
context_object_name = "leads"
models.py
class Lead(models.Model):
PROBLEM_LEAD = 'Problem Lead'
PAY_TOO_FAR = 'Payments Too Far'
PAY_TOO_SMALL = 'Payments Too Small'
NPI = 'No Payment Information'
ACTIVE = 'Active Deal'
NO_DEAL = 'No Deal'
choices_lead_status = [
(PROBLEM_LEAD, 'Problem Lead'),
(PAY_TOO_FAR,'Payments Too Far'),
(PAY_TOO_SMALL,'Payments Too Small'),
(NPI,'No Payment Information'),
(ACTIVE,'Active Deal'),
(NO_DEAL,'No Deal')
]
choices_lead_owner = [
("Settlement, New",'Settlement, New'),
("Lead, Sales",'Lead, Sales'),
]
lead_status = models.CharField(max_length=100, choices=choices_lead_status, blank=True)
lead_owner = models.CharField(max_length=100, choices=choices_lead_owner, blank=True)
agent = models.ForeignKey(Agent, null=True, on_delete=models.SET_NULL, blank=True)
def __str__(self):
return f"{self.first_name} {self.last_name}"
html
# this displays the lead_owner but i also need it to iterate through the choices to allow proper selection
<div id="select">
<div class="form-group">
<label for="input-select">Lead </label>
<select class="form-control" id="input-select" >
<option>{{ leads.lead_owner}}</option>
<!-- <option>Lead, Sales</option>
<option>Settlement, New</option>
<option>Corden, James</option>
<option>Rower, Charles</option>
<option>Has to be dynamic</option> -->
</select>
</div>
</div>
There are a few things to take into account and more than one way (as always) to accomplish it. Here's my suggestions:
First, update your HTML to use Django tags with a for loop and iterate your lead_owner choices. If the value matches the existing Lead_owner value, it's pre-selected:
<div id="select">
<div class="form-group">
<label for="input-select">Lead Owner</label>
<select class="form-control" id="input-select" name="lead_owner">
{% for choice in leads.choices_lead_owner %}
{% if choice.0 == leads.lead_owner %}
<option value="{{ choice.0 }}" selected>{{ choice.1 }}</option>
{% else %}
<option value="{{ choice.0 }}">{{ choice.1 }}</option>
{% endif %}
{% endfor %}
</select>
</div>
</div>
Submitting and updating the form can be done as such by inheriting from your LeadDetailView. I included the imports as well:
from django.views.generic.edit import UpdateView
from django import forms
class LeadUpdateView(LoginRequiredMixin, UpdateView):
model = Lead
form_class = LeadUpdateForm
template_name = "lead-update.html"
success_url = reverse_lazy('lead_detail')
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context['leads'] = self.object
return context
Now, you can create a new template and extend your existing HTML template like so by :
{% extends 'lead-details.html' %}
{% block content %}
<h1>Update Lead</h1>
<form method="post">
{% csrf_token %}
{{ form.as_p }}
<button type="submit" class="btn btn-primary">Save</button>
</form>
{% endblock %}
Hope this helps.
Edited for your question:
You could use the existing view and form.
You can edit the LeadDetailView to be something like this:
class LeadDetailView(LoginRequiredMixin, DetailView):
template_name = "lead-details.html"
queryset = Lead.objects.all()
context_object_name = "leads"
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context['form'] = LeadOwnerForm(instance=context['leads'])
return context
def post(self, request, *args, **kwargs):
lead = self.get_object()
form = LeadOwnerForm(request.POST, instance=lead)
if form.is_valid():
form.save()
messages.success(request, "Lead updated successfully!")
else:
messages.error(request, "Lead update failed.")
return redirect('lead_detail', pk=lead.pk)
And, then the form can be adjusted like so:
{% block content %}
{{ leads.first_name }} {{ leads.last_name }}
<form method="post">
{% csrf_token %}
{{ form.as_p }}
<button type="submit" class="btn btn-primary">Save</button>
</form>
{% endblock %}
Another approach would be using Ajax, which is a bit more complicated but offers some solid benefits:
The page does not need to refresh upon submitting the form. The backend will respond with Json too, which is something I prefer as your app evolves.
Ajax means that you'll ask for less data, typically, to be returned to the frontend. It doesn't need to send back the entire template, but instead only the updated data or data you're choosing to return.
Ajax can be implemented with limited Javascript experience, but having JS experience allows you to do more with it.
I recommend getting to become familiar with implementing the above and then evolve your app to use Ajax, but that's me. I also prefer to use function based views instead of class based views when starting with Django, so I can really see what's happening before it's mostly hidden in class based views. But, Django is all about doing more with less, so learning CBV's out of the gate is not a bad thing at all.

Hide buttons if user doesn't belong to any of Django groups

My problem is that I want to hide the button from all users who are not in group1 and group2 or in both groups. I did the following thing but it seems doesn't work at all.
My views.py:
def is_group1(user):
return user.groups.filter(name='Group1').exists()
def is_group2(user):
return user.groups.filter(name='Group2').exists()
def employee_list(request):
groups = [g.name for g in request.user.groups.filter(name__in=['Group1', 'Group2'])]
context = {'employee_list': Employee.objects.filter(dept__in=groups)}
return render(request, 'employee_register/employee_list.html', context)
My little example of employee_list.html:
<form>
{% if user.is_group1 %}
<button formaction="{% url 'employee_insert' %}">Add</button>
{% if user.is_group2%}
<button formaction="{% url 'employee_insert' %}">Add</button>
{% else %}
<p>You are not logged</p>
{% endif %}
</form>
Any thoughts how I can implement this ?
In order to hide a button if a user does not belong to a group, you can implement following method:
First, set-up categories using AbstractUser:
class CustomUser(AbstractUser):
class StatusType(models.Model):
VOLUNTEER = "VOLUNTEER"
MANAGER = "MANAGER"
EMPLOYEE = "EMPLOYEE"
STATUS = [
(MANAGER, "Manager"),
(EMPLOYEE, "Employee"),
(VOLUNTEER, "Volunteer"),
]
status_type = models.CharField(
max_length=50,
choices=StatusType.STATUS,
default=StatusType.VOLUNTEER,
verbose_name="Statut")
Then, in your template, add this to toggle the button:
{% if user.status_type == "MANAGER" %}
<form action="{% url 'interviews:advocacy_topic_create' %}" id="topic-create">
<button type="submit">Create</button>
</form>
{% endif %}
You should not create a view depending on each type of user.

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.

Get a string variable from views to urls in Django

I am a beginner at Python and Django, I am trying to solve a problem where when a user searches if that search is valid, I want to get that search = var_X, in my URL like:
www.website.com/search/var_X
or something like,
www.website.com/search/<df.item>
Views.py
def views_search(request):
temp_dict = {}
if request.method == 'POST':
var_X = request.POST['var_X']
try:
df = wsc.Summary(temp_dict, var_X)
except Exception as e:
df = "ERROR"
return render(request,'search.html', {'df' : df})
else:
return render(request,'home.html', {'var_X' : "Not Found"})
Urls
from django.urls import path
from . import views
from requests import *
urlpatterns = [
path('search/<var_X>', views.views_search, name="url-search"),
]
HTML
<form action="{% url 'url-search' var_X %}"class="d-flex" method="POST">
{% csrf_token %}
<input class="form-control me-2" type="search" placeholder="Enter String" aria-label="Search" name="var_X">
<button class="btn btn-outline-secondary" type="submit">Search</button>
</form>
When Django renders a template it converts all template tags into html.
You won't be able to set the value of var_X in {% url 'url-search' var_X %} using python code on the client side.
My suggestion is to use javascript to set the form's action using the onclick html attribute.
<button ... onclick="this.form.action = {% url 'url-search' %} + document.getElementById('id-of-input-element').value;>"
This also means removing the action attribute from the input element.
From
<form action="{% url 'url-search' var_X %}"class="d-flex" method="POST">
to
<form class="d-flex" method="POST">
Because I don't know what your code does (because I don't know what df is. Use the following as only an example of what you could achieve.
(In my code snippets entering a search goes back to the same page to display results.)
urls.py
urlpatterns = [
path('search/', views.views_search, name="url-search"),
path('search/<str:var_X>', views.views_search)
]
The route 'search/' is needed in order to make {% url 'url-search' %} work on first page load.
The route 'search/<str:var_X>' matches any value after search/ into a variable called var_X as a string in the view function.
views.py
def views_search(request, var_X=None):
if request.method == 'POST':
pass
# do the stuff you need to do with the form..
return render(
request,
"views_search.html",
{
'var_X': var_X
}
)
The parameter var_X is None by default if the url doesn't have anything after search/ else it will have the search string.
views_search.html (wtv your html template is called)
<form class="d-flex" method="POST">
{% csrf_token %}
<input id="search_input" class="form-control me-2" type="search" placeholder="Enter String" aria-label="Search" name="var_X" value="">
<button class="btn btn-outline-secondary" type="submit" onclick="this.form.action = {% url 'url-search' %} + document.getElementById('search_input').value;">Search</button>
</form>
{% if var_X %}
<p>Showing results for '{{ var_X }}'.</p>
{% endif %}
with the above html you'll get this output:
Before pressing search button
After pressing search button
This also has the benefit that if you type something directly into the url it will search that too.
Hopefully this helps steer you in the right direction for what you're looking for.

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!

Resources