I use {extends 'xxx.html'} to make all templates have the same 'head' and 'tail', there's an user avatar area {{ avatar }} in head, but I use the same method to pass this avatar in every views, my index.html can't correctly show the avatar, but the other can, so I assume is something wrong with my index views.
Here's the index view:
def index(request):
if request.method == 'GET':
all_user = UserInfo.objects.all()
user = all_user.filter(username=request.user.username)
return render(request, 'index.html', {
"icon": user.icon,
"user": user.username,
})
And here's a part of views which could correctly show the avatar:
if request.user.is_authenticated():
my_fav = UserFavorite.objects.all()
my_fav_num = my_fav.filter(user=request.user).count()
my_posts_num = all_posts.filter(user=request.user).count()
my_msg = UserMessage.objects.all()
my_msg_num = my_msg.filter(user=request.user, has_read=False).count()
all_user = UserInfo.objects.all()
user = all_user.get(username=request.user.username)
return render(request, 'community.html', {
"all_posts": posts,
"post_num": post_num,
"animal_kind": animal_kind,
"post_kind": post_kind,
"sort": sort,
"my_fav_num": my_fav_num,
"my_posts_num": my_posts_num,
"my_msg_num": my_msg_num,
"icon": user.icon,
"user": user.username,
})
else:
my_fav_num = 0
my_msg_num = 0
my_posts_num = 0
return render(request, 'community.html', {
"all_posts": posts,
"post_num": post_num,
"animal_kind": animal_kind,
"post_kind": post_kind,
"sort": sort,
"my_fav_num": my_fav_num,
"my_posts_num": my_posts_num,
"my_msg_num": my_msg_num,
})
HTML code:
<div class="head_bar" style="z-index: 1;">
<a class="logo" href="{% url 'index' %}">Nostray</a>
<div class="nav_bar">
<a class="nav" href="{% url 'adopt:market' %}"><span class="roll" id="adopt">领养</span></a>
<a class="nav" href="{% url 'community:allpost' %}"><span class="roll" id="community">社区</span></a>
<a class="nav" href=""><span class="roll" id="charity">公益</span></a>
</div>
{% if request.user.is_authenticated %}
<div class="current_user"><a href="">
<img src="{{ MEDIA_URL }}{{ icon }}" title="登录状态:{{ user }}" class="curr_icon">
</a></div>
{% else %}
<button class="bar_btn1" onclick="location.href={% url 'login' %}">登录</button>
<button class="bar_btn2" onclick="location.href={% url 'registe' %}">注册</button>
{% endif %}
can't see why the index can't find the avatar.
In your index you have list of user but in you 'correctly show' user is single object and it has the attrs, you need replace
user = all_user.filter(username=request.user.username)
on
user = all_user.get(username=request.user.username)
# ^^^^
Related
I'm trying to clone the Instagram web page using Django(version-3.1).
My Django project has an app called 'post'.
One of its template I have a form which is posting a comment to a post. The form post request should call the path('add_comment/',views.add_comment,name='add_comment'), but It's calling path('<slug:slug>/',views.post_details,name='post_details'), instead. And raising DoesNotExist at /post/add_comment error. I added print() statement at the beginning of both add_comment() and post_details() methods to find out which is running when the request is made. I have no idea what I have done wrong.
The project GitHub link - https://github.com/mirasel/Instagram_Clone
the post_details.html template is -
{% extends 'base.html' %}
{% load static %}
{% block title %} post {% endblock %}
{% block profilephoto %} {{ propic.url }} {% endblock %}
{% block body %}
<div>
<div>
<img src="{{post.image.url}}" alt="post" height="250px" width="250px">
</div>
<div>
<a href="{% url 'instagram:profile' post.uploader %}">
<img src="{{uploader.profile_pic.url}}" alt="{{uploader}}" style="border-radius: 50%;" height="24px" width="24px">
{{ post.uploader }}
</a><br>
<p>{{ post.date_published.date }}</p>
</div>
<div>
<p>{{ post.caption }}</p>
</div>
<div>
<form action="{% url 'post:add_comment' %}" id="comment_form" method="POST">
{% csrf_token %}
<textarea name="comment" id="comment" cols="30" rows="1" placeholder="Write a comment..."></textarea>
<input type="hidden" name="slug" id="slug" value="{{post.slug}}">
<!-- <input type="submit" style="display: none;" name="submit"> -->
</form>
<script>
$(function(){
$("#comment").keypress(function (e) {
if(e.which == 13 && !e.shiftKey) {
$(this).closest("form").submit();
e.preventDefault();
}
});
});
</script>
{% endblock %}
the views.py -
from django.shortcuts import render,redirect
from instagram.views import get_nav_propic,get_profile_details
from .models import UserPost,PostComment,PostLike
from django.http import JsonResponse
def get_post_likes(post):
likes = PostLike.objects.filter(post=post)
total_likes = len(likes)
likers = []
for l in likes:
likers.append(get_profile_details(l.liker))
return {'likers':likers,'total_likes':total_likes}
def get_post_comments(post):
comments = PostComment.objects.filter(post=post)
total_comments = len(comments)
commenter = []
comment = []
for c in comments:
commenter.append(get_profile_details(c.commenter))
comment.append(c.comment)
postcomment = zip(commenter,comment)
return {'post_comment':postcomment,'total_comments':total_comments}
def upload_post(request):
if request.method == 'POST':
image = request.FILES['post_img']
caption = request.POST['caption']
uploader = request.user
UserPost.objects.create(uploader=uploader,image=image,caption=caption)
return redirect('instagram:feed')
else:
context = {
'propic' : get_nav_propic(request.user)
}
return render(request,'post/upload_post.html',context)
def post_details(request,slug):
print('I am here in post details')
post = UserPost.objects.get(slug=slug)
context = {
'propic' : get_nav_propic(request.user),
'post' : post,
'uploader' : get_profile_details(post.uploader),
'LIKES' : get_post_likes(post),
'COMMENTS' : get_post_comments(post),
}
return render(request,'post/post_details.html',context)
def add_comment(request):
print('I am here in add comment')
if request.method == 'POST':
post_slug = request.POST.get('slug')
post = UserPost.objects.get(slug=post_slug)
user = request.user
comment = request.POST.get('comment')
PostComment.objects.create(post=post,commenter=user,comment=comment)
return redirect('post:post_details',slug=post_slug)
the urls.py -
from django.urls import path
from . import views
app_name='post'
urlpatterns = [
path('upload_post/',views.upload_post,name='upload_post'),
path('<slug:slug>/',views.post_details,name='post_details'),
path('add_comment/',views.add_comment,name='add_comment'),
]
The error - Error page
Solved
I had to make the URL path of add_comment as following-
#previous one
path('add_comment/',views.add_comment,name='add_comment'),
#modified one
path('comment/add_comment/',views.add_comment,name='add_comment'),
This is because the pattern for the slug URL and add comment URL were similar.
Because Django will process the urlpatterns sequentially, from docs:
Django runs through each URL pattern, in order, and stops at the first
one that matches the requested URL, matching against path_info.
And '/add_comment' is a valid slug <slug:slug>, so post_details will be called.
So you should keep the definition of the most generic url patterns at last:
urlpatterns = [
path('upload_post/',views.upload_post,name='upload_post'),
path('add_comment/',views.add_comment,name='add_comment'),
path('<slug:slug>/',views.post_details,name='post_details'),
]
Hopefully this will work for you.
I'm trying to add data that I rendered on a page from an API endpoint, to my database when I click "Add to my records" button, as can be seen in the image below, and I'm only trying to store "Date and Country" into the database (my model table has only date and country)
enter image description here
I've seen many resources talking about how JS and AJAX are useful in this case but I'm lost with logic of it all. Is there any way someone could explain how it's supposed to be done.
models.py
from django.db import models
class CountryData(models.Model):
country = models.CharField(max_length=100)
date = models.DateTimeField()
def __str__(self):
return self.country
views.py
def all_countries(request):
first_response = requests.get("https://api.covid19api.com/summary").json()
results = len(first_response["Countries"])
my_new_list = []
data_list = []
for i in range(0, results):
my_new_list.append(first_response["Countries"][i])
# print(my_new_list)
if request.method == "POST":
if request.POST.get("country") and request.POST.get("date"):
added_record = CountryData()
added_record.country = request.POST.get("country")
# 2022-12-19T08:53:48.179Z
added_record.date = datetime.datetime.strptime(
request.POST.get("date"), "%Y-%m-%dT%I:%M:%S.%fZ"
)
added_record.save()
return render(request, "allcountries.html")
else:
return render(request, "allcountries.html", )
context = {"my_new_list": my_new_list}
return render(request, "allcountries.html", context)
urls.py
from django.urls import path, include
from .views import home, all_countries
urlpatterns = [
path("", home, name="home"),
path("allcountries", all_countries, name="all_countries")
]
allcountries.html
{% extends '_base.html' %}
{% block page_title %} Covid19 Statistics For All Countries {% endblock %}
{% block content %}
<h3 class="text-center">Covid19 Statistics For All Countries </h3>
{% for object in my_new_list %}
<div class="row justify-content-center">
<div class="col-sm-10 d-flex justify-content-center">
<div class="card text-dark text-center" style="width: 20rem;">
<div class="card-block card-body">
<form method="POST" action="">
{% csrf_token %}
<h5 class="card-header" name="country">Country: {{object.Country}}, {{object.CountryCode}}</h5>
<br>
<p class="card-text">Total Confirmed Cases: {{object.TotalConfirmed}} </p>
<p class="card-text">Total Deaths Cases: {{object.TotalDeaths}} </p>
<p class="card-text">Total Recovered Cases: {{object.TotalRecovered}} </p>
<p class="card-text" name="date">Date: {{object.Date}}</p>
<button class="btn btn-success" type="submit">ADD TO MY RECORDS </button>
</form>
</div>
</div>
<br>
</div>
</div>
{% endfor %}
{% endblock %}
You can use the following ajax snippet to send data in the backend:
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.6.1/jquery.min.js"></script>
<script>
$.ajax({
type: 'POST',
url: 'url', #leave blank if URL is same as the current one
data: {
'country': 'county_name',
'date': 'date_value',
},
success: function(response) {
# depending upon the response from the server you can make an alert here.
},
error: function(response){
# If some error occurred on the backend you can show error message from here
}
});
</script>
when looping through all the media files in template passed variable i am getting video and image same styles. From the looped items i need to give different style for images and different style for videos.
here is my template file (gallery.html)
{% for photo in photos %}
<div class="col-md-4">
<div class="card my-2">
<video class="video-thumbail" controls="controls" src="
{{photo.image.url}}" alt="Card image cap"></video>
<image class="image-thumbail" src="
{{photo.image.url}}" alt="Card image cap">
<a href="{% url 'keyhtml' %}"
class="btn btn-outline-dark btn-sm m-1">View</a>
</div>
</div>
{% empty %}
<h3>No photos...</h3>
{% endfor %}
here is my views function for this
#login_required(login_url='login')
def gallery(request):
user = request.user
category = request.GET.get('category')
if category == None:
photos = Photo.objects.filter(category__user=user)
else:
photos = Photo.objects.filter(
category__name=category,
category__user=user)
if category == None:
photos2 =
Photo2.objects.filter(category__user=user)
else:
photos2 = Photo2.objects.filter(
category__name=category, category__user=user)
categories = Category.objects.filter(user=user)
context = {'categories': categories, 'photos': photos,'photos2': photos2}
return render(request, 'photos/gallery.html', context)
I have no Idea why, but if I try to 'GET' this view I get this error:
django.urls.exceptions.NoReverseMatch: Reverse for 'profile-update-name' with arguments '('',)' not found. 1 pattern(s) tried: ['ce_profiles/profile\\-update\\-name/(?P<pk>[0-9]+)/$']
But if submit a 'POST' request, everything is fine. ???
Here is the work flow:
First I access this view and template:
def customer_profile(request, pk):
name = get_object_or_404(CEName, id=pk)
return render(
request,
'customer/customer_profile.html',
{'profile_name': name}
)
{% block content %}
{% include 'ce_profiles/name_header.html' %}
<div id="name" class="container d-flex justify-content-between pt-1">
{% include 'ce_profiles/profile_name.html' %} <!-- displays the profile_name -->
<button id="update_button" action="{% url 'ce_profiles:profile-update-name' profile_name.id %}" class="bold btn btn-main btn-sm button-main">UPDATE</button>
</div>
<div id="div_NameForm" class="container">
</div>
{% endblock %}
{% block script %}
<script src="{% static 'ce_profiles/ce_profiles.js' %}"></script>
{% endblock %}
When I click the update button it should AJAX in the form to be modified. I've tried substitution of the variable to just a '1', but it still doesn't work. I have tests to verify that the view by itself doesn't work with the 'GET', but does with the 'POST', apart from the previous view.
urls.py
app_name='ce_profiles'
urlpatterns = [
path('profile-update-name/<int:pk>/', views.profile_update_name,
name='profile-update-name'
),
]
view
def profile_update_name(request, pk):
name = get_object_or_404(CEName, id=pk)
if request.POST:
name_form = NameForm(data=request.POST, instance=name)
if name_form.has_changed() == False:
name_form.add_error(None, _('No changes made.'))
if name_form.is_valid():
name_form.save()
updated_name = get_object_or_404(CEName, id=name.id)
profile_name_json = render_to_string(
'ce_profiles/profile_name.html',
{'profile_name': updated_name,}
)
return JsonResponse({'profile_name': profile_name_json})
else:
return JsonResponse({'error': name_form.errors})
else:
name_form = NameForm(instance=name)
get_NameForm_json = render_to_string(
'ce_profiles/update_NameForm.html',
{'NameForm': name_form}
)
return JsonResponse({'NameForm': get_NameForm_json})
Here is the template. Is something missing?
update_NameForm.html
<div id="div_NameForm" class="container">
<hr size="3px">
<form id="NameForm" method="POST" action="{% url 'ce_profiles:profile-update-name' profile_name.id %}">
{% csrf_token %}
{{ NameForm.as_p }}
<div id="NameForm_errors"></div>
<br>
<button id="save_changes" type="submit" class="btn btn-main button-main btn-block">Save Changes</button>
</form>
</div>
Instead of using render_to_string, you may use render(), and you forgot to send the variable profile_name: to the templates.
def profile_update_name(request, pk):
name = get_object_or_404(CEName, id=pk)
if request.POST:
''' code '''
# no need to use else statement
# since 'return' breaks the 'if request.POST' statement
name_form = NameForm(instance=name)
context = {
profile_name:name,
'NameForm': name_form,
}
return render(request,'ce_profiles/update_NameForm.html',context)
Note that you can you leave action='' empty in the form which will mean the same view
<form id="NameForm" method="POST" action="">
I have the following in template
<div class="profile-navbar">
{% url 'users:profile' user.id as profile_link %}
<a class="item home" href="{{ profile_link }}">Home</a>
{% url 'users:profile_ask' user.id as profile_ask_link %}
<a class="item" href="{{ profile_ask_link }}" > Ask <span class="num">0</span></a>
{% url 'users:profile_answer' user.id as profile_answer_link %}
<a class="item" href="{{ profile_answer_link }}" > Answer <span class="num">0</span></a>
</div>
The urls are
url(r'^profile/(?P<userid>\d+)', views.profile, name='profile'),
url(r'^profile/ask/(?P<userid>\d+)', views.profile_ask, name='profile_ask'),
url(r'^profile/answer/(?P<userid>\d+)', views.profile_answer, name='profile_answer'),
Here is the view function:
def profile(request,userid):
if request.user.is_authenticated():
if request.user.id == userid:
pass
else:
pass
else:
pass
template_name = 'users/profile.html'
if request.method == 'POST':
pass
return render(request, template_name)
Guest visitors can visit the page if he/she types in the link but the links in the page (the above template) don't work.
What's wrong that I'm doing here?
Thanks.
You could take two approaches at this (second is the preferred method):
1.)
<div class="profile-navbar">
<a class="item home" href="{% url 'profile' user.id %}">Home</a>
<a class="item" href="{% url 'profile_ask' user.id %}" > Ask <span class="num">0</span></a>
<a class="item" href="{% url 'profile_answer' user.id %}" > Answer <span class="num">0</span></a>
</div>
2.)
models.py:
# Completely making this up, but you'll get the idea
class Model(models.Model):
user = models.ForeignKey(User)
def get_profile_url(self):
return reverse('profile',
kwargs={'userid': self.user.id})
def get_profile_ask_url(self):
return reverse('profile_ask',
kwargs={'userid': self.user.id})
def get_profile_answer_url(self):
return reverse('profile_answer',
kwargs={'userid': self.user.id})
html:
<a class="item home" href="{{ request.user.get_profile_url }}">Home</a>
<a class="item" href="{{ request.user.get_profile_ask_url }}"> Ask <span class="num">0</span></a>
<a class="item" href="{{ request.user.get_profile_answer_url }}"> Answer <span class="num">0</span></a>
-
The second method is preferred because it is now universal. If you need to make changes, you only need to do it in the model. If you set it up the first way I showed, you'll need to go through every single template and make the changes - pain in the butt.
I wanted to show you the first method so you can see what is happening, but I highly recommend following the format of the second one.
Note: I typed this directly in the response, so make sure the syntax and variables are correct before using. You'll also need to change it based on your model, etc. Feel free to ask questions if you get stuck.
EDIT:
Also, change your urls to this (should use a trailing slash and dollar sign):
# I'm assuming these are extended from a branch?
url(r'^profile/(?P<userid>\d+)/$', 'profile', name='profile'),
url(r'^profile/ask/(?P<userid>\d+)/$', 'profile_ask', name='profile_ask'),
url(r'^profile/answer/(?P<userid>\d+)/$', 'profile_answer', name='profile_answer'),
views.py:
def profile(request, userid):
user_profile = get_object_or_404(User, id=userid)
template_name = 'users/profile.html'
if request.method == 'POST':
pass
return render(request, template_name, {'user_profile': user_profile})