Here is my models.py file.
from django.db import models
from django.contrib.auth.models import User
from django.urls import reverse
from django.utils.text import slugify
import misaka
from django.contrib.auth import get_user_model
# Create your models here.
class Category(models.Model):
name = models.CharField(max_length=255, unique=True)
slug = models.SlugField(allow_unicode=True, unique=True)
description = models.TextField(blank=True, default='')
description_html = models.TextField(editable=False, default='',blank=True)
members = models.ManyToManyField(User, through="CategoryMember")
category_pic = models.ImageField(upload_to = 'category_pics', blank=True)
def __str__(self):
return self.name
# WE are saving the model. But before that we are converting
# the name using slugify and description using misaka.
def save(self, *args, **kwargs):
self.slug = slugify(self.name)
self.description_html = misaka.html(self.description)
super().save(*args, **kwargs)
#get_absolute_url is used because it tell the template
# CreateView to go to the page it is directing.
# for this example it is directing to go to single page of a category.
def get_absolute_url(self):
return reverse("categories:single", kwargs={"slug":self.slug})
class Meta:
ordering = ['name']
class CategoryMember(models.Model):
category = models.ForeignKey(Category, related_name = "memberships", on_delete=models.CASCADE)
user = models.ForeignKey(User, related_name="user_categories", on_delete=models.CASCADE)
def __str__(self):
return self.user.username
class Meta:
unique_together= ("category", "user")
This is some part of views.py file
from django.contrib.auth.models import User
from categories.models import CategoryMember, Category
class UserPosts(ListView):
model = Post
template_name = 'posts/user_post_list.html'
def get_queryset(self):
try:
self.post_user = User.objects.prefetch_related("user_of_post_model").get(
username__iexact=self.kwargs.get("username")
)
except User.DoesNotExist:
raise Http404
else:
return self.post_user.user_of_post_model.all()
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
current_user = UserProfileInfo.objects.filter(
user__id__iexact = self.post_user.id
).get()
i=1
user_categories={}
for member in CategoryMember.objects.all():
if member.user == self.post_user:
user_categories.update({i:member.category.name})
i=i+1
else:
print('not found')
print(user_categories)
if current_user.profile_pic:
profile_pic = True
picture = current_user.profile_pic
edited_picture = get_thumbnail(picture, '350x350', quality=99, format='PNG')
else:
profile_pic = False
root = settings.MEDIA_ROOT
import os
root1 = os.path.join(root, 'profile_pics/no-image.png')
picture = root1
edited_picture = get_thumbnail(picture, '350x350', quality=99, format='PNG')
# resizeimage.resize_cover(picture, [200, 100], validate=False)
# rescale_image(picture,width=100,height=100)
current_user1 = current_user
user_info = {
'current_user':current_user,
'user_categories':user_categories,
'picture':edited_picture,
'profile_pic':profile_pic,
'post_user':self.post_user,
}
context['user_info'] = user_info
return context
After rendering the html page i can see that dictionary has values inside. Here is the values printed in terminal.
not found
not found
not found
not found
not found
{1: 'Regression', 2: 'Classification'}
Now, i want to get user_categories in my django template. i have tried in different approaches but can't get user_categories .
this is some part of my django html file.
<h3>Member of Categories</h3>
{# this line shows error #}
{# {{ userinfo[{{user_categories}}] }} #}
{{ userinfo.user_categories.1 }}
{% for categories in userinfo.user_categories %}
{{categories}}
{% endfor %}
<h5 class="techfont">Post written by {{user_info.post_user.username}} : {{post_list.count}} </h5>
This section only renders user_info.post_user.username but not user_info.user_categories.1
see the text below.
Member of categories.
Post written by abc: 1
user_categories is a dictionary, not a list. So try like this:
{% for idx, categories in userinfo.user_categories.items %}
{{idx}}. {{categories}}
{% endfor %}
Related
I have added like and dislike button to Song post When like object is not created if some click on like it is showing intigrity error if like object is already there then it is not rendering that to template.
models.py
Codes in models.py
class Song(models.Model):
song_title = models.CharField(max_length=25)
album = models.ForeignKey(Album, related_name='album_name', on_delete=models.CASCADE, blank=True)
singer = models.ManyToManyField(Singer, blank=True)
language = models.CharField(max_length=25)
class VoteManager(models.Manager):
def get_vote_or_unsaved_blank_vote(self,song,user):
try:
return Vote.objects.get(song=song,user=user)
except ObjectDoesNotExist:
return Vote(song=song,user=user)
class Vote(models.Model):
UP = 1
DOWN = -1
VALUE_CHOICE = ((UP, "👍️"),(DOWN, "👎️"),)
like = models.SmallIntegerField(choices=VALUE_CHOICE)
user = models.ForeignKey(User,on_delete=models.CASCADE)
song = models.ForeignKey(Song, on_delete=models.CASCADE)
voted_on = models.DateTimeField(auto_now=True)
objects = VoteManager()
class Meta:
unique_together = ('user', 'song')
views.py
Codes in views.py
class SongDetailView(DetailView):
model = Song
template_name = 'song/song_detail.html'
def get_context_data(self,**kwargs):
ctx = super().get_context_data(**kwargs)
if self.request.user.is_authenticated:
vote = Vote.objects.get_vote_or_unsaved_blank_vote(song=self.object, user = self.request.user)
if vote.id:
vote_url = reverse('music:song_vote_update', kwargs={'song_id':vote.song.id,'pk':vote.id})
else:
vote_url = reverse('music:song_vote_create', kwargs={'song_id':vote.song.id})
vote_form = SongVoteForm(instance=vote)
ctx['vote_form'] = vote_form
ctx['vote_url'] = vote_url
return ctx
class SongUpdateView(UpdateView):
form_class = SongVoteForm
queryset = Song.objects.all()
def get_object(self,queryset=None):
song = super().get_object(queryset)
user = self.request.user
return song
def get_success_url(self):
song_id = self.kwargs.get('song_id')
return reverse('music:song_detail', kwargs={'pk':song_id})
class SongVoteCreateView(View):
form_class = SongVoteForm
context = {}
def post(self,request,pk=None,song_id=None):
vote_obj,created = Vote.objects.get_or_create(pk=pk)
song_obj = Song.objects.get(pk=song_id)
vote_form = SongVoteForm(request.POST, instance=vote_obj)
if vote_form.is_valid():
new_vote = vote_form.save(commit=False)
new_vote.user = self.request.user
new_vote.song = song_obj
return redirect('/album/')
Song_detail.html
codes in song_detail.html
<form action="{{vote_url}}" method="post" enctype="multipart/form-data">
{% csrf_token %}
{{ vote_form.as_p }}
<button class="btn btn-primary" type="submit" >Vote</button>
</form>
Error Code
This is the error when submitting the like button. Refer here for the traceback
NOT NULL constraint failed: album_vote.song_id
song and user fields are required. So you have to give song and user while creating Vote.
here is full code::
class SongVoteCreateView(View):
form_class = SongVoteForm
context = {}
def post(self,request,pk=None,song_id=None):
song_obj = Song.objects.get(pk=song_id)
vote_obj,created = Vote.objects.get_or_create(song = song_obj, user = request.user)
vote_form = SongVoteForm(request.POST, instance=vote_obj)
if vote_form.is_valid():
vote_form.save()
return redirect('/album/')
also in VoteManager, the code
return Vote(song=song,user=user)
won't create vote, instead you have to use
return Vote.objects.create(song=song,user=user)
I have two models many to many relationships, I am trying to update a field by subtraction two values from the two models and save the changes to the db.
class LeaveBalance(models.Model):
user=models.OneToOneField(User,on_delete=models.CASCADE,primary_key=True,)
Leave_current_balance= models.FloatField(null=True, blank=True, default=None)
Year=models.CharField(max_length=100,default='')
def __unicode__(self):
return self.Year
class NewLeave(models.Model):
user=models.ForeignKey(User,default='',on_delete=models.CASCADE)
leave_balance=models.ManyToManyField(Leave_Balance)
leave=(
('annual','annual'),
('sick','sick'),
)
Leave_type=models.CharField(max_length=100,choices=leave,blank=False,default='')
Total_working_days=models.FloatField(null=True, blank=False)
DirAuth=(
('Pending','Pending'),
('Approved','Approved'),
('Rejected','Rejected'),
)
Director_Authorization_Status=models.CharField(max_length=100,choices=DirAuth,default='Pending',blank=False)
Date_Authorized=models.DateField(null=True,blank=False)
Authorized_by_Director=models.CharField(max_length=100,default='',blank=False)
def __unicode__(self):
return self.Leave_type
here is my form, when a leave is submitted the director is notified by email. the director can login to the system to approve the leave using the form. once the leave is approved, I want to adjust the Leave_current_balance.
class DirectorForm(forms.ModelForm):
class Meta:
model=NewLeave
fields=('Director_Authorization_Status','Authorized_by_Director','Date_Authorized',)
widgets={
'Date_Authorized':DateInput()
}
This is the function that allows the director to approve the leave which throws the error: u'Leave_current_balance'
def unitDirectorForm(request,id):
if request.method=='POST':
getstaffid=NewLeave.objects.get(id=id)
form = DirectorForm(request.POST, instance=getstaffid)
if form.is_valid():
getstaffid = form.save(commit=False)
getstaffid.save()
total_days = getstaffid.Total_working_days
current_balance = getstaffid.user.leave_balance.Leave_current_balance
diff_balance = current_balance - total_days
current_balance = diff_balance
current_balance=form.fields['Leave_current_balance']
current_balance.save()
getstaffid.leave_balance.add(current_balance)
return HttpResponse('You have successfuly Authorise the leave')
else:
#getstaffid=NewLeave.objects.get(id=id)
form=DirectorForm()
#c_balance=Leave_Balance.objects.get()
balance_form = leavebbalanceForm()
return render(request,'managerauthorisedform.html',{'form':form})
You could get this working in another way too. For example:
def on_balance(user_id):
id = user_id
c_balance = LeaveBalance.objects.get(user=id)
current_balance = c_balance.Leave_current_balance
t_days = NewLeave.objects.get(user=id)
total_days = t_days.Total_working_days
current_balance = current_balance - total_days
balance = LeaveBalance.objects.get(user=id)
balance.leave_balance = current_balance
balance.save()
And the above does not cause combined expression error.
Or just a bit simpler:
def on_balance(user_id):
id = user_id
c_balance = LeaveBalance.objects.get(user=id)
current_balance = c_balance.Leave_current_balance
t_days = NewLeave.objects.get(user=id)
total_days = t_days.Total_working_days
current_balance = current_balance - total_days
c_balance.leave_balance = current_balance
c_balance.save()
UPDATE - restructuring the models and views
So the above code works if it's used in an appropriate model/form/view structure, but instead I would suggest you to restructure the whole thing starting from your models. I give you a simple working example (I tested this and works):
My app name is in this example: Myusers1 , so where ever you see that, you can change that name to your app name if needed.
So the Models:
from django.db import models
from django.conf import settings
from django.utils.text import slugify
from django.db.models import F
from django.urls import reverse
class Director(models.Model):
name = models.CharField(max_length = 100, default = '', null = True, verbose_name = 'Name of Director')
def __str__(self):
return self.name
class Staff(models.Model):
TYPE_CHOICES = (
('REGULAR', 'Regular'),
('MANAGER', 'Manager'),
('FRESH', 'Fresh'),
)
name = models.CharField(max_length = 100, default = '', null = True, unique=True, verbose_name = 'Name of staff member')
birthdate = models.DateField(blank = True, verbose_name = 'Birth date')
department = models.CharField(max_length = 100, default = '', null = True, verbose_name = 'Department')
# department could also be a choice field from another table
type = models.CharField(max_length = 20, choices = TYPE_CHOICES, verbose_name = 'Position Type', null = True)
def __str__(self):
return self.name
class LeaveBalance(models.Model):
staff = models.ForeignKey(Staff, to_field='name', on_delete = models.CASCADE, primary_key = False)
Leave_current_balance = models.FloatField(null = True, blank = True, default = '')
date_updated = models.DateTimeField(auto_now_add = True, verbose_name = 'Last Updated date and time')
def __unicode__(self):
return self.Leave_current_balance
class NewLeave(models.Model):
all_staff = Staff.objects.values()
STAFF_CHOICES = [(d['name'], d['name']) for d in all_staff]
staff = models.CharField(max_length = 100, choices = STAFF_CHOICES)
leave_days_to_approve_now = models.FloatField(null = True, blank = False, default = 5.0, verbose_name = 'Leave days for approval now')
LEAVE_CHOICES=(
('annual','annual'),
('sick','sick'),
)
Leave_type = models.CharField(max_length = 100, choices = LEAVE_CHOICES, blank = False, default = '', verbose_name = 'Type of leave')
Total_working_days = models.FloatField(null = True, blank = False, default = 200.0)
APPROVAL_STATUS_CHOICES=(
('Pending','Pending'),
('Approved','Approved'),
('Rejected','Rejected'),
)
Director_Authorization_Status = models.CharField(max_length = 100, choices = APPROVAL_STATUS_CHOICES, default = 'Pending', blank = False)
Date_Authorized = models.DateTimeField(auto_now_add = True, verbose_name = 'date and time of Authorization')
all_directors = Director.objects.values()
DIRECTOR_CHOICES = [(d['name'], d['name']) for d in all_directors]
Authorized_by_Director = models.CharField(max_length = 100, choices = DIRECTOR_CHOICES, default = '', blank = False)
def __unicode__(self):
return self.Leave_type
def get_absolute_url(self):
pass
# return reverse('newleave-detail', kwargs={'pk': self.pk}) # this should be worked out too
def save(self, *args, **kwargs):
staff_name = self.staff
this_staff = Staff.objects.get(name=staff_name)
name = this_staff.name
minus_value = self.leave_days_to_approve_now
if (self.Director_Authorization_Status == 'Approved'):
LeaveBalance.objects.filter(staff = name).update(Leave_current_balance=F('Leave_current_balance') - minus_value)
return super(NewLeave, self).save(*args, **kwargs)
else:
return super(NewLeave, self).save(*args, **kwargs)
In the above, you can see that I created a Director and Staff Model in which you can set as many staff and directors as you want in the Admin back-end. I created the staff Model because maybe not all of the staff will be users, so I think it is just a bit better to keep them separately in the DB from Users.
Important: first create the Director and Staff Models then migrate immediately since the other two tables will depend on them. Then you can create the other two Models.
I also do not think that in the LeaveBalance Model you should keep more things than what I put there. I think Year field for example redundant, since you can always filter by the date and date range in you want in the database.
Then the views (I used simple views only directly from the Models). With using these view classes you do not have to create Forms since it is automatically created from the Models and you can handle them with different functions/methods as Forms in the Views and in the Model classes.
from django.shortcuts import render, redirect
from django.http import HttpResponseRedirect, HttpResponse, HttpRequest
from django.urls import reverse
from django.views import View
from django.views.generic.detail import DetailView
from django.views.generic import ListView, TemplateView
from django.template import loader
from .models import NewLeave
from django.views.generic.edit import FormView, CreateView, DeleteView, UpdateView
from django.urls import reverse_lazy
class NewLeaveCreate(CreateView):
model = NewLeave
fields = '__all__'
def form_valid(self, form):
super().form_valid(form)
auth_status = form.cleaned_data['Director_Authorization_Status']
if (auth_status == 'Approved'):
return redirect('Myusers1:success_page')
elif (auth_status == 'Pending'):
return redirect('Myusers1:pending_success')
else:
return redirect('Myusers1:rejected_success')
class NewLeaveUpdate(UpdateView):
model = NewLeave
fields = '__all__'
class NewLeaveDelete(DeleteView):
model = NewLeave
success_url = reverse_lazy('newleave-list')
class NewLeaveDetail(DetailView):
model = NewLeave
template_name = 'myusers1/newleave_detail.html'
context_object_name = 'newleave'
queryset = NewLeave.objects.all()
def get_context_data(self, **kwargs):
context = super(NewLeaveDetail, self).get_context_data(**kwargs)
context['leave_details'] = NewLeave.objects.filter(pk=pk)
return context
class Success(TemplateView):
template_name = "authorizationsuccess.html"
class pending_success(TemplateView):
template_name = "pendingsuccess.html"
class rejected_success(TemplateView):
template_name = "rejectedsuccess.html"
Then in urls.py I defined the required urls:
from django.urls import path, re_path
from . import views
from . import models
app_name = 'Myusers1'
urlpatterns = [
path('newleave/add/', views.NewLeaveCreate.as_view(), name='newleave-add'),
path('newleave/<int:pk>/', views.NewLeaveUpdate.as_view(), name='newleave-update'),
path('newleave/<int:pk>/delete/', views.NewLeaveDelete.as_view(), name='newleave-delete'),
# path('newleave/add/<int:pk>/', views.NewLeaveDetail.as_view(), name='newleave-detail'),
path('newleave/add/success/', views.Success.as_view(), name='success_page'),
path('newleave/add/pendingleaves/', views.pending_success.as_view(), name='pending_success'),
path('newleave/add/rejectedleaves/', views.rejected_success.as_view(), name='rejected_success'),
]
I have not worked out all of the url paths.
And the templates like the newleave_form.html
{% extends 'myusers1/base.html' %}
{% block content %}
<div class"container">
<div class="col col-lg-2">
<h2>New Leave Form</h2>
<form method="post">
{% csrf_token %}
{{ form }}
<button type="submit">Authorize</button>
</form>
</div>
</div>
{% endblock %}
And there should be at least 3 different redirect template when a they submit a NewLeave form, authorized, pending, and rejected templates. I just give here the simple authorized success template:
{% extends 'myusers1/base.html' %}
{% block content %}
<h2>Thank you! The authorization of leave was successful</h2>
<div class="col-xs-12 .col-md-8"><li> Back to Home </li></div>
{% endblock %}
Do not forget to migrate and then register the models in the admin.py. Then you should create some staff in the database and few directors to try the above. I hope that the above can give you some direction to accomplish what you are up to with your project. With this I just wanted to give you a very simple example. (You have to create all of the other necessary templates and views).
If you create a new app for trying the above then in your project main urls.py file you should reference (include) your app urls like this with adding one extra line to your project' urls.py file. Then all of your new app urls has to be defined in your app's urls.py file:
This is how your main project's urls.py looks like then:
urlpatterns = [
path('admin/', admin.site.urls),
path('myusers1/', include('Myusers1.urls')),
# so in your case:
path('myapp/', include('myapp.urls')),
]
(you have to change the Myusers1 to your app name,)
And of course we could do a lot of other things with the Model Manager in Django: https://docs.djangoproject.com/en/2.1/topics/db/managers/
You have to call refresh_from_db on balance. like balance.refresh_from_db() to get the updated values from database.
I'm new to Django and web coding.
I'm following Bucky tuts: Django Tutorial for Beginners - 29 - Generic Views
& I'm trying to get my music ( index ) page , but it gives me that error in the browser :
AttributeError at /music/ type object 'Album' has no attribute
'object'
& here's my views.py :
from django.http import HttpResponse, Http404
from django.shortcuts import render , get_object_or_404
from .models import Album,song
from django.views import generic
"""
def index(request):
all_albums = Album.objects.all()
context = {'all_albums': all_albums}
return render(request, 'music/index.html', context)
"""
class IndexView (generic.ListView):
template_name = 'music/index.html'
context_object_name = 'all_albums'
def get_queryset(self):
return Album.object.all()
'''
class DetailView (generic.DetailView):
model = Album
template_name = "music/details.html"
'''
def details(request, album_id):
try:
album = Album.objects.get(pk=album_id)
except Album.DoesNotExist:
raise Http404("Album Does Not Exists !")
return render(request, 'music/details.html', {'album': album})
def favourite (request , album_id):
album = get_object_or_404 (Album , pk=album_id)
try:
selected_song = album.song_set.get(pk=request.POST['song'])
except(KeyError, song.DoesNotExist):
return render(request, 'music/details.html', {
'album':album,
'error_message': "you entered wrong"
})
else:
selected_song.is_favorite = False
selected_song.save()
return render(request,'music/details.html' , {'album':album})
models.py
from django.db import models
# Create your models here.
class Album (models.Model):
artist = models.CharField(max_length = 100)
album_title = models.CharField(max_length = 100)
genre = models.CharField(max_length = 50)
album_logo = models.CharField(max_length = 1000)
def __str__(self):
return self.album_title + " - " + self.artist
class song (models.Model):
album = models.ForeignKey(Album , on_delete=models.CASCADE)
file_type = models.CharField(max_length = 10)
song_title = models.CharField(max_length = 100)
is_favourite = models.BooleanField(default=False)
def __str__(self):
return self.song_title
index.html
{% extends 'music/base.html' %}
{% block title %}Main : MuSiC {% endblock %}
{% block body %}
<ul>
{% for album in all_albums %}
<li>{{ album.album_title }}</li>
{% endfor %}
</ul>
{% endblock %}
#/music/{{ album.id }}
project structure
{ (website) project dir }
|-music
..|-migrations
..|-static
..|-templates
....|-music
......|-base.html
......|-details.html
......|-index.html
|-__init__.py
|-admin.py
|-apps.py
|-models.py
|-tests.py
|-urls.py
|-views.py
|-website
..|-__init__.py
..|-settings.py
..|-urls.py
..|-wsgi.py
|-db.sqlite3
|-manage.py
and I don't know where is the problem :(
btw, lot's of coding terms I still didn't learned , that's why I may ask alot ever I searched for a solution but didn't understand the answer from other question's answers .
Album.object does not exist; you should've written Album.objects.
class IndexView (generic.ListView):
template_name = 'music/index.html'
context_object_name = 'all_albums'
def get_queryset(self):
# return Album.object.all() <-- Remove this
return Album.objects.all()
As a side note, reserved words cannot be python attributes. This is by design, because disallowing these words makes parsing substantially easier.
Why can't attribute names be Python keywords?
The id of admin is 1 when i open the admin user at the admin panel. Likewise the id of michael is 2 but when i click the profile icon instead of showing me the profile of admin i get profile of michael. To get the id i have used user.id of the requested user.
Also the problem is i could not use slug in such model.
restaurant/base.html
{% if user.is_authenticated %}
<li class="nav-item">
<a class="nav-link user-icon" href="{% url 'userprofiles:profile' user.id %}">
<i class="fa fa-user"></i>
</a>
</li>
{% else %}
userprofiles/urls.py
urlpatterns = [
# url(r'^profile/(?P<profile_name>[-\w]+)/(?P<profile_id>\d+)/$', views.profile, name='profile'),
url(
r'^profile/(?P<profile_id>\d+)/$',
views.profile,
name='profile'
),
]
userprofiles/views.py
def profile(request, profile_id):
if profile_id is "0":
userProfile = get_object_or_404(UserProfile, pk=profile_id)
else:
userProfile = get_object_or_404(UserProfile, pk=profile_id)
user_restaurant = userProfile.restaurant.all()
user_order = userProfile.order_history.all()
total_purchase = 0
for ur in user_order:
total_purchase += ur.get_cost()
return render(
request,
'userprofiles/profile.html',
{
'userProfile':userProfile,
'user_restaurant':user_restaurant,
'user_order':user_order,
'total_purchase':total_purchase
}
)
userprofiles/profile.html
{% for user_restaurant in user_restaurant %}
{{user_restaurant.name}}<br/>
{{user_restaurant.address }}
{% endfor %}
userprofiles/models.py
class UserProfile(models.Model):
user = models.OneToOneField(User)
restaurant = models.ManyToManyField(Restaurant)
order_history = models.ManyToManyField(OrderMenu)
# favorites = models.ManyToManyField(Restaurant)
is_owner = models.BooleanField(default=False)
class Meta:
def __str__(self):
return self.user.username
# def get_absolute_url(self):
# return reverse('userprofiles:profile', kwargs={'slug':self.slug, 'id':self.id})
How can i use slug for such model so that in admin panel the slug for that user be automatically saved? Because there is no post method.
But the main problem is i am getting userprofile of another user.
Just add 1 everywhere you use profile_id
def profile(request, profile_id):
if profile_id is "0": # Is profile_id a string or integer?
userProfile = get_object_or_404(UserProfile, pk=(profile_id+1)) # What does this do?
else:
userProfile = get_object_or_404(UserProfile, pk=(profile_id+1))
user_restaurant = userProfile.restaurant.all()
user_order = userProfile.order_history.all()
total_purchase = 0
for ur in user_order:
total_purchase += ur.get_cost()
return render(request, 'userprofiles/profile.html', {'userProfile':userProfile,
'user_restaurant':user_restaurant,
'user_order':user_order,
'total_purchase':total_purchase })
I suspect that somewhere in your code you've got a n-1 problem (i.e. computers start counting at 0 but humans start counting at 1). I haven't found exactly where it is, but this will probably work as a bandage solution in the meantime.
Also, I'm not sure what that if does in your code, it looks like it would never get used if profile_id is an integer.
I used slug instead of id and for using slug i have used pre_save signal where slug value is taken from the username.
def profile(request, profile_slug):
if profile_slug is None:
userprofile = get_object_or_404(UserProfile,slug=profile_slug)
else:
userprofile = get_object_or_404(UserProfile, slug=profile_slug)
user_restaurant = userprofile.restaurant.all()
user_order = userprofile.order_history.all()
total_purchase = userprofile.total_purchase
return render(request, 'userprofiles/profile.html', {'userprofile':userprofile,
'user_restaurant':user_restaurant,
'user_order':user_order,
'total_purchase':total_purchase})
I filled the value of slug in this way.
def create_slug(instance, new_slug=None):
print('instance',instance.user)
slug = slugify(instance.user.username)
if new_slug is not None:
slug = new_slug
qs = UserProfile.objects.filter(slug=slug).order_by("-id")
exists = qs.exists()
if exists:
new_slug = "%s-%s" %(slug, qs.first().id)
return create_slug(instance, new_slug=new_slug)
return slug
def pre_save_post_receiver(sender, instance, *args, **kwargs):
if not instance.slug:
instance.slug = create_slug(instance)
from django.db.models.signals import pre_save
pre_save.connect(pre_save_post_receiver, sender=UserProfile)
Views.py - I want to be able to go to a users page, and then click and follow them from a button exactly like twitter, i sort of know how to add users as you can see by my add variable in my view but I really have not clue how to actually implement that into a button that allows me to follow the user! I have been stuck on this for a whole day and it may be very obvious so any help is greatly appreciated! I do not think my template is need for this question but if it is let me know!
#login_required
def home(request, username):
context = {}
if username == request.user.username:
return HttpResponseRedirect('/home /user/{0}'.format(request.user.username))
else:
user = User.objects.get(username=username)
user_profile = UserProfile.objects.filter(user=user)
following = user.userprofile.follows.all()
number = user.userprofile.follows.all().count()
tweet = Tweet.objects.filter(userprofile=user_profile).order_by('date')
yum = Tweet.objects.filter(userprofile=user_profile).count()
add = user.userprofile.follows.add(request.user.userprofile)
context['user'] = user
context['profile'] = user_profile
context['follow'] = following
context['number'] = number
context['tweet'] = tweet
context['yum'] = yum
return render (request, 'homer.html', context)
models.py
from django.db import models
from django.contrib.auth.models import User
import os
def get_image_path(instance, filename):
return os.path.join('photos', str(instance.user.id), filename)
class UserProfile(models.Model):
user = models.OneToOneField(User)
bio = models.CharField(max_length=120, blank=True, verbose_name='Biography')
follows = models.ManyToManyField('self', related_name='followers', symmetrical=False, blank=True)
theme = models.ImageField(upload_to=get_image_path, blank=True)
profile_picture = models.ImageField(upload_to=get_image_path, blank=True)
def __str__(self):
return self.bio
class Tweet(models.Model):
userprofile = models.ForeignKey(UserProfile)
tweets = models.TextField(max_length=120)
date = models.DateTimeField()
def __str__(self):
return self.tweets
You could do this on a GET or a POST. Here's the view it on a GET since that's simpler.
from django.http import JsonResponse
def follow_user(request, user_profile_id):
profile_to_follow = get_object_or_404(UserProfile, pk=user_profile_id)
user_profile = request.user.userprofile
data = {}
if profile_to_follow.follows.filter(id=user_profile.id).exists():
data['message'] = "You are already following this user."
else:
profile_to_follow.follows.add(user_profile)
data['message'] = "You are now following {}".format(profile_to_follow)
return JsonResponse(data, safe=False)
Then in your urls.py you'd need to add the following to your urlpatterns.
url(r'^follow/(?<user_profile_id>[\d]+)/$', views.follow_user)
Then you'd need to use some javascript like the following:
$('.follow-button').click(function() {
$.get($(this).data('url'), function(response) {
$('.message-section').text(response.message).show();
});
});
This assumes some html like the following:
<body>
<div class="message-section" style="display:none;"></div>
{% for user_profile in all_user_profiles %}
<button data-url="{% url "example_app.views.follow_user" user_profile_id=user_profile.id %}"
class="follow-button" type="button">Follow</button>
{% endfor %}
</body>