Display intro video first visit only Django - javascript

I have a Django app that needs to display a video that gives an into to the website. I only want it to do this on the initial visit as opposed to every time the user refreshes. I feel like sessions would have something to do with this but I’m not sure. Thanks!

I think its best to put this flag directly in your database. You can put a field in your user model(if you are using custom user) or in a model which has OneToOne relation with User. For example:
class Profile(models.Model):
user = models.OneToOneField(User)
has_seen_intro = models.BooleanField(default=False)
And send this information to Template from view like this, for example:
class HomeView(TemplateView):
template_name = 'home.html'
def get_context_data(self, **kwargs):
context = super(HomeView, self).get_context_data(**kwargs)
profile = self.request.user.profile
if not profile.has_seen_intro:
context['show_intro'] = True
profile.has_seen_intro = False
profile.save()
# or use user.has_seen_intro if you have custom model
return context
And update the template like this
{% if show_intro %}
// intro video codes
{% endif %}
Update
for anonymous user, please try like this:
class HomeView(TemplateView):
template_name = 'home.html'
def get_context_data(self, **kwargs):
context = super(HomeView, self).get_context_data(**kwargs)
if self.request.user.is_authenticated:
profile = self.request.user.profile
if not profile.has_seen_intro:
context['show_intro'] = True
profile.has_seen_intro = False
profile.save()
else:
if not self.request.session.get('has_seen_intro', True):
self.request.session['has_seen_intro'] = False
context['show_intro'] = True
return context

Related

django: How to write JavaScript fetch for url with slug parameter?

A django and async newbie here, trying to improve a simple message-board app. I'm sure you've all seen this problem dozens of times, but I'm unable to find a solution...
Currently, when a user likes a posted message, it refreshes the whole page. I'd like to use simple JavaScript with the fetch API to prevent this, without having to resort to Ajax, as I've never used it. The problem is, I'm very new to the fetch method as well and I'm struggling to find the correct syntax for the url in the fetch request, as it uses the post model's slug field as a parameter. Like so:
urls.py
urlpatterns = [
...
path('post/<slug:slug>/', views.FullPost.as_view(), name='boards_post'),
path('like/<slug:slug>/', views.PostLike.as_view(), name='post_like'),
...
]
models.py
...
class Post(models.Model):
"""
Model for message posts
"""
STATUS = ((0, "Draft"), (1, "Published"))
title = models.CharField(max_length=200, unique=True)
slug = models.SlugField(max_length=200, unique=True)
author = models.ForeignKey(
User, on_delete=models.CASCADE, related_name="board_posts"
)
category = models.ForeignKey(
Category,
on_delete=models.CASCADE,
default="",
related_name="category_posts"
)
created_on = models.DateTimeField(auto_now_add=True)
updated_on = models.DateTimeField(auto_now=True)
content = models.TextField()
post_image = CloudinaryField('image', default='placeholder')
status = models.IntegerField(choices=STATUS, default=0)
likes = models.ManyToManyField(User, related_name="post_likes")
class Meta:
# Orders posts in descending order
ordering = ['-created_on']
def __str__(self):
return self.title
def number_of_likes(self):
return self.likes.count()
def get_absolute_url(self):
"""
Method to tell django how to find the url to any specific
instance of a post when the Post model is instantiated,
(i.e. a new post created). Returns the url generated by the
'boards_post' path from the FullPost class view, with
this model's slug field as a keyword argument. This
effectively acts as a redirect to the full_post.html template.
"""
return reverse('boards_post', kwargs={'slug': self.slug})
...
views.py
...
class FullPost(View):
"""
View for a single post, selected by the user, displaying
comments and likes. The url for each individual post is derived
from the Post model's slug field which is, in turn,
populated by the title.
"""
def get(self, request, slug, *args, **kwargs):
"""
Method to get post object.
"""
queryset = Post.objects.filter(status=1)
post = get_object_or_404(queryset, slug=slug)
comments = post.comments.order_by('created_on')
liked = False
if post.likes.filter(id=self.request.user.id).exists():
liked = True
return render(
request,
"full_post.html",
{
"post": post,
"comments": comments,
"liked": liked,
"comment_form": CommentForm()
},
)
def post(self, request, slug, *args, **kwargs):
"""
Post method for comment form.
"""
queryset = Post.objects.filter(status=1)
post = get_object_or_404(queryset, slug=slug)
comments = post.comments.order_by("-created_on")
liked = False
if post.likes.filter(id=self.request.user.id).exists():
liked = True
comment_form = CommentForm(data=request.POST)
if comment_form.is_valid():
comment_form.instance.name = self.request.user
comment = comment_form.save(commit=False)
comment.post = post
comment.save()
else:
comment_form = CommentForm()
return redirect(self.request.path_info)
...
...
class PostLike(View):
"""
View for liking and unliking posts.
"""
def post(self, request, slug):
"""
Method to toggle liked/unliked state on a particular post.
"""
post = get_object_or_404(Post, slug=slug)
liked = True
if post.likes.filter(id=self.request.user.id).exists():
post.likes.remove(request.user)
liked = False
else:
post.likes.add(request.user)
likes = post.number_of_likes()
# ----- The original return statement is the one commented out below:
# return HttpResponseRedirect(reverse('boards_post', args=[slug]))
return JsonResponse({"likes": likes, "liked": liked})
...
Snippet from full post template
...
<div class="row">
<div class="col-1">
{% if user.is_authenticated %}
<strong>
<form class="d-inline" action="{% url 'post_like' post.slug %}" method="POST">
{% csrf_token %}
{% if liked %}
<!-- I used 'post.id' for the argument passed to the like function here, as I couldn't get 'post.slug' to work -->
<button class="btn-like" type="submit" name="post_id" value="{{ post.slug }}" onclick="like({{ post.id }})">
<i id="like-btn" class="fas fa-thumbs-up"></i>
</button>
<span id="likes-count">{{ post.number_of_likes }}</span>
{% else %}
<button class="btn-like" type="submit" name="post_id" value="{{ post.slug }}" onclick="like({{ post.id }})">
<i id="like-btn" class="far fa-thumbs-up"></i>
</button>
<span id="likes-count">{{ post.number_of_likes }}</span>
{% endif %}
</form>
</strong>
{% else %}
<strong class="text-secondary"><i class="far fa-thumbs-up"></i> <span id="likes-count">{{ post.number_of_likes }}</span></strong>
{% endif %}
</div>
...
All I've got so far in JavaScript is the following...
function like(post_id) {
let likeButton = document.getElementById("like-btn");
let likeCount = document.getElementById("likes-count");
console.log(likeCount.innerText);
console.log(post_id);
// -------- I've no idea what works here! I've tried both of the below
// -------- and several variations.
// -------- Obviously, none work.
// const url = "{% url 'post_like' post.slug %}";
//or const url = `/like/${post.slug}`;
fetch(url, {method: "POST"})
.then(response => response.json())
.then(data => {
console.log(data);
// ------ If I ever get the json data, I'll use it here to manipulate the
// ------ likeButton and likeCount variables in the DOM. Something like:
likeCount.innerHTML = data["likes"];
if (data["liked"] === true) {
likeButton.className = "fas fa-thumbs-up";
} else {
likeButton.className = "far fa-thumbs-up";
}
})
.catch((e) => alert("Unable to like/unlike post."));
// -------- or something.
}
Also, I know I need to handle the csrf token somehow but I've no idea how. Like I said, total newbie.
So, can anyone help? And does anyone have any advice?
Cheers!
For csrf_token problem add to view this decorator:
from django.utils.decorators import method_decorator
#method_decorator(csrf_exempt, name='dispatch')
class PostLike(View):
...
For fetch you need to have whole path, not just relative path. This should work:
url = "{{ request.scheme }}://{{ request.get_host }}{% url 'post_like' post.slug %}"

How can a Ajax/jQuery script show 2+ dependent dropdown box entries within one Form url?

I am developing a simple form prototype that contains 4 entries in PythonAnywhere (Python 3.7 + Django):
PinID (Independent, simple manual number entry)
Region (Independent Dropdown Box)
Name (Region-Dependent Dropdown Box)
Source (Name-Dependent Dropdown Box)
What shows up in the Name box is dependent on the Region box, and what shows up in the Source box is dependent on the Name box. So ultimately, the Source Box is dependent on the Region box (If A, then B. If B, then C. So C is dependent on A). To note, if the Region or Name box is blank, their respective dependents are blank.
As my current code is written (which is likely wrong), I can only get my Name box to autopopulate correctly. The Source box remains blank, but it does indeed autopopulate correctly after I refresh the page. However, I intend to keep the form all in one url. I refer to two other .html files to "insert" themselves into the form's .html file without refreshing the page. In the jQuery script, I put the identical segment of code for the second dependent dropdown box under the success function of the first dependent dropdown box, which might be my issue.
So, I presume my coding issue is initiating two different url references within one jQuery script. Does anyone know if I can correct my jQuery script to reference both urls? I included my relevant Django files for reference and if I am overlooking an error in those particular files.
For reference, I have based my work using this tutorial. However, this tutorial only worked with one dependent dropdown box.
form.html (Ajax/jQuery)
<form method="post" id="nameForm" data-names-url="{% url 'ajax_load_names' %}" data-sources-url="{% url 'ajax_load_sources' %}" novalidate>
{% csrf_token %}
<table>
{{ form.as_table }}
</table>
<button type="submit">Add</button>
Nevermind
</form>
<script src="https://code.jquery.com/jquery-3.3.1.min.js"></script>
<script>
$("#id_region").change(function () {
var url = $("#nameForm").attr("data-names-url");
var regionId = $(this).val();
$.ajax({
url: url,
data: {
'region': regionId
},
success: function (data) {
$("#id_name").html(data);
$("#id_source").change(function () {
var url = $("#nameForm").attr("data-sources-url");
var nameId = $(this).val();
$.ajax({
url: url,
data: {
'name': nameId
},
success: function (data) {
$("#id_source").html(data);
}
});
});
}
});
});
</script>
name_dropdown_list_options.html
<option value="">---------</option>
{% for name in names %}
<option value="{{ name.pk }}">{{ name.name }}</option>
{% endfor %}
source_dropdown_list_options.html
<option value="">---------</option>
{% for source in sources %}
<option value="{{ source.pk }}">{{ source.source }}</option>
{% endfor %}
forms.py
class RequestForm(forms.ModelForm):
class Meta:
model = Request
fields = ('pinid', 'region', 'name', 'source')
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.fields['name'].queryset = Name.objects.none()
self.fields['source'].queryset = Source.objects.none()
if 'region' in self.data:
try:
region_id = int(self.data.get('region'))
self.fields['name'].queryset = Name.objects.filter(region_id=region_id).order_by('region')
except (ValueError, TypeError):
pass # invalid input from the client; ignore and fallback to empty Name queryset
elif self.instance.pk:
self.fields['name'].queryset = self.instance.region.name_set.order_by('region')
if 'name' in self.data:
try:
name_id = int(self.data.get('name'))
self.fields['source'].queryset = Source.objects.filter(name_id=name_id).order_by('name')
except (ValueError, TypeError):
pass # invalid input from the client; ignore and fallback to empty Source queryset
elif self.instance.pk:
self.fields['source'].queryset = self.instance.name.source_set.order_by('source')
models.py
class Region(models.Model):
region = models.CharField(max_length=30)
def __str__(self):
return self.region
class Name(models.Model):
region = models.ForeignKey(Region, on_delete=models.CASCADE)
name = models.CharField(max_length=30)
def __str__(self):
return self.name
class Source(models.Model):
name = models.ForeignKey(Name, on_delete=models.CASCADE)
source = models.CharField(max_length=30)
def __str__(self):
return self.source
class Request(models.Model):
pinid = models.PositiveIntegerField()
region = models.ForeignKey(Region, on_delete=models.SET_NULL, null=True)
name = models.ForeignKey(Name, on_delete=models.SET_NULL, null=True)
source = models.ForeignKey(Source, on_delete=models.SET_NULL, null=True)
def __int__(self):
return self.pinid
views.py
class NameCreateView(CreateView):
model = Request
form_class = RequestForm
success_url = reverse_lazy('name_changelist')
def load_names(request):
region_id = request.GET.get('region')
names = Name.objects.filter(region_id=region_id).order_by('region')
return render(request, '/home/name_dropdown_list_options.html', {'names': names})
def load_sources(request):
name_id = request.GET.get('name')
sources = Source.objects.filter(name_id=name_id).order_by('name')
return render(request, '/home/source_dropdown_list_options.html', {'sources': sources})
First move change your form.html javascript, so that the $("#id_source").change(function ()
is on the same level as the name change function. I suppose otherwise it will never be called:
forms.html javascript
<script>
$("#id_region").change(function () {
var url = $("#nameForm").attr("data-names-url");
var regionId = $(this).val();
$.ajax({
url: url,
data: {
'region': regionId
},
success: function (data) {
$("#id_name").html(data);
}
});
});
$("#id_source").change(function () {
var url = $("#nameForm").attr("data-sources-url");
var nameId = $(this).val();
$.ajax({
url: url,
data: {
'name': nameId
},
success: function (data) {
$("#id_source").html(data);
}
});
});
</script>
I would start with a much simpler design to fetch the names and sources. Remove the complete init of your request form so that the standard init gives you all values for the names and sources. You will need them because the form validates against these values and if its empty none of them will be valid. You can remove the values then with a little javascript:
$(document).ready(function() {
$("#id_region").html("---"); // or whatever your null value will be
$("#id_source").html("---");
});
To get the values of names and sources you need to view functions:
def load_names(request, region_id):
names = Name.objects.filter(region__id=region_id).order_by('region')
html = ''
for name in names:
html += '<option value="{id}">{name}</option>\n'.format(id=name.id, name=name.name)
return HttpResponse(html)
def load_sources(request, name_id):
sources = Source.objects.filter(name__id=name_id).order_by('region')
html = ''
for source in sources:
html += '<option value="{id}">{source}</option>\n'.format(id=name.id, source=source.source)
return HttpResponse(html)
If this works fine you can change them to templatetags, if you want
At last you need the proper url definitions:
path('load_names', views.load_names, name='load-names'),
path('load_sources', views.load_sources, name='load-sources'),
Pass these to your view form.

Redirect Django to the same spot in the page after post

I have a 2 buttons in my website - 1. Edit entry 2. Delete Entry.
The problem is, after I click Confirm for the deleting or editing, the page refreshes and get all the new information but it loads the page from the beginning (Upper side of the page)
Since my page is very long with a lot of entries.... I want that after I click "confirm" it will redirect the user to the same spot he clicked in the page so he wouldn't need to roll the mouse to go down the page again and again..
Anyone knows?
views.py -
class HomeView(TemplateView):
template_name = 'serverlist.html'
def get(self, request):
form = HomeForm()
query = request.GET.get("q")
posts = serverlist.objects.all()
forms = {}
if query:
posts = serverlist.objects.filter(Q(ServerName__icontains=query) | Q(Owner__icontains=query) | Q(Project__icontains=query) | Q(Description__icontains=query) | Q(IP__icontains=query) | Q(ILO__icontains=query) | Q(Rack__icontains=query))
else:
posts = serverlist.objects.all()
for post in posts:
forms[post.id] = HomeForm(instance=post)
args = {'form' : form,'forms': forms, 'posts' : posts}
return render(request, self.template_name,args)
def post(self,request):
form = HomeForm(request.POST)
posts = serverlist.objects.all()
forms = {}
if form.is_valid(): # Checks if validation of the forms passed
post = form.save(commit=False)
post.save()
messages.success(request,'{0} has been added successfully!'.format(post.ServerName))
return redirect('serverlist')
messages.error(request,'Servername is required, please refresh the page and try again.')
for post in posts:
forms[post.id] = HomeForm(instance=post)
args = {'form' : form, 'forms': forms, 'posts' : posts}
return render(request, self.template_name,args)
class PostDelete(SuccessMessageMixin,DeleteView):
model = serverlist
success_url = reverse_lazy('serverlist')
success_message = "The server has been deleted successfully!"
def delete(self, request, *args, **kwargs):
messages.warning(self.request, self.success_message)
return super(PostDelete, self).delete(request, *args, **kwargs)
class PostEdit(SuccessMessageMixin,UpdateView):
template_name = 'serverlist.html'
model = serverlist
form_class = HomeForm
success_url = reverse_lazy('serverlist')
success_message = "%(ServerName)s has been edited successfully!"
def edit(self, request, *args, **kwargs):
messages.warning(self.request, self.success_message)
return super(PostEdit, self).edit(request, *args, **kwargs)

Check if requested user is owner in django

I have developed an app which is about storing hotel information. I want an edit and delete feature too but edit button should be visible only to that user who has registered hotel not to all the authenticated user. I want to pass if requested user is the one who has registered hotel through javascript argument. How can i check this?
hotel_detail.html
<script type="text/javascript">
var data = {
pk:{{ instance.pk }},
isUserAuthenticated:{% if request.user.is_authenticated %}true{% else %}false{% endif %},
user:'{{request.user.username}}'
}
console.log('owner is', data.user);
console.log(data);
$(function() {
app.showRoomDetail("hotelDetail",data);
});
</script>
views
def hotel_detail(request, pk):
instance = get_object_or_404(Hotel, pk=pk)
context = {
'pk':instance.pk,
'instance':instance
}
return render(request,'rentals/hotel_detail.html',context)
Models
class Hotel(models.Model):
ownerName = models.CharField(_("Owner's Name"),max_length=255, blank=True,null=True,
help_text=_("Owner's Full Name"))
email = models.CharField(max_length=120,blank=True,null=True)
phoneNumber = models.PositiveIntegerField(blank=False,null=True,
help_text=_("Phone number of contact person"))
hotelName = models.CharField(_("Hotel Name"), max_length=255, blank=False,null=True)
slug = models.SlugField(unique=True,blank=True,null=True)
summary = models.TextField(max_length=500, blank=True,null=True,help_text=_("Description of the Hotel"))
location = models.CharField(_("location"),max_length=10,null=True)
room = models.PositiveIntegerField(_("No of Rooms"), blank=False, null=True,
help_text=_("Number of bedrooms available"))
price = models.PositiveIntegerField(blank=False,null=True,
help_text=_("Price per room"))
Well what you can do is add user field or say hotelOwner in your models.py like
hotelOwner = models.ForeignKey(User) # note you need to import user model
now in your data object inside javascript you should do following
user:{% if request.user == instance.renter %}true{% else %}false{% endif %}

Integrating typeahead.js with Django apps

I'm fairly new to Django and am trying to integrate typeahead.js to my Django app. I want to be able to search through the field 'name' in my local sql2lite DB which has around 15,000 entry. The table name is called 'institution'.
My html is able to find typeahead.js and have the following script to run it:
<script type="text/javascript" src="{% static 'js/typeahead/typeahead.jquery.js' %}">
$(document).ready(function() {
$("#InstitutionsSearch").typeahead({
name: 'Institutions',
remote: 'profile/account_names_autocomplete/?q=%QUERY'
What do I need to do with remote to set the search on a field in my DB? I read other threads but it isn't clear to me what remote actually do. Do I have to engage Bloodhound to make this work?
The query is reach my View printing hello0 but no more.
My view:
class UserAccountsUpdate(UpdateView):
context_object_name = 'variable_used_in `add_user_accounts.html`'
form_class = AddUserAccountsForm
template_name = 'add_user_accounts.html'
success_url = 'summary.html'
print "hello0"
def account_name_autocomplete(request):
print "hello1"
query = request.GET.get('q','')
if query:
print "hello2"
results = Insitutions.objects.filter(name__istartswith=query)
result_list = []
for item in results:
result_list.append(item.short)
else:
result_list = []
response_text = json.dumps(result_list, separators=(',',':'))
return HttpResponse(response_text, content_type="application/json")
#get object
def get_object(self, queryset=None):
return self.request.user
Thanks

Categories