How add follow button to profile in django getstream - django

I try to add follow button in django with Getstream.io app.
Following the getstream tutorial, django twitter, I managed to create a list of users with a functioning follow button as well as active activity feed. But when i try add follow button on user profile page, form send POST but nothing happends later.
I spend lot of time trying resolve this, but i'm still begginer in Django.
Code:
Follow model:
class Follow(models.Model):
user = models.ForeignKey('auth.User', related_name = 'follow', on_delete = models.CASCADE)
target = models.ForeignKey('auth.User', related_name ='followers', on_delete=models.CASCADE)
created_at = models.DateTimeField(auto_now_add = True)
class Meta:
unique_together = ('user', 'target')
def unfollow_feed(sender, instance, **kwargs):
feed_manager.unfollow_user(instance.user_id, instance.target_id)
def follow_feed(sender, instance, **kwargs):
feed_manager.follow_user(instance.user_id, instance.target_id)
signals.post_delete.connect(unfollow_feed, sender=Follow)
signals.post_save.connect(follow_feed, sender=Follow)
Views:
def user(request, username):
user = get_object_or_404(User, username=username)
feeds = feed_manager.get_user_feed(user.id)
activities = feeds.get()['results']
activities = enricher.enrich_activities(activities)
context = {
'user': user,
'form': FollowForm(),
'login_user': request.user,
'activities': activities,
}
return render(request, 'profile/user.html', context)
def follow(request):
form = FollowForm(request.POST)
if form.is_valid():
follow = form.instance
follow.user = request.user
follow.save()
return redirect("/timeline/")
def unfollow(request, target_id):
follow = Follow.objects.filter(user=request.user, target_id=target_id).first()
if follow is not None:
follow.delete()
return redirect("/timeline/")
Forms:
class FollowForm(ModelForm):
class Meta:
exclude = set()
model = Follow
Urls:
path('follow/', login_required(views.follow), name='follow'),
path('unfollow/<target_id>/', login_required(views.unfollow), name='unfollow'),
And user.html
<form action="{% if request.user in User.followers.all %}{% url 'unfollow' target.id %}{% else %}{% url 'follow' %}{% endif %}" method="post">
{% csrf_token %}
<input type="hidden" id="id_target" name="target" value="{{target.id}}">
<input type="hidden" id="id_user" name="user" value="{{user.id}}">
<button type="submit" class="btn btn-primary btn-sm" value="Create" />
{% if request.user in User.followers.all %}
Unfollow
{% else %}
Follow
{% endif %}
</button>
</form>
This form work in list user page:
{% for one, followed in following %}
<div class="col-md-3 col-sm-6 col-xs-12">
<div class="card">
<div class="card-body">
{% include "profile/_user.html" with user=one %}
<form action="{% if followed %}{% url 'unfollow' one.id %}{% else %}{% url 'follow' %}{% endif %}" method="post">
{% csrf_token %}
<input type="hidden" id="id_target" name="target" value="{{one.id}}">
<input type="hidden" id="id_user" name="user" value="{{user.id}}">
<button type="submit" class="btn btn-primary btn-sm" value="Create" />
{% if followed %}
Przestań obserwować
{% else %}
Obserwuj
{% endif %}
</button>
</form>
</div>
</div>
</div>
{% if forloop.counter|divisibleby:'4' %}
<div class="clearfix visible-sm-block visible-md-block visible-lg-block"></div>
{% elif forloop.counter|divisibleby:'2' %}
<div class="clearfix visible-sm-block"></div>
{% endif %}
{% endfor %}
</div>
And user list Views.py
def discover(request):
users = User.objects.order_by('date_joined')[:50]
login_user = User.objects.get(username=request.user)
following = []
for i in users:
if len(i.followers.filter(user=login_user.id)) == 0:
following.append((i, False))
else:
following.append((i, True))
login_user = User.objects.get(username=request.user)
context = {
'users': users,
'form': FollowForm(),
'login_user': request.user,
'following': following
}
return render(request, 'uzytkownicy.html', context)

Related

Django: User Login only working with terminal created users

I'm only new to django & this is my first time posting on stack overflow so appologies if I havent done this right.
My problem is that when I use my login function, it only seems to work with those created with the createsuperuser command in the terminal. Those created within the website just dont work.
The users show within the admin panel and have a password within them.
models.py
class Trickster_User(AbstractBaseUser, PermissionsMixin):
UserID = models.AutoField(primary_key=True)
Email = models.EmailField(('Email Address'), unique=True)
Username = models.CharField(('Username'),max_length=25, unique=True)
FirstName = models.CharField(('First Name'),max_length=25)
LastName = models.CharField(('Last Name'),max_length=25)
is_staff = models.BooleanField(default=False)
is_active = models.BooleanField(default=True)
objects = CustomUserManager()
USERNAME_FIELD = 'Email'
REQUIRED_FIELDS = ['Username', 'FirstName', 'LastName']
def __str__(self):
return self.FirstName + ' ' + self.LastName
views.py
def user_login(request):
context = {}
user = request.user
if user.is_authenticated:
return redirect('home')
if request.method == "POST":
form = UserAuthenticationForm(request.POST)
if form.is_valid():
Email = request.POST['Email']
password = request.POST['password']
user = authenticate(Email=Email, password=password)
if user is not None:
login(request, user)
return redirect('home')
else:
form = UserAuthenticationForm()
context['user_login'] = form
return render(request, 'authentication/login.html', context)
forms.py
class UserAuthenticationForm(forms.ModelForm):
Email = forms.EmailField(widget=forms.EmailInput(attrs={'class':'form-control'}))
password = forms.CharField(label='password', widget=forms.PasswordInput(attrs={'class':'form-control'}))
class Meta:
model = Trickster_User
fields = ('Email', 'password')
def clean(self):
Email = self.cleaned_data['Email']
password = self.cleaned_data['password']
if not authenticate(Email=Email, password=password):
raise forms.ValidationError("Invalid Login")
login.html
{% block content %}
<div class="shadow p-4 mb-5 bg-body rounded">
<h1> Login </h1>
<br/><br/>
<form action="" method=POST enctype="multipart/form-data">
{% csrf_token %}
{% for feild in user_login %}
<p>
{{ feild.label_tag }}
{{ feild}}
{% if feild.help_text %}
<small style="color: grey">{{ feild.help_text }}</small>
{% endif %}
{% for errors in field.errors %}
<p style="color: red">{{ feild.errors }}</p>
{% endfor %}
{% if user_login.non_feild_errors %}
<div style="color:red";>
<p>{{ user_login.non_feild_errors }}</p>
</div>
{% endif %}
</p>
{% endfor %}
<button type="submit" class="btn btn-primary">Login</button>
</form>
</div>
{% endblock %}
Code to register users:
views.py
def register_user(request):
context = {}
if request.method == "POST":
form = UserRegistrationForm(request.POST)
if form.is_valid():
form.save()
Email = form.cleaned_data.get('Email')
raw_password = form.cleaned_data.get('password1')
user = authenticate(Email=Email, password=raw_password)
login(request, user)
messages.success(request, ("Registration Successful! Password"))
return redirect('home')
else:
context['UserRegistrationForm'] = form
else:
form = UserRegistrationForm()
context['UserRegistrationForm'] = form
return render(request, 'authentication/register_user.html', context)
register_user.html
{% block content %}
{% if form.errors %}
<div class="alert alert-warning alert-dismissible fade show" role="alert">
There was an error with your form!
<button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button>
</div>
{% endif %}
<div class="shadow p-4 mb-5 bg-body rounded">
<h1> Register </h1>
<br/><br/>
<form action="{% url 'register_user' %}" method=POST enctype="multipart/form-data">
{% csrf_token %}
{% for feild in UserRegistrationForm %}
<p>
{{ feild.label_tag }}
{{ feild}}
{% if feild.help_text %}
<small style="color: grey">{{ feild.help_text }}</small>
{% endif %}
{% for errors in field.errors %}
<p style="color: red">{{ feild.errors }}</p>
{% endfor %}
</p>
{% endfor %}
<button type="submit" class="btn btn-primary">Submit</button>
</form>
</div>
{% endblock %}
Ive seen one other post on something simmilar to this but the only solution posted was to change the 'is_active' status to True by default.
I tried this and am still running into same issue.

Django reference multiple image in template

Hi I am letting the user upload multiple images per project but so far the images are not displayed. In projects.html all projects should be displayed and the title and the describtion work so far. But the main-image doesn´t show up. In single-project all images should be displayed.
What do I have to change in my models.py?
Thanks in forward
models.py
class Project(models.Model):
title = models.CharField(max_length=200)
describtion = models.TextField(null=True, blank=True)
id = models.UUIDField(default=uuid.uuid4, unique=True, primary_key=True, editable=False)
class ProjectImage(models.Model):
project = models.ForeignKey(Project, on_delete=models.CASCADE)
featured_images = models.FileField()
forms.py
class ProjectForm(ModelForm):
featured_images = forms.ImageField(widget=ClearableFileInput(attrs={'multiple':True}))
class Meta:
model = Project
fields = ['title', 'describtion', 'featured_images']
views.py
def createProject(request):
form = ProjectForm()
if request.method == 'POST':
form = ProjectForm(request.POST)
images = request.FILES.getlist('image')
if form.is_valid():
project = form.save()
for i in images:
ProjectImage(project=project, image=i).save()
context = {'form':form}
return render(request, 'projects/project_form.html', context)
def projects(request):
projects = Project.objects.all()
context = {"projects":projects}
return render(request, 'projects/projects.html', context)
def project(request, pk):
projectObj = Project.objects.get(id=pk)
return render(request, 'projects/single-project.html', {'project':projectObj})
projects.html
{% for project in projects %}
<div class="column">
<div class="card project">
<a href="{% url 'project' project.id %}" class="project">
<img class="project__thumbnail" src="{{project.featured_images.url}}" alt="project thumbnail" />
<div class="card__body">
<h3 class="project__title">{{project.title}}</h3>
<h3 class="project__title">{{project.price}} €</h3>
</div>
</a>
</div>
</div>
{% endfor %}
single-project.html
<h3 class="project__title">{{project.title}}</h3>
<h3 class="project__title">{{project.price}} €</h3>
<h3 class="singleProject__subtitle">Infos zum Produkt</h3>
{{project.describtion}}
project_form.html
<form class="form" method="POST" enctype="multipart/form-data">
{% csrf_token %}
{% for field in form %}
<div class="form__field">
<label for="formInput#text">{{field.label}}</label>
{{field}}
</div>
{% endfor %}
<input class="btn btn--sub btn--lg my-md" type="submit" value="Submit" />
</form>
To access the images of a project, you need to use the related manager in your templates:
projects.html
{% for project in projects %}
<div class="column">
<div class="card project">
<a href="{% url 'project' project.id %}" class="project">
<img class="project__thumbnail" src="{{project.projectimage_set.all.0.featured_images.url}}" alt="project thumbnail" />
<div class="card__body">
<h3 class="project__title">{{project.title}}</h3>
<h3 class="project__title">{{project.price}} €</h3>
</div>
</a>
</div>
</div>
{% endfor %}
I assumed that by "main-image" you mean the first image of the project.
single-project.html
<h3 class="project__title">{{project.title}}</h3>
<h3 class="project__title">{{project.price}} €</h3>
<h3 class="singleProject__subtitle">Infos zum Produkt</h3>
{{project.describtion}}
{% for projectimage in project.projectimage_set.all %}
<img src="{{projectimage.featured_images.url}}"/>
{% endfor %}
To avoid the N+1 query problem, you can also change the query in your view:
views.py
def projects(request):
projects = Project.objects.all().prefetch_related('projectimage_set')
context = {"projects":projects}
return render(request, 'projects/projects.html', context)

uploading multiple files in django form and function in views

I am trying to upload multiple files in Django form. I followed multiple methods. I am successful via models to views but I want via models to forms to views. I followed Use view/form in Django to upload a multiple files this question but my form is not submitting. Here I am sharing my codes. I hope to get the mistake I am doing by any expert.
#models.py
class Question(models.Model):
description = models.TextField(blank=True, null=True)
created_by = models.ForeignKey(User, blank=False, on_delete=models.CASCADE)
def __str__(self):
return self.description
class QuestionFile(models.Model):
question = models.ForeignKey(
Question, on_delete=models.CASCADE, related_name='files', null=True, blank=True)
file = models.FileField(
'files', upload_to=path_and_rename, max_length=500, null=True, blank=True)
def __str__(self):
return str(self.question)
#forms.py
from django import forms
from .models import *
class QuestionForm(forms.ModelForm):
class Meta:
model = Question
fields = ['description']
class QuestionFileForm(QuestionForm): # extending Questionform
file = forms.FileField(
widget=forms.ClearableFileInput(attrs={'multiple': True}))
class Meta(QuestionForm.Meta):
fields = QuestionForm.Meta.fields + ['file', ]
def clean(self):
cleaned_data = super().clean()
description = cleaned_data.get("description")
file = cleaned_data.get("file")
if not description and not file:
self.add_error(
'description', 'Kindly describe the question details or upload any file')
#views.py
def questionView(request):
if request.method == 'POST':
form = QuestionFileForm(request.POST or None, request.FILES or None)
files = request.FILES.getlist('file')
if form.is_valid():
question = form.save(commit=False)
question.created_by = request.user
# add everything needed to add here
question.save()
if files: # check if user has uploaded some files
for file in files:
QuestionFile.objects.create(question=question, file=file)
messages.success(request, 'Question asked successfully.')
return redirect('url_name')
else:
form = QuestionFileForm()
context = {
"page_title": "Ask a Math Question",
"form": form
}
return render(request, 'template.html', context)
#template.html
{% extends 'base.html' %}
<!-- title -->
{% block title %}{{ page_title }}{% endblock title %}
<!-- body -->
{% block content %}
<div class="ask_question text-center">
<!--for message-->
{% if messages %} {% for message in messages %}
<div
{% if message.tags %}
class="alert alert-{{ message.tags }} text-center"
{% endif %}
>
{{ message }}
</div>
{% endfor %} {% endif %}
<form
method="POST"
action="{% url 'fask_question' %}"
novalidate
class="needs-validation"
enctype="multipart/form-data"
>
{% csrf_token %}
<div class="mb-3">
<input
type="file"
class="clearablefileinput form-control-file"
name="files"
id="exampleFormControlFile1"
multiple
/>
</div>
<div class="mb-3">
<textarea
class="form-control"
id="exampleFormControlTextarea1"
rows="8"
placeholder="Type your question here"
name="description"
></textarea>
</div>
<button type="submit" class="btn">Submit</button>
</form>
</div>
{% endblock %}
I am unable to understand where I am making the mistake that my form is not submitting.
If anyone can help I will be grateful.
Thanks in advance.
Try to pass the form from the context in to the template
Change this part of your template
<form
method="POST"
action="{% url 'fask_question' %}"
novalidate
class="needs-validation"
enctype="multipart/form-data"
>
{% csrf_token %}
<div class="mb-3">
<input
type="file"
class="clearablefileinput form-control-file"
name="files"
id="exampleFormControlFile1"
multiple
/>
</div>
<div class="mb-3">
<textarea
class="form-control"
id="exampleFormControlTextarea1"
rows="8"
placeholder="Type your question here"
name="description"
></textarea>
</div>
<button type="submit" class="btn">Submit</button>
</form>
To
<form
method="POST"
action="{% url 'fask_question' %}"
novalidate
class="needs-validation"
enctype="multipart/form-data"
>
{% csrf_token %}
{{ form }}
<button type="submit" class="btn">Submit</button>
</form>

How to add a form in an html page in django

I want to add comments form a specific html which has it's own views and models and I do not want to create a new html file like comment.html which will only display the form and its views. I want users to be able to comment right underneath a post, so that users don't have to click a button such as "add comment" which will take them to a new page with the "comment.form" and then they can comment. Basically want a page with all transfer news and their respective comments as well as a comment-form under the old comment. But I'm stuck. I can add comments manually from the admin page and it's working fine, but it seems that I have to create another url and html file to display the comment form and for users to be able to add comments(btw I'm trying to build a sports related website). Thanks in advance!
My models.py:
class Transfernews(models.Model):
player_name = models.CharField(max_length=255)
player_image = models.CharField(max_length=2083)
player_description = models.CharField(max_length=3000)
date_posted = models.DateTimeField(default=timezone.now)
class Comment(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
transfernews = models.ForeignKey(Transfernews, related_name="comments", on_delete=models.CASCADE)
body = models.TextField()
date_added = models.DateTimeField(auto_now_add=True)
def __str__(self):
return '%s - %s' % (self.transfernews.player_name, self.user.username)
My forms.py :
class CommentForm(forms.ModelForm):
class Meta:
model = Comment
fields = ('body', 'transfernews')
My views.py :
def addcomment(request):
model = Comment
form_class = CommentForm
template_name = 'transfernews.html'
def transfer_targets(request):
transfernews = Transfernews.objects.all()
form = CommentForm(request.POST or None)
if form.is_valid():
new_comment = form.save(commit=False)
new_comment.user = request.user
new_comment.save()
return redirect('transfernews/')
return render(request, 'transfernews.html', {'transfernews': transfernews})
My urls.py:
path('transfernews/', views.transfer_targets, name='transfernews'),
My transfernews.html:
<h2>Comments...</h2>
{% if not transfernew.comments.all %}
No comments Yet...
{% else %}
{% for comment in transfernew.comments.all %}
<strong>
{{ comment.user.username }} - {{ comment.date_added }}
</strong>
<br/>
{{ comment.body }}
<br/><br/>
{% endfor %}
{% endif %}
<hr>
<div>Comment and let us know your thoughts</div>
<form method="POST">
{% csrf_token %}
<input type="hidden" value="{{ transfernew.id}}">
<div class="bg-alert p-2">
<div class="d-flex flex-row align-items-start"><textarea class="form-control ml-1 shadow-none textarea"></textarea></div>
<div class="mt-2 text-right"><button class="btn btn-primary btn-sm shadow-none" type="submit">
Post comment</button><button class="btn btn-outline-primary btn-sm ml-1 shadow-none" type="button">Cancel</button></div>
</div>
</div>
</form>
Here's how you can do it :
First, add a field in your CommentForm :
class CommentForm(forms.ModelForm):
class Meta:
model = Comment
fields = ('body', 'transfernews')
Then in your template, you can set an hidden input in the form to link the comment to the transfernews :
{% if form.errors %}
<p>There are errors in your form :</p>
<ul>{{ form.errors }}</ul>
{% endif %}
<form method="POST">
{% csrf_token %}
{# Add this next line #}
<input type="hidden" value="{{ transfernew.id}}">
<div class="bg-alert p-2">
<div class="d-flex flex-row align-items-start">
<textarea class="form-control ml-1 shadow-none textarea" name="body"></textarea>
</div>
<div class="mt-2 text-right">
<button class="btn btn-primary btn-sm shadow-none" type="submit">Post comment</button>
<button class="btn btn-outline-primary btn-sm ml-1 shadow-none" type="button">Cancel</button>
</div>
</div>
</form>
Then in your view :
def transfer_targets(request):
transfernews = Transfernews.objects.all()
form = CommentForm(request.POST or None)
if form.is_valid():
new_comment = form.save(commit=False)
new_comment.user = request.user
new_comment.save()
return redirect('transfernews')
return render(request, 'transfernews.html', {
'transfernews': transfernews,
'form': form
})

redirect to different pages in django after login

When i click on the sell product link from homepage it redirects to the login page and after login done it redirects to the homepage and i have to again click on the sell product link to fill the form.I want to redirect to the sell_product page after login instead of homepage.How can i do that ?? How can i redirect to the different pages from one signin url.
urls.py
path('signin/user/',views.users_signin,name='users_signin'),
path('sell/product/',views.sell_product,name='sell_product'),
views.py
def users_signin(request):
if request.method == "POST":
form = UserSigninForm(request.POST)
username = form['username'].value()
password = form['password'].value()
user = authenticate(username=username,password=password)
login(request,user)
return redirect('shop:home')
else:
form = UserSigninForm()
return render(request,'shop/users_signin.html',{'form':form})
def sell_product(request):
if request.user.is_authenticated:
if request.method == "POST":
form = SellProductForm(request.POST,request.FILES)
if form.is_valid():
myproduct = form.save(commit=False)
myproduct.seller = request.user
myproduct.save()
messages.success(request,'Your Product has been posted successfully.!!')
return redirect("shop:home")
else:
form = SellProductForm()
return render(request,'shop/sell_product.html',{'form':form})
else:
messages.error(request,'please login first')
return redirect('shop:users_signin')
sell_product.html
{% extends "shop/base.html" %}
{% load bootstrap4 %}
<title>{% block title %}Sell a Product{% endblock %}</title>
{% block content %}
<div class="container">
<div class="row">
<div class="col-lg-6 offset-lg-3 col-sm-10 offset-sm-1">
<div class="card my-5">
<div class="card-header text-center">
Sell Your Product
</div>
<div class="card-body">
<form action="{% url 'shop:sell_product' %}" method="post" enctype="multipart/form-data">
{% csrf_token %}
{% bootstrap_form form %}
<input type="submit" class="btn btn-success text-center w-100 mb-3" value="Submit">
</form>
</div>
</div>
</div>
</div>
</div>
{% endblock %}
base.html
<li class="nav-item">
<a class="nav-link" href="{% url 'shop:sell_product' %}">Sell a Product</a>
</li>
forms.py
class SellProductForm(forms.ModelForm):
class Meta:
model = Product
fields = ['name','image','category', 'description', 'brand', 'quantity', 'price', 'shipping_fee']
class UserSigninForm(forms.Form):
username = forms.CharField()
password = forms.CharField(widget=forms.PasswordInput)
You may specify the next parameter in the url to set the redirect page after login.
Try
return redirect('%s?next=%s' % (reverse('shop:users_signin'), request.path))
See https://docs.djangoproject.com/en/2.2/topics/auth/default/#limiting-access-to-logged-in-users-that-pass-a-test
You may also use a #login_required decorator so as to omit the 'if-else` block that ensures the authentication.