I am trying to get user's profile picture in a template using their username. What I have tried:
templatetags/users_extras.py:
from django import template
from django.contrib.auth.models import User
register = template.Library()
#register.filter(name="get_user", is_safe=True)
def get_user(username):
return User.objects.filter(username=username).first()
My template:
{% load users_extras %}
<img src="{{ username|get_user.profile.image.url }}">
My Profile view:
class Profile(ListView):
model = Post
template_name = "users/profile.html"
context_object_name = 'posts'
ordering = ['-datePosted']
def get_queryset(self):
user = get_object_or_404(User, username=self.kwargs.get('username'))
return Post.objects.filter(author=user).order_by('-datePosted')
def get_context_data(self, **kwargs):
context = super(Profile, self).get_context_data(**kwargs)
context['username'] = self.kwargs['username']
return context
The url for profile page is like path('profile/<str:username>/', Profile.as_view(), name='profile')
But that gives error
Could not parse the remainder: '.profile.image.url' from 'username|get_user.profile.image.url'
How can I fix this error or how can I get user object using username in django template?
You may need to get the result of the filter in a variable.
{% load users_extras %}
{% with username|get_user as user %}
<img src="{{ user.profile.image.url }}">
{% endwith %}
No need for solving things in template. First it is a bad practive. Second there's a better way. Just edit the function get_context_data
def get_context_data(self, **kwargs):
context = super(Profile, self).get_context_data(**kwargs)
context['user_requested'] = get_object_or_404(User,
username=self.kwargs.get('username'))
return context
Related
I have created a custom mixin GetVerboseNameMixin in order to get the verbose name of model fields, and then display these in my html template using a DetailView. However, whenever I try and render the list of verbose names nothing is returned, and I cannot work out why.
Mixin.py:
class GetVerboseNameMixin:
def get_verbose_name(model, fields=[]):
verbose_names = []
for field in fields:
verbose_names.append(str(model._meta.get_field(field)))
return verbose_names
View:
class ShowProfileView(GetVerboseNameMixin, DetailView):
model = Profile
template_name = 'profiles/user_profile.html'
verbose_model_fields = GetVerboseNameMixin.get_verbose_name(model=Profile, fields=['first_name', 'surname', 'date_of_birth', 'phone_number', 'bio', 'gender', 'emergency_contact_name', 'emergency_contact_number'])
def get_context_data(self, *args, **kwargs):
context = super(ShowProfileView, self).get_context_data(*args, **kwargs)
user_profile = get_object_or_404(Profile, id=self.kwargs['pk'])
context["user_profile"] = user_profile
return context
def get_object(self, *args, **kwargs):
obj = Profile.objects.filter(id=self.kwargs['pk']).values('first_name', 'surname', 'date_of_birth', 'phone_number', 'bio', 'gender', 'emergency_contact_name', 'emergency_contact_number') # list of dictionaries
object = obj[0]
return object
Html template:
{% extends "base.html" %}
{% block content %}
<h1>Profile</h1>
<br/><br/>
{% csrf_token %}
<ul>
{% for v in object.values %}
{% for field_name in verbose_model_fields %}
<p>{{field_name}}: {{ v }}</p>
{% endfor %}
{% endfor %}
</ul>
<a href='{% url "profiles:edit_profile" pk=user.profile.id %}'>Edit Profile</a>
{% endblock %}
Even if I just render:
{{ verbose_model_fields }}
In my html file nothing is being displayed. This leads me to think maybe the problem is in my mixin, or perhaps the function is not being called properly?
I do not get how verbose_model_fields is getting passed to the template from the view, and also, I did not find any reference in DetailView documentation. I assume you want to have this custom implementation, if so, then you need to pass along this parameter via context:
class ShowProfileView(GetVerboseNameMixin, DetailView):
...
def get_context_data(self, *args, **kwargs):
context = super(ShowProfileView, self).get_context_data(*args, **kwargs)
user_profile = get_object_or_404(Profile, id=self.kwargs['pk'])
context["user_profile"] = user_profile # redundant implementation, you can get this value by `object` context variable in template
context["verbose_model_fields"] = self.verbose_model_fields # or just call self.get_verbose_name(...) method
return context
Also in this solution I have marked redundant implementation that you do not need to re-implement how to get object, because it is already taken care by DetailView.
Hello how can I pass form into template from class based view? In HTML everything inherits and I can render elements inside block content but I can not render form. This is my code. :
views.py:
class Signup(TemplateView):
model = Profile
template_name = 'home/sign-up.html'
form_class = UserCreationForm()
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context['form'] = UserCreationForm
HTML:
{% extends "home/todo.html" %}
{% block content %}
<form method="POST">
{{form}}
</form>
{% endblock content %}
Give this a try
context['form'] = self.form_class
should work
But for User creation, you may better use CreateView instead of TemplateView
from django.views.generic import CreateView
class Signup(CreateView):
template_name = 'home/sign-up.html'
form_class = UserCreationForm()
So I have two forms.ModelForm for my two models
First:
class TranslatorChoice(forms.ModelForm):
def __init__(self, *args, **kwargs):
self.user_id = kwargs.pop('user_id',None)
super(TranslatorChoice, self).__init__(*args, **kwargs)
self.fields['owner'].queryset = Translator.objects.all().filter(owner_id = self.user_id)
owner = forms.ModelChoiceField(queryset = None)
class Meta:
model = Translator
fields = ('owner',)
Second:
class ProfileChoice(forms.ModelForm):
def __init__(self, *args, **kwargs):
self.user_id = kwargs.pop('user_id',None)
super(ProfileChoice, self).__init__(*args, **kwargs)
self.fields['login'].queryset = Profile.objects.all().filter(created_by_id = self.user_id)
login = forms.ModelChoiceField(queryset= None, label='Profile')
class Meta:
model = Profile
fields = ('login',)
I've tried writing a view for them but it doesn't work, seems like it just won't save because whenever I hit submit button it just refreshes the page and cleans the fields without redirecting me to needed URL. The model instances in my DB aren't updated either.
Here's the view:
def link_profile(request):
context = {
'form': ProfileChoice(user_id=request.user.id),
'form2': TranslatorChoice(user_id=request.user.id)
}
if request.method == 'POST':
form = ProfileChoice(request.POST)
form2 = TranslatorChoice(request.POST)
if form.is_valid():
login = form.cleaned_data.get('login')
translator = form.cleaned_data.get('owner')
link = Profile.objects.get(login=login)
link.owner = login
link.save(['owner'])
form.save()
form2.save()
return redirect('dashboard')
return render(request, 'registration/link.html', context)
I know also something is wrong is because I am using to many save functions. I just don't have any experience in creating views like that...
Sharing my template:
{% extends 'base.html' %}
{% block content %}
<h2>Add profile</h2>
<form method="post">
{% csrf_token %}
<table>
{{ form.as_table }} {{ form2.as_table }}
</table>
<button type="submit">Link</button>
</form>
{% endblock %}`
And my urls.py part with the view:
url(r'^link/', views.link_profile),
You didn't share your urls.py or the form in your template so it's not clear if the view is being executed, or how you're passing your forms. But, here's something that might work if you're not doing it already.
{{ form.as_table }}
{{ form2.as_table }}
FYI: there are some indentation issues with your code but I'm assuming that that's just something that happened when you pasted it here.
I was able to load the comments that were added through the admin page but I am not able to make a form in the DetailView itself
I have tried adding a form in the detailview template but I still don't see the form in the site
#views.py
class MessageDetailView(DetailView):
model = Message
template_name = "messaging/detail.html"
#queryset = Message.objects.all()
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context['comments'] = Comment.objects.filter(message=self.object)
return context
#detail.html
<form method="POST">
{% csrf_token %}
<h3>Write a New Comment</h3>
<div class="messagebox">
{{ form|crispy }}
<button class="btn" type="submit">
Post Comment
</button>
</div>
</form>
#forms.py
class CommentForm(forms.ModelForm):
class Meta:
model = Comment
fields = ("comment")
#models.py
class Comment(models.Model):
message = models.ForeignKey(Message,on_delete=models.CASCADE)
comment = models.TextField(max_length=50)
date_posted = models.DateTimeField(default=timezone.now)
def __str__(self):
return "Comment on {}".format(str(self.date_posted))
The comments loaded in the site, but the form didn't load, any way to solve this problem? Please provide some code in the answer instead of just linking me to a documentary.
you didn't pass the form to your template:
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context['comments'] = Comment.objects.filter(message=self.object)
context['form'] = CommentForm()
return context
I am creating a form using ModelForm to let the users upload a file along with a description . The is_valid() function isn't returning true and I am really confused. I have searched and there are many questions with same title as mine but they don't solve my problem.
here is forms.py:
class PostForm(forms.ModelForm):
document = forms.FileField(widget=forms.FileInput)
class Meta:
model = FeedModel
fields = ['description', 'document']
Here is models.py:
class FeedModel(models.Model):
description = models.CharField(max_length=255, blank=True)
document = models.FileField()
like = models.IntegerField(default=0)
dateTime = models.DateTimeField(auto_now=True, auto_created=True)
user = models.ForeignKey(User, on_delete=models.CASCADE, default=0)
def get_absolute_url(self):
u=self.user
return reverse('home:feed',u.primary_key)
Here is views.py:
class PostView(CreateView):
form_class = PostForm
template_name = 'home/feedModel_form.html'
def get(self, request, *args, **kwargs):
form=self.form_class(None)
return render(request, self.template_name, {'form':form })
def post(self, request, *args, **kwargs):
logger = logging.getLogger(__name__)
form=self.form_class(request.POST)
if form.is_valid():
user=request.user
self.object=form.save(commit=False)
self.object.user=user
self.object.save()
logger.error("voila")
redirect({'home:feed'}, user.id)
return render(request, self.template_name, {'form':form })
def feedview(request, user_id):
user = User.objects.get(pk=user_id)
return render(request, 'home/feed.html', {'user': user})
Here is feedModel_form.html:
{% extends 'home/navbar.html' %}
{% block body %}
<div class="form">
<form action="" method="post" enctype="multipart/form-data">
{% csrf_token %}
{% include 'home/form.html' %}
<button type="submit" class="button button-block" `
name="reg_btn">Post</button>`
</form>
</div>
{% endblock %}
Here is form.html:
{% for field in form %}
<div class="field-wrap">
<label>
{{ field.label_tag }}<span class="req">*</span>
</label>
<div>{{ field }}</div>
</div>
{% endfor %}
To see why the form isn't valid, you should check form.errors.
One error will be because you have not passed request.FILES to the form.
form=self.form_class(request.POST, request.FILES)
There may be other errors as well. If you used {{ form }} in your template, Django would include the errors automatically. Since you are rendering the fields manually, it's up to you to include the errors.
The key problem here is that you have overridden post. That means that you're missing out on lots of the code from CreateView.
In your case, it looks like you could remove the post method, and simply override form_valid instead.
def form_valid(self, form):
self.object=form.save(commit=False)
self.object.user=user
self.object.save()
# Note that you had {'home:feed'} here which was incorrect
return redirect('home:feed', user_id)
Your document field expects an uploaded file and is required. In order for the form to actually get the file, you have to also pass it the uploaded file in views.py:
form = self.form_class(data=request.POST, files=request.FILES)