Skip to content

Instantly share code, notes, and snippets.

@LowerDeez
Last active October 24, 2017 08:00
Show Gist options
  • Save LowerDeez/bcb4e0c804a6118b6c38aa7099b68042 to your computer and use it in GitHub Desktop.
Save LowerDeez/bcb4e0c804a6118b6c38aa7099b68042 to your computer and use it in GitHub Desktop.
Django. Simple Follower System
// Include before main script file and after jquery (or after jquery if everything in one file)
$(document).ready(function(){
...
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~Cross Site Request Forgery protection~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
function getCookie(name) {
var cookieValue = null;
if (document.cookie && document.cookie != '') {
var cookies = document.cookie.split(';');
for (var i = 0; i < cookies.length; i++) {
var cookie = jQuery.trim(cookies[i]);
// Does this cookie string begin with the name we want?
if (cookie.substring(0, name.length + 1) == (name + '=')) {
cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
break;
}
}
}
return cookieValue;
}
var csrftoken = getCookie('csrftoken');
function csrfSafeMethod(method) {
// these HTTP methods do not require CSRF protection
return (/^(GET|HEAD|OPTIONS|TRACE)$/.test(method));
}
$.ajaxSetup({
beforeSend: function(xhr, settings) {
if (!csrfSafeMethod(settings.type) && !this.crossDomain) {
xhr.setRequestHeader("X-CSRFToken", csrftoken);
}
}
});
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~Cross Site Request Forgery protection~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
});
class Contact(models.Model):
user_from = models.ForeignKey(User, related_name='rel_from_set')
user_to = models.ForeignKey(User, related_name='rel_to_set')
created = models.DateTimeField(auto_now_add=True, db_index=True)
class Meta:
ordering = ('-created',)
unique_together = ('user_from', 'user_to')
def __str__(self):
return '{} follows {}'.format(self.user_from, self.user_to)
# Add following field to User dynamically
User.add_to_class('following',
models.ManyToManyField('self',
through=Contact,
related_name='followers',
symmetrical=False))
"""
The relationship includes symmetrical=False. When you defie a ManyToManyField to the model itself,
Django forces the relationship to be symmetrical. In this case, we are setting symmetrical=False to
define a non-symmetric relation. This is, if I follow you, it doesn't mean you automatically follow me.
"""
<!-- Somewhere in profile page -->
{% with total_followers=user.followers.count %}
<span class="count">
<span class="badge total" style="margin: 4px;">{{ total_followers }}</span>
follower{{ total_followers|pluralize }}
</span>
{% if request.user != user %}
<div style="margin-top: 5px;">
<a href="#"
data-id="{{ user.id }}"
data-action="{% if request.user in user.followers.all %}un{% endif %}follow"
data-url="{% url "accounts:user_follow" %}"
class="btn btn-success follow button">
{% if request.user not in user.followers.all %}
Follow
{% else %}
Unfollow
{% endif %}
</a>
</div>
{% endif %}
{% endwith %}
$(document).ready(function() {
$('a.follow').click(function(e){
e.preventDefault();
$.ajax({
type: 'POST',
url: $(this).data('url'),
data: {
id: $(this).data('id'),
action: $(this).data('action')
},
dataType: "json",
success: function (data, textStatus) {
if (data['status'] == 'ok')
{
var previous_action = $('a.follow').data('action');
// toggle data-action
$('a.follow').data('action', previous_action == 'follow' ? 'unfollow' : 'follow');
// toggle link text
$('a.follow').text(previous_action == 'follow' ? 'Unfollow' : 'Follow');
// update total followers
var previous_followers = parseInt($('span.count .total').text());
$('span.count .total').text(previous_action == 'follow' ? previous_followers + 1 : previous_followers - 1);
}
},
error: function(xhr, status, e) {
alert(status, e);
}
});
});
});
url(r'^users/follow/$', views.UserFollowView.as_view(), name='user_follow'),
You can integrate it in your account app.
Or you can make it as app:
1) create new app for followers
2) add it to installed apps.
3) make migrations and migrate
3) include url to main file
class UserFollowView(LoginRequiredMixin, View):
def post(self, request, *args, **kwargs):
if request.is_ajax():
user_id = request.POST.get('id')
action = request.POST.get('action')
if user_id and action:
try:
user = User.objects.get(id=user_id)
except User.DoesNotExist:
return JsonResponse({'status': 'ko'})
if action == 'follow':
Contact.objects.get_or_create(user_from=request.user,
user_to=user)
else:
Contact.objects.filter(user_from=request.user,
user_to=user).delete()
return JsonResponse({'status': 'ok'})
else:
return JsonResponse({'status': 'ko'})
else:
return HttpResponseBadRequest()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment