Separate Users accounts - python

I want to separate the open sessions in my site so a user can't delete/modify objects from another account. If someone could explain me how do I do that, for example here with the delete function.
This is my code:
models.py
class User(AbstractUser): ##abstract user model
pass
class Auction(models.Model): ##these are the objects
user = models.ForeignKey(User, on_delete=models.CASCADE, blank=True)
name = models.CharField(max_length=64)
img = models.ImageField(upload_to='listing_image', null=True, default="/static/default_image.jpg")
description = models.TextField(blank=True)
starting_bid = models.IntegerField()
category = models.ForeignKey(Category, on_delete=models.CASCADE, related_name="auctions", null=True)
views.py
#login_required(login_url="login")
def delete(request, id):
auction = get_object_or_404(Auction, id=id)
if request.method == "POST":
auction.delete()
return redirect ('index')
return render(request, "auctions/delete.html", {
"auction": auction
})
html:
{{auction.user}}
<h1>{{ auction.name }}</h1>
<img src="{{ auction.img.url }}" width="600">
<h5>Starting price: ${{ auction.starting_bid }}</h5>
<form method="POST" enctype="multipart/form-data">
{%csrf_token%}
<button type="submit" class="btn btn-primary">Place a New Bid</button>
{{form.as_p}}
</form>
{%for bid in bids%}
<h3>${{ bid.new_bid}}</h3>
{%empty%}
No offers yet.
{%endfor%}
{{auction.description}}
<h2>Comments</h2>
<ul>
<p>New Comment</p>
{%for comment in comments%}
<li>{{comment.user}} - {{comment.created_on}}
<p><h4>{{comment.body}}</h4></p>
</li>
{%empty%}
<li>No comments yet.</li>
{%endfor%}
</ul>
<p>Edit
Delete</p>

You filter on the user as well:
#login_required(login_url='login')
def delete(request, id):
auction = get_object_or_404(Auction, id=id, user=request.user)
if request.method == 'POST':
auction.delete()
return redirect ('index')
return render(request, 'auctions/delete.html', {
'auction': auction
})
This will return a HTTP 404 error in case the .user of the Auction is not the logged in user, so they will not be able to remove the object.
In the template, you need to check if the user is the logged in one to show the buttons. But even if you somehow show buttons, the users will not be able to trigger the logic behnind it if you filter accordingly:
{% if user == auction.user %}
<p>Edit
Delete</p>
{% endif %}

Related

Getting NoReverseMatch while click the comment button

I was getting that same error while click the like button, But the error was solved..
again after creating comment view and its other staff I'm getting that error again...When I click the comment button then the error appears..I'm very new to Django,,, help me please..
My project models.py, template page, urls.py, views.py are attached herewith
**models.py**
from email.policy import default
from django.db import models
from django.contrib.auth.models import User
# Create your models here.
class Blog(models.Model):
author = models.ForeignKey(User, on_delete=models.CASCADE)
title = models.CharField(max_length=200, verbose_name="Put a Title")
blog_content = models.TextField(verbose_name="What is on your mind")
blog_image = models.ImageField(upload_to="blog_images", default = "/default.png")
created = models.DateTimeField(auto_now_add=True)
updated = models.DateTimeField(auto_now=True)
def __str__(self):
return self.title
class Comment(models.Model):
blog = models.ForeignKey(Blog, on_delete=models.CASCADE, related_name = "blog_comment" )
user = models.ForeignKey(User, on_delete=models.CASCADE, related_name = "user_comment")
comment = models.TextField()
comment_date = models.DateField(auto_now_add=True)
def __str__(self):
return self.comment
class Like(models.Model):
blog = models.ForeignKey(Blog, on_delete=models.CASCADE, related_name = "blog_liked")
user = models.ForeignKey(User, on_delete=models.CASCADE, related_name = "user_liked")
class Unlike(models.Model):
blog = models.ForeignKey(Blog, on_delete=models.CASCADE, related_name = "blog_unliked")
user = models.ForeignKey(User, on_delete=models.CASCADE, related_name = "user_unliked")
**blog_page.html**
{% extends "main.html" %}
{% load static %}
{% load crispy_forms_tags %}
{% block content %}
<div style="text-align:center;">
<h2>{{blog.title}}</h2>
<img src="{{blog.blog_image.url}}" alt="" width="630px" height="300px">
</div>
<div style="text-align:center;">
{{blog.blog_content|linebreaks}}
</div>
{% if not liked and not unliked %}
<h4> Like </h4>
<h4>Unlike</h4>
{% elif unliked %}
<h4> Like </h4>
{% elif liked %}
<h4>Unlike</h4>
{% endif %}
<div>
<h4>
Comments:
</h4>
{% for comment in comments %}
<div>
{{ user }} <br>
<h5>{{ comment }}</h5>
</div>
{% endfor %}
<!-- <h6>Add your comment:</h6> -->
<form action="" method="POST">
{% csrf_token %}
{{form|crispy}} <br>
<a class="btn btn-sm btn-info" href="{% url 'comment' %}">Comment</a>
</form>
</div>
{% endblock content %}
**urls.py**
from django.urls import path
from blog_app import views
urlpatterns = [
path("", views.home, name='home'),
path("blog_page/<str:pk>/", views.blog_view, name='blog_page'),
path("like/<str:pk>/", views.like, name="like"),
path("unlike/<str:pk>/", views.unlike, name="unlike"),
path("comment/", views.comment, name="comment"),
]
**views.py**
from django.shortcuts import render
from . models import Blog, Comment, Like, Unlike
from . forms import CommentForm
# Create your views here.
def home(request):
blogs = Blog.objects.all()
context = {'blogs': blogs}
return render(request, 'blog_app/home.html', context)
def blog_view(request, pk):
blog = Blog.objects.get(id=pk)
form = CommentForm()
comments = Comment.objects.filter(blog=blog)
context = {"blog": blog, "comments": comments, "form":form}
return render(request, 'blog_app/blog_page.html', context)
def like(request, pk):
blog = Blog.objects.get(id=pk)
user = request.user
liked, like = Like.objects.get_or_create(blog=blog, user=user)
context = {"liked" : liked, "blog": blog }
return render(request, "blog_app/blog_page.html", context)
def unlike(request, pk):
blog = Blog.objects.get(id=pk)
user = request.user
unliked, unlike = Unlike.objects.get_or_create(blog=blog, user=user)
context = {"unliked" : unliked, 'blog': blog}
return render(request, "blog_app/blog_page.html", context)
def comment(request):
form = CommentForm()
if request.method == 'POST':
form = CommentForm(request.POST)
if form.is_valid():
form.save()
context = {}
return render(request, "blog_app/blog_page.html", context)
Your comment button is just a link, is it normal ? I think, you want to submit your form when you click on?
<div>
<h4>
Comments:
</h4>
{% for comment in comments %}
<div>
{{ user }} <br>
<h5>{{ comment }}</h5>
</div>
{% endfor %}
<!-- <h6>Add your comment:</h6> -->
<form action="{% url 'comment' %}" method="POST">
{% csrf_token %}
{{form|crispy}} <br>
<button type="submit" class="btn btn-sm btn-info">Comment</button>
</form>
</div>
And i think, your problem occured because you dispolay this template from comment view without set blog in context data.
def blog_view(request, pk):
blog = Blog.objects.get(id=pk)
form = CommentForm()
comments = Comment.objects.filter(blog=blog)
context = {"blog": blog, "comments": comments, "form":form}
return render(request, 'blog_app/blog_page.html', context)
def comment(request):
form = CommentForm()
if request.method == 'POST':
form = CommentForm(request.POST)
if form.is_valid():
form.save()
return redirect("blog_page", pk=form.instance.blog.pk)
return HttpResponse(status_code=400) # error case
else:
return HttpResponse(status_code=501) # try to GET page
Better solution is to pass blog pk in the url for being able to render page with error:
path("blog/<int:pk>/comment/", views.comment, name="comment")
<form action="{% url 'comment' blog.pk %}" method="POST">
{% csrf_token %}
{{form|crispy}} <br>
<button type="submit" class="btn btn-sm btn-info">Comment</button>
</form>
def comment(request, pk):
blog = get_object_or_404(Blog, pk=pk)
form = CommentForm()
if request.method == 'POST':
form = CommentForm(request.POST)
if form.is_valid():
form.save()
return redirect("blog_page", pk=blog.pk)
return render(request, "...", {"blog": blog, "form": form})

Django forms User form not summited

I need help with my code. I have read through the code several times and I didn't see anything wrong with it.
The user is expected to submit a job application and redirect the user to the dashboard, but it did not submit the job application neither does it direct the user to the dashboard.
here is my code:
mode.py
from django.db import models
from django.contrib.auth.models import User
class Job(models.Model):
title = models.CharField(max_length=255)
short_description = models.TextField()
long_description = models.TextField(blank=True, null=True)
created_by = models.ForeignKey(User, related_name='jobs', on_delete=models.CASCADE)
created_at = models.DateTimeField(auto_now_add=True)
changed_at = models.DateTimeField(auto_now=True)
def __str__(self):
return self.title
class Application(models.Model):
job = models.ForeignKey(Job, related_name='applications', on_delete=models.CASCADE)
content = models.TextField()
experience = models.TextField()
created_by = models.ForeignKey(User, related_name='applications', on_delete=models.CASCADE)
created_at = models.DateTimeField(auto_now_add=True)
Views.py
from django.shortcuts import render, redirect
from django.contrib.auth.decorators import login_required
from .forms import AddJobForm, ApplicationForm
from .models import Job
def job_detail(request, job_id):
job = Job.objects.get(pk=job_id)
return render(request, 'jobs/job_detail.html', {'job': job})
#login_required
def add_job(request):
if request.method == 'POST':
form = AddJobForm(request.POST)
if form.is_valid():
job = form.save(commit=False)
job.created_by = request.user
job.save()
return redirect('dashboard')
else:
form = AddJobForm()
return render(request, 'jobs/add_job.html', {'form': form})
#login_required
def apply_for_job(request, job_id):
job = Job.objects.get(pk=job_id)
if request.method == 'POST':
form = ApplicationForm(request.POST)
if form.is_valid():
application = form.save(commit=False)
application.job = job
application.created_by = request.user
application.save()
#create_notification(request, job.created_by, 'application', extra_id=application.id)
return redirect('dashboard')
else:
form = ApplicationForm()
return render(request, 'jobs/apply_for_job.html', {'form': form, 'job': job})
forms.py
from django import forms
from .models import Job, Application
class AddJobForm(forms.ModelForm):
class Meta:
model = Job
fields = ['title','short_description','long_description']
class ApplicationForm(forms.ModelForm):
class Meta:
model = Application
fields = ['content', 'experience']
apply_for_job.html
{% extends 'core/base.html' %}
{% block content %}
Apply for job - {{ job.title }}
<form method="post" action=".">
{% csrf_token %}
{% if form.errors %}
{% for error in form.errors %}
<div class="notification is-danger">
{{ error }}
</div>
{% endfor %}
{% endif %}
<div class="field">
<label>Content</label>
<div class="control">
<textarea class="textarea" name="content" id="id_content"></textarea>
</div>
</div>
<div class="field">
<label>Experience</label>
<div class="control">
<textarea class="textarea" name="experience" id="id_experience"></textarea>
</div>
</div>
<div class="field">
<div class="control">
<button class="button is-success">Submit</button>
</div>
</div>
</form>
{% endblock %}
what could be wrong with my code?
the error in this line
<form method="post" action=".">
just delete the point, and it should work,
<form method="post" action="">

Making a topic public to all users in Django

I've got a project where users can enter topics and have the option to make the topic public or private. I want all public topics to be visible to everyone, and private topics to only be visible by the owner of that topic (Project is from Python Crash Course exercise 20-5).
I'm not getting any errors when I click through my project, but when I create a new topic and select the "public" option, it is still not showing up for public viewing.
I've researched similar problems and followed all the suggestions here
How to make a topic public to all users in django? and here Django - How to make the topics, that you create public? Learning Log Project with no luck.
I'm guessing my queryset is not rendering data correctly? I've read the Django documentation on querysets as well, but nothing I've tried has worked. I'm really new to programming so any help would be appreciated. Thank you!
Here's my models.py:
from django.db import models
from django.contrib.auth.models import User
# Create your models here.
class Topic(models.Model):
"""A topic the user is learning about"""
text = models.CharField(max_length=200)
date_added = models.DateTimeField(auto_now_add=True)
owner = models.ForeignKey(User, on_delete=models.CASCADE)
public = models.BooleanField(default=False)
def __str__(self):
"""Return a string representation of the model"""
return self.text
class Entry(models.Model):
"""Something specific learned about a topic"""
topic = models.ForeignKey(Topic, on_delete=models.CASCADE)
text = models.TextField()
date_added = models.DateTimeField(auto_now_add=True)
class Meta:
verbose_name_plural = 'entries'
def __str__(self):
"""Retrun a string representation of the model"""
if len(self.text) < 50:
return f"{self.text}"
else:
return f"{self.text[:50]}..."
views.py:
from django.shortcuts import render, redirect, get_object_or_404
from django.contrib.auth.decorators import login_required
from django.contrib.auth.models import User
from django.http import Http404
from .models import Topic, Entry
from .forms import TopicForm, EntryForm
# Create your views here.
def index(request):
"""The home page for Learning Log"""
return render(request, 'learning_logs/index.html')
#Checks whether logged in user has access to topic
def check_topic_owner(request, topic):
if topic.owner != request.user:
raise Http404
def topics(request):
"""Shows all topics"""
#Gets public topics
public_topics = Topic.objects.filter(public=True).order_by('date_added')
#Gets private topics
if request.user.is_authenticated:
private_topics = Topic.objects.filter(owner=request.user).order_by('date_added')
topics = public_topics | private_topics
else:
topics = public_topics
context = {'topics': topics}
return render(request, 'learning_logs/topics.html', context)
def topic(request, topic_id):
"""Show a single topic and all its entries"""
topic = get_object_or_404(Topic, id=topic_id)
entries = topic.entry_set.order_by('-date_added')
context = {'topic': topic, 'entries': entries}
return render(request, 'learning_logs/topic.html', context)
#login_required
def new_topic(request):
"""Add a new topic"""
if request.method != 'POST':
#No data submitted; create a blank form.
form = TopicForm()
else:
#POST data submitted; process data
form = TopicForm(data=request.POST)
if form.is_valid():
new_topic = form.save(commit=False)
new_topic.owner = request.user
new_topic.save()
return redirect('learning_logs:topics')
#Display a blank or invalid form
context = {'form': form}
return render(request, 'learning_logs/new_topic.html', context)
#login_required
def new_entry(request, topic_id):
"""Add a new entry for a particular topic"""
topic = get_object_or_404(Topic, id=topic_id)
check_topic_owner(request, topic)
if request.method != 'POST':
#No data submitted, create a blank form
form = EntryForm()
else:
#POST data submitted; process data
form = EntryForm(data=request.POST)
if form.is_valid():
new_entry = form.save(commit=False)
new_entry.topic = topic
if new_entry.topic.owner == request.user:
new_entry.save()
else:
return Http404
return redirect('learning_logs:topic', topic_id=topic_id)
#Display a blank or invalid form
context = {'topic': topic, 'form': form}
return render(request, 'learning_logs/new_entry.html', context)
#login_required
def edit_entry(request, entry_id):
"""Edit an existing entry"""
entry = get_object_or_404(Entry, id=entry_id)
topic = entry.topic
check_topic_owner(request, topic)
if request.method != 'POST':
#Initial request; prefill with the current entry
form = EntryForm(instance=entry)
else:
#POST data submitted; process data
form = EntryForm(instance=entry, data=request.POST)
if form.is_valid():
form.save()
return redirect('learning_logs:topic', topic_id=topic.id)
context = {'entry': entry, 'topic': topic, 'form': form}
return render(request, 'learning_logs/edit_entry.html', context)
new_topic.html:
{% load bootstrap4 %}
{% block page_header %}
<h3>Add a new topic:</h3>
{% endblock page_header %}
{% block content %}
<form method="post" action="{% url 'learning_logs:new_topic' %}" class="form">
{% csrf_token %}
{% bootstrap_form form %}
<div class="form-check">
<input class="form-check-input" type="checkbox" value=True id="public" />
<label class="form-check-label" for="public">
<p>Make post public?<p/>
</label>
</div>
{% buttons %}
<button name="submit" class="btn btn-primary">Add topic</button>
{% endbuttons %}
</form>
{% endblock content %}
And forms.py:
from .models import Topic, Entry
class TopicForm(forms.ModelForm):
class Meta:
model = Topic
fields = ['text']
labels = {'text': ''}
class EntryForm(forms.ModelForm):
class Meta:
model = Entry
fields = ['text']
labels = {'text': ''}
widgets = {'text': forms.Textarea(attrs={'cols': 80})}
And topics.html:
{% block page_header %}
<h1>Topics</h1>
{% endblock page_header %}
{% block content %}
<ul>
{% for topic in topics %}
<li><h4>
{{ topic }}
</h4></li>
{% empty %}
<li><h4>No topics have been added yet.</h4></li>
{% endfor %}
</ul>
<h4>Add a new topic</h4>
{% endblock content %}
Edit:
I've gotten the project to work as expected now with the help from hasnain095. Here is my updated new_topic.html. I still don't understand how the checkbox is being generated since I've deleted the html which I thought was specifically generating it, but since it's still working, I'm content.
{% extends "learning_logs/base.html" %}
{% load bootstrap4 %}
{% block page_header %}
<h3>Add a new topic:</h3>
{% endblock page_header %}
{% block content %}
<form method="post" action="{% url 'learning_logs:new_topic' %}" class="form">
{% csrf_token %}
{% bootstrap_form form %}
{% buttons %}
<button name="submit" class="btn btn-primary">Add topic</button>
{% endbuttons %}
</form>
{% endblock content %}
I think the issue is that you've only specified the field 'text in your Topic Form:
class TopicForm(forms.ModelForm):
class Meta:
model = Topic
fields = ['text']
labels = {'text': ''}
but in new_topic.html file, you have only one checkbox input, no place to enter the text
<div class="form-check">
<input class="form-check-input" type="checkbox" value=True id="public" />
<label class="form-check-label" for="public">
<p>Make post public?<p/>
</label>
</div>
{% buttons %}
<button name="submit" class="btn btn-primary">Add topic</button>
{% endbuttons %}
Your checkbox for "Make post public?" is getting mapped to the field "text" of your Topic.
To fix do:
class TopicForm(forms.ModelForm):
class Meta:
model = Topic
fields = ['text', 'public']
labels = {'text': ''}
and
<div class="form-check">
<input class="form-check-input" type="checkbox" value=True id="public" />
<label class="form-check-label" for="public">
<p>Make post public?<p/>
</label>
<input class="form-input" type="input" value=True id="text1" />
<label class="form-label" for="text1">
<p>Text<p/>
</label>
</div>
Use unions to add to a queryset:
def topics(request):
"""Shows all topics"""
# Gets public topics (renamed to topic_set to not shadow function name)
topic_set = Topic.objects.filter(public=True).order_by('date_added')
# Add private topics, if any. We save some work by not including the public
# topics.
if request.user.is_authenticated:
topic_set = topic_set.union(
Topic.objects.filter(public=False, owner=request.user)
)
context = {'topics': topic_set}
return render(request, 'learning_logs/topics.html', context)
Side note: add indexes to fields you filter on:
class Topic(models.Model):
"""A topic the user is learning about"""
text = models.CharField(max_length=200)
date_added = models.DateTimeField(auto_now_add=True)
owner = models.ForeignKey(User, on_delete=models.CASCADE)
public = models.BooleanField(default=False, db_index=True)
def __str__(self):
"""Return a string representation of the model"""
return self.text
It's working for me after use union to append private topics to public topic, but there maybe some different. list below, hope will help:
views.py
def check_topic_owner(topic, request):
if not topic.public:
if topic.owner != request.user:
raise Http404
def topics(request):
#Gets public topics
public_topics = Topic.objects.filter(public=True)
#Gets private topics and append the public topic
if request.user.is_authenticated:
private_topics = Topic.objects.filter(owner=request.user)
topics = public_topics.union(private_topics).order_by('date_added')
else:
topics = public_topics
context = {'topics': topics}
return render(request, 'learning_logs/topics.html', context)
models.py
class Topic(models.Model):
text = models.CharField(max_length=200)
date_added = models.DateTimeField(auto_now_add=True)
owner = models.ForeignKey(User, on_delete=models.CASCADE)
public = models.BooleanField(default=False)
def __str__(self):
return self.text

Django - Query To Check if Item In Many to Many Relationship Field

I have a User and a Deal model as shown below. The User model has a 'favorites' field which is a many to many relationship with the Deal model.
I'm trying to allow a user to save a Deal to their Favorites. I have tested both the favorite and remove_favorite views and both are doing exactly what they are supposed to do.
Here's My Issue -- The conditional statement on my deal_detail.html page which checks to see if the current deal on the page is a favorite of the logged in user doesn't seem to be working.
{% if deal_detail in user.favorites %}
I'm just having a hard time wrapping my head around how to check this.
class User(AbstractBaseUser, PermissionsMixin):
email = models.EmailField(unique=True, error_messages={'unique':"This email has already been registered."})
username = models.CharField(max_length=40, default='')
first_name = models.CharField(max_length=40, default='', blank=True)
last_name = models.CharField(max_length=40, default='', blank=True)
date_joined = models.DateTimeField(default=timezone.now)
favorites = models.ManyToManyField(Deal, related_name='favorited_by', null=True, blank=True)
class Deal(models.Model):
title = models.CharField(max_length=200)
slug = models.SlugField(max_length=140, unique=True)
description = models.TextField(default='')
My corresponding views look like this:
def deal_by_detail(request, slug):
deal_detail = Deal.objects.get(slug=slug)
user = request.user
return render(request, 'deals/deal_detail.html', {'deal_detail': deal_detail, 'user': user})
#login_required(login_url='/accounts/sign_in/')
def favorite(request, pk):
if request.method == 'POST':
favorite = Deal.objects.get(pk=pk)
user = request.user
user.favorites.add(favorite)
messages.add_message(request, messages.INFO, 'Deal Favorited.')
return redirect('home')
#login_required(login_url='/accounts/sign_in/')
def remove_favorite(request, pk):
if request.method == 'POST':
favorite = Deal.objects.get(pk=pk)
user = request.user
user.favorites.remove(favorite)
messages.add_message(request, messages.INFO, 'Deal Removed.')
return redirect('home')
My form deal_detail.html looks like this:
{% if deal_detail in user.favorites %}
<form id="favorite{{deal_detail.id}}" method="POST" action="{% url 'deals:favorite' deal_detail.id %}">
{% csrf_token %}
<input type="hidden" name="supporttype" />
<input type="submit" value="Add Deal to Favorites" />
</form>
{% else %}
<form id="favorite{{deal_detail.id}}" method="POST" action="{% url 'deals:remove_favorite' deal_detail.id %}">
{% csrf_token %}
<input type="hidden" name="supporttype" />
<input type="submit" value="Remove Deal From Favorites" />
</form>
{% endif %}
I believe you are just missing the .all after the manytomany field. Then it should be able to run the check and function as you intended
{% if deal_detail in user.favorites.all %}

Updating user in django

In my application, I used email and password for user authentication, which works fine. However, I want to offer the user the option of adding other information to their account like first names, last names, and dates of birth.
I have a change form in myapp.forms.py
class MyChangeForm(forms.ModelForm):
"""
Form for editing an account.
"""
first_name = forms.CharField(widget=forms.TextInput, label="First name")
last_name = forms.CharField(widget=forms.TextInput, label="Last name")
date_of_birth = forms.DateField(widget=forms.DateField, label="Date of birth")
class Meta:
model = MyUser
fields = ['first_name', 'last_name', 'date_of_birth']
def save(self, commit=True):
user = super(MyChangeForm, self).save(commit=False)
if commit:
user.save()
return user
in my views.py, I have the following method for updating
#login_required(login_url='/')
def update_user(request):
if request.method == 'POST':
form = MyChangeForm(request.POST, instance=request.user)
if form.is_valid():
user = form.save(commit=False)
user.save()
return HttpResponseRedirect('/')
else:
form = MyChangeForm(instance=request.user)
return render_to_response('update_user.html', context_instance=RequestContext(request))
and my update_user.html is as follows
{% extends 'user_base.html' %}
{% block content %}
<div class="col-sm-3 col-sm-offset-5">
<h1> Update User</h1>
<form method='POST' action='/update_user/'> {% csrf_token %}
<ul>
{{ form.as_table }}
</ul>
<input type='Submit' class='btn btn-primary btn-block'>
</form>
</div>
{% endblock %}
However, when I serve the file I see this:
As seen here, there's no way to enter my fields!
How can I fix this? It's probably easy, but I'm getting tunnel vision.
erip
Add form to the context, for example like this:
render('update_user.html', {'form': form})

Categories