Calling user follow/follower list in Django - django

Hi Djangonauts,
I am trying to get the user follows list(example like Instagram 'A' follows 'B') in the templates. I have tried almost everything I am not able to call it in the templates. What am I doing wrong
My models (It's a monkey patch to the Django User model)
class Profile(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
#other profile fields
class Contact(models.Model):
user_from = models.ForeignKey(User, related_name='supporter')
user_to = models.ForeignKey(User, related_name='leader')
def __str__(self):
return '{} follows {}'.format(self.user_from, self.user_to)
User.add_to_class(
'following',
models.ManyToManyField(
'self',
through=Contact,
related_name='followers',
symmetrical=False))
My views (not sure if this is correct)
def get_context_data(self, **kwargs):
context = super(ProfileView, self).get_context_data(**kwargs)
context['follows'] = Contact.objects.filter(
user_from__isnull=False,
user_from__username__iexact=self.kwargs.get('username'))
context['followers'] = Contact.objects.filter(
user_to__isnull=False,
user_to__username__iexact=self.kwargs.get('username'))
return context
My Templates
{{user}} follows {{user.supporter.count}} members #This works shows the correct number
{% for contact in Contact.objects.all %}
{{contact.user_to.username}} # I am not able to get this part to work
{% endfor %}

The bit that isn't working is the loop, because Contact is not defined in the template. But I don't understand why you think you need to access it. You should be looping through the many-to-many field on the user:
{% for follow in user.following.all %}
{{ follow.username }}
{% endfor %}

Related

Django: display many to many relationship through a model in template

I have this ManyToMany relationship through an intermediary model:
class Group(models.Model):
members = models.ManyToManyField(Student, through='NamedMembershipClub')
class Membership(models.Model):
year = models.IntegerField()
user = models.ForeignKey(User, on_delete=models.CASCADE)
group = models.ForeignKey(Group, on_delete=models.CASCADE)
I'm trying to display members with the year they joined in my template.
I read on this post that I should use members_set.all
{% for member in object.members_set.all %}
<p>{{member.user.first_name}} {{member.year}}</p>
{% endfor %}
But it doesn't produce any output, the loop is just not entered because the set is empty.
I also tried :
{% for member in object.members.all %}
<p>{{member.first_name}}</p>
{% endfor %}
The view:
class DetailGroupView(TemplateView):
template_name = 'group/detail.html'
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
self.object = Group.object.get(slug=kwargs['slug'])
context['object'] = self.object
return context
Which gives some satisfaction because I can display the user but not the associated data in the Membership model.
Is there any way to get the set directly in the template ? Thanks!
I'm running Django 3.0.

Django custom Management: Unable for an "administrator" to update an user

I'm currently creating a django customer management/admin interface for a web application(I know of the built-in one, but as part of this project, a custom one needs to be created).
I'm supposed to be able to create/update/delete users from this interface, while connected as a Manager/Admin.
While connected as a manager/admin I can successfully create or delete an user, I'm unable to update one (I keep getting the error that the user "already exists")
Help or the wright direction to follow would be much apreciated as I've been struging with this for a while and am blocked atm.
Hereunder the code.
(models.py) class UserProfile (one to one to built-in Django User class)
class UserProfile(models.Model):
"""
The Class UserProfile extends the built-in "User" class of Django
Used here to add extra fields in the forms
"""
user = models.OneToOneField(User, on_delete=models.CASCADE,verbose_name="User")
vpn_enabled = models.BooleanField(default=False, verbose_name="VPN Enabled")
language = models.CharField(max_length=2, choices=LANGUAGES, default='EN', verbose_name="Language")
birth_date = models.DateField(null=True,blank=True, verbose_name="Birth Date")
address = models.CharField(max_length=200, null=True, blank=True, verbose_name="Address")
postal_code = models.CharField(max_length=50,null=True, blank=True, verbose_name="Postal Code")
country = models.CharField(max_length=20, blank=True, null=True, verbose_name="Country")
class Meta:
verbose_name = 'User Profile'
verbose_name_plural = 'User Profiles'
def __str__(self):
return self.user.username
views.py
#group_required('Administrator', 'Manager')
def update_user(request, id):
user = User.objects.get(id=id)
user_update_form = UserUpdateForm(request.POST or None, instance = user)
user_profile_update_form = UserProfileUpdateForm (request.POST or None, instance = user.userprofile)
if user_update_form.is_valid() and user_profile_update_form.is_valid():
user_update_form.save()
user_profile_update_form.save()
return redirect("manager_home")
context = {
'user_update_form': user_update_form,
'user_profile_update_form': user_profile_update_form,
}
return render (request, "update_user.html", context)
forms.py
class UserUpdateForm(forms.ModelForm):
"""UserUpdateForm custom made class"""
class Meta:
""" Meta definitioon of UserUpdateForm"""
model = User
fields = [
'username',
'last_name',
'first_name',
'email',
]
class UserProfileUpdateForm(forms.ModelForm):
'''UserProfileUpdateForm custom made class'''
class Meta:
"""Meta definition of UserProfileUpdateForm"""
model = UserProfile
fields = [
'language',
'birth_date',
'address',
'postal_code',
'country',
]
template
<!-- template update_user.html -->
{% extends 'base.html' %}
{% block title %} Edit User {% endblock %}
{% block content %}
<form method="POST" class="post-form" action="{% url 'update_user' user.id %}">
{% csrf_token %}
{{user_update_form.as_p}}
{{user_profile_update_form.as_p}}
{{user_update_form.errors}}
<hr>
<button type="submit">Update User</button>
</form>
{% endblock %}
result (while trying to update, for example, user country)
enter image description here
The problem is with the view. If you are using function as a view you need to say explicitly what you do in case of the post request, otherwise everything will be processed as GET request, and this is not something that you want.
#group_required('Administrator', 'Manager')
def update_user(request, id):
if request.method == 'GET':
# get request processing code
# you are missing POST request processing part
if request.method == 'POST':
# post request processing code

Displaying get_context_data in template Django

I am trying to display the get_context_data on the template. I have a method on the model class that I need to call from ProfileView which has two different models. For the Profile View I have Profile Model and for the shippingaddress view I have ShippingAddress Model. And these models are from two different app. I tried the function below and it does not show any error, but when I tried to call it in the Template, It does not show the method.
Views.py
class ProfileView(LoginRequiredMixin, DetailView):
model = Profile
template_name = "account/profile.html"
success_url = "/"
def get_context_data(self, *args, **kwargs):
context = super(ProfileView, self).get_context_data(**kwargs)
context['shipping'] = ShippingAddress.objects.filter(user=self.request.user)
return context
Template code
{{object.get_full_address}}
Models.py
class ShippingAddress(models.Model):
user = models.ForeignKey(settings.AUTH_USER_MODEL,
on_delete=models.CASCADE)
phone_number = PhoneNumberField(null=True, blank=True)
street_address = models.CharField(max_length=300)
province = models.CharField(max_length=300)
city = models.CharField(max_length=50)
country = models.CharField(max_length=50)
zip_code = models.CharField(max_length=10)
def __str__(self):
return str(self.user)
def get_phone_number(self):
return self.phone_number
#property
def get_full_address(self):
return f"{self.street_address}, {self.province}, {self.city}, {self.country}, {self.zip_code}"
object is the context variable that DetailView will add to the context. For your view this would be an instance of Profile. You pass a queryset into the context with the name shipping so you can loop over that:
{% for shipping_address in shipping %}
{{ shipping_address.get_full_address }}
{% endfor %}
Note: You need to loop because one user has multiple Shipping Addresses according to your models.
Note: Also you didn't need to override get_context_data you could simply have written:
{% for shipping_address in request.user.shippingaddress_set %}
{{ shipping_address.get_full_address }}
{% endfor %}
Where shippingaddress_set is the related model name with _set
appended. You can change that by setting related_name on your
foreign key.

how can i display other user information in django

I'm creating a website that the user can look at other users profile but the problem is when the user enter another user profile it show his personal information
this is the urls.py file code
urlpatterns = [
path('user/<str:username>', UserPostListView.as_view(), name='user-posts'),
]
this is the view.py file code
class UserPostListView(ListView):
model = Post = Profile
template_name = 'website/user_posts.html'
def get_queryset(self):
user = get_object_or_404(User, username=self.kwargs.get('username'))
return Post.objects.filter(author=user)
def get_username_field(self):
user = get_object_or_404(User, username=self.kwargs.get('username'))
return Profile.objects.filter(user=user)
this is the models.py file
class Profile(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
age = models.IntegerField(verbose_name='Ålder', default=15,
blank=True)
def get_absolute_url(self):
return reverse('user_posts', kwargs={'pk': self.pk})
def __str__(self):
return f'{self.user.username} Profile'
user_posts.html file
{{ user.get_full_name }}
{{ user.profile.age }}
{{ view.kwargs.username }}
in the template it's show the username but it didnt' show the name and the age.
user is always the current logged-in user. Your view uses the Profile model, so you can either access profile or object.
{{ profile.user.get_full_name }}
{{ profile.age }}
Note, your get_username_field method is never called and does not do anything; you should remove it.
Note also, it's really not a good idea to store age as an integer in the database. That means you somehow have to update it every year, as people have a strange habit of getting older... Better to store the date of birth, and have a method to display the age.
First of all your get_username_field is of no use.
In your views.py,
class UserPostListView(ListView):
model = Profile
template_name = 'website/user_posts.html'
context_object_name = 'user_content'
allow_empty = False #this will show 404 if the username does not exists
def get_queryset(self):
return User.objects.filter(username=self.kwargs['username'])
# you can do it in one line now
Now to show this in html,
{% for user in user_content %}
{{user.get_full_name}}
# rest of your code
{% endfor %}
You can also show posts of that particular user in same way as above.

How to route DetailView to inherit user and slug

I have a fairly simple DetailView:
class TrackDetails(DetailView):
model = Track
And in my urls.py:
url(r'^(?P<slug>[-\w]+)/$', TrackDetails.as_view(), name='track-details'),
The model:
class Track(models.Model):
....
# Variables
track_type_choices = [
('ORG', 'Original'),
('RMX', 'Remix'),
('CLB', 'Collab'),
('LIV', 'Live'),
]
# Model Fields
user = models.ForeignKey(User, unique=False)
title = models.CharField(max_length=100)
desc = models.TextField(max_length=7500)
track_type = models.CharField(max_length=3,
choices=track_type_choices,
default='ORG')
track_type_content = models.CharField(max_length=100,blank=True)
created = models.TimeField(auto_now=True,auto_now_add=False)
upload = models.FileField(upload_to=generate_user_folder_tracks,storage=OverwriteStorage(),validators=[is_mp3])
albumart = models.ImageField(upload_to=generate_user_folder_art,storage=OverwriteStorage(),validators=[is_square_png])
private = models.BooleanField(default=False)
downloadable = models.BooleanField(default=False)
likes = models.ManyToManyField(User, related_name="likes",blank=True)
dislikes = models.ManyToManyField(User, related_name="dislikes",blank=True)
plays = models.BigIntegerField(default=0)
slug = models.SlugField(max_length=50,unique=True)
The model displayed in the view has a "user" field connected to the user model, I want to use this in the url, so that instead of writing "www.domain.com/slug/" I would write "www.domain.com/user/slug" to access the view of the instance.
Additionally, I have extended the User model with a field called "Display_name", I'd like to show this field instead of the username in my template (track_detail.html):
{% include '__header.html' %}
{% load static from staticfiles %}
<div id="track_container">
<div id="track_titleinfo">
<div id="track_artist" class="text">{{ object.user }}</div>
<div id="track_title" class="text">{{ object.title }}</div>
{% if object.track_type == 'ORG' %}
{% else %}
<div id="track_type" class="text">({{object.track_type_content}})</div>
{% endif %}
</div>
</div>
{% include '__footer.html' %}
<img src="/static/users/{{ object.user }}/art/{{ object.slug }}.png" alt="">
The div with the ID "track_artist" displays the raw username (In this case, enitoni), I'd like it to display the display_name (In this case "Ekchö") from the userprofile class of the user who owns the Track instance:
class UserProfile(models.Model):
user = models.OneToOneField(User)
display_name = models.CharField(max_length=50, default="null")
def create_user_profile(sender, instance, created, **kwargs):
if created:
UserProfile.objects.create(user=instance)
post_save.connect(create_user_profile, sender=User)
To include the username in the detail view, you first need to add it to your url patterns.
url(r'^(?P<username>[-\w]+)/(?P<slug>[-\w]+)/$', TrackDetails.as_view(), name='track-details'),
Then, since you are using DetailView, you need to override get_object so that you use the username and slug to fetch the object.
from django.shortcuts imporg get_object_or_404
class TrackDetails(DetailView):
model = Track
def get_object(self, queryset=None):
return get_object_or_404(
Track,
user__username=self.kwargs['username'],
slug=self.kwargs['slug'],,
)
Displaying the display_name of the user in the template is a separate problem. If you have a user, you can follow the one to one key backwards to the profile with user.userprofile. Therefore, in your template you can show the display_name with.
{{ object.user.userprofile.display_name }}
To access username and slug first pass in the two keywords:
url(r'^/(?P<username>\d+)/(?P<slug>[-\w]+)/$', get_userpage, name='track-details'),
Then check if Track.objects.filter(slug=slug, username=username) returns anything:
def get_userpage(request, username, slug):
"""Render user page"""
user = User.objects.get(username=username)
track_song = Track.objects.filter(slug=trackslug, user=user).first()
if track_song:
# return song page for user
else:
# try to return user
track_user = Track.objects.filter(user=user).first()
if track_user:
# return user page
# if nothing returned above
# return 404
Previous suggestions:
you can you use get_object_or_404(Track, slug=slug) in your view to return the correct response.
you could also redirect a user to their unique combination of username and slug using:
redirect('track-username-slug', username=myusername slug=myslug, permanent=True)
where track-username-slug is your named url