How can I create a detailed view for the user to create a profile template. From what I gather from the documentation
views.py
`from django.contrib.auth.models import User
from django.views.generic.detail import DetailView
class UserDetailView(DetailView):
model = User
template_name= "app/user_detail.html`
urls.py
from . import views
urlpatterns = [
url(r'(P<id>)/$', views.ClassDetailView.as_view(), name=user_profile),]
But it needs a slug in order to work is there a way to change that to the user id, username(prefered) or some other alternative? what would the urls.py would look like?
You can define get_object in your class to return the object to display.
class UserDetailView(DetailView):
model = User
template_name= "app/user_detail.html"
def get_object(self, queryset=None):
return self.request.user
Related
im currently in the process of building a diary app in django. I have created multiple users (e.g User A and User B). However, when user A logs in, user A can see User B's entries.
How can i lock it down, so only User B can see User B's entries and when User A logs in, User A can have a personal entry view? (do i need to create a different view?)
views.py for my diary app:
from django.urls import reverse_lazy
from django.views.generic import (
ListView,
DetailView,
CreateView,
UpdateView,
DeleteView,
)
from .models import Entry
from django.contrib.auth.decorators import login_required
from django.shortcuts import render, redirect
# Create your views here.
class ELV(ListView):
model = Entry
queryset = Entry.objects.all().order_by("-date_created") #takes all the entries and orders it by date
template_name = 'entries\entry_list.html'
class EDV(DetailView):
model = Entry
template_name = 'entries\entry_detail.html'
class ECV(CreateView):
model = Entry
fields = ["title", "content"]
success_url = reverse_lazy("entry-list")
template_name = 'entries\entry_form.html'
class EUV(UpdateView):
model = Entry
fields = ["title", "content"]
template_name = 'entries\entry_update_form.html'
def get_success_url(self):
return reverse_lazy(
"entry-detail",
kwargs={"pk": self.object.pk}
)
class EntryDeleteView(DeleteView):
model = Entry
success_url = reverse_lazy("entry-list")
template_name = 'entries\entry_delete.html'
Does it have anything to do with user sessions? - i'm not sure, please help!
Yes, you can do this easily. But before this you have to add an extra field in your Entry model.
# models.py
from django.contrib.auth import get_user_model
User = get_user_model()
class Entry(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE, related_name='entries', default=None)
# your other remaining fields
and make sure to run makemigrations and migrate commands after adding the new field. And in your views.py file, add a get_queryset(self)
# Create your views here.
class ELV(ListView):
model = Entry
template_name = 'entries\entry_list.html'
def get_queryset(self):
return Entry.objects.filter(user=self.request.user).order_by("-date_created")
PS: And it's a good idea to add a LoginRequiredMixin to make sure only the authenticated got the access you ListView
from django.contrib.auth.mixins import LoginRequiredMixin
class ELV(LoginRequiredMixin, ListView):
# ...
Here is docs link
I also needed to add this bit to my entry create view (ECV), once done, worked like a charm!
def form_valid(self, form):
form.instance.user = self.request.user
return super(ECV, self).form_valid(form)
I create and save user from django-rest-framework, but it do when i am anonymous user. Now i dont see those model in django-admin. How to add model to django-admin?
admin.py
from django.contrib import admin
from possible_blacklist.models import PossibleBlacklist
class PossibleBlacklistAdmin(admin.ModelAdmin):
list_display = [field.name for field in PossibleBlacklist._meta.get_fields()]
admin.site.register(PossibleBlacklist, PossibleBlacklistAdmin)
serializers.py
from rest_framework import serializers
from possible_blacklist.models import PossibleBlacklist
class PossibleBlacklistSerializer(serializers.ModelSerializer):
class Meta:
model = PossibleBlacklist
fields = '__all__'
def create(self, validated_data):
return PossibleBlacklist.objects.create(**validated_data)
def validate_mobile_phone(self, data):
if data.startswith('0'):
raise serializers.ValidationError("Номер должен начинаться на +380")
return data
I had this problem and when I research, I've found this good documentation which will add the model automatically to your Django admin interface.
and no need to touch your admin with every single model which are you adding.
https://medium.com/hackernoon/automatically-register-all-models-in-django-admin-django-tips-481382cf75e5
I'm trying to get all the post by a single user and display it using DetailView and I also want to pass the username of the user on the URL.
this is my urls.py:
from django.urls import path
from .views import ProfileDetail
from . import views
urlpatterns = [
path('<str:username>/', ProfileDetail.as_view(), name = 'profile'),
]
this is my views.py:
from django.views.generic import (DetailView)
from django.shortcuts import render , redirect, get_object_or_404
from django.contrib.auth.models import User
from blog.models import Post
class ProfileDetail(DetailView):
model = Post
template_name = 'users/myprofile.html'
context_object_name = 'posts'
paginate_by = 5
def get_queryset(self):
user = get_object_or_404(User, username=self.kwargs.get('username'))
return Post.objects.filter(author = user).order_by('-date_posted')
I have a class-based view almost exactly just like this one and it is working.
This one always gives me this AttributeError: Generic detail view ProfileDetail must be called with either an object pk or a slug in the URLconf.
If you want to display multiple posts, then a ListView with model = Post would be more suitable.
from django.views.generic import ListView
class ProfileDetail(List):
model = Post
template_name = 'users/myprofile.html'
context_object_name = 'posts'
paginate_by = 5
def get_queryset(self):
user = get_object_or_404(User, username=self.kwargs.get('username'))
return Post.objects.filter(author = user).order_by('-date_posted')
Alternatively, if you want to use DetailView, then you should have model = User because you are showing the posts for a single user. You can avoid the "must be called with either an object pk or a slug" error by overriding get_object.
from django.views.generic import DetailView
class ProfileDetail(ListView):
model = User
template_name = 'users/myprofile.html'
def get_object(self):
return User.objects.get(username=self.kwargs['username'])
Then, in the template, you can loop over the user's posts with something like:
{% for post in user.post_set.all %}
{{ post }}
{% endfor %}
Note that by switching to DetailView, you lose the pagination features of ListView.
I'm new to Django and writing an application in Django 1.11.
I want to create a Profile update page.
I have created an app accounts to manage all profile related activities and created a class
from django.contrib.auth.models import User
# Create your views here.
from django.views.generic import TemplateView, UpdateView
class ProfileView(TemplateView):
template_name = 'accounts/profile.html'
class ChangePasswordView(TemplateView):
template_name = 'accounts/change_password.html'
class UpdateProfile(UpdateView):
model = User
fields = ['first_name', 'last_name']
template_name = 'accounts/update.html'
and in myapp/accounts/urls.py
from django.conf.urls import url
from . import views
app_name = 'accounts'
urlpatterns = [
url(r'^$', views.ProfileView.as_view(), name='profile'),
url(r'^profile/', views.ProfileView.as_view(), name='profile'),
url(r'^change_password/', views.ChangePasswordView.as_view(), name='change_password'),
url(r'^update/', views.UpdateProfile.as_view(), name='update'),
url(r'^setting/', views.SettingView.as_view(), name='setting')
]
When I access 127.0.0.1:8000/accounts/update, It gives
AttributeError at /accounts/update/
Generic detail view UpdateProfile must be called with either an object pk or a slug.
Since, I want the logged in user to edit his/her profile information. I don't want to pass pk in the url.
How to create profile update page in Django 1.11?
class UpdateProfile(UpdateView):
model = User
fields = ['first_name', 'last_name']
template_name = 'accounts/update.html'
def get_object(self):
return self.request.user
As the error told you, you have to return a pk or slug if you're not precising the object. So by overridding the get_object method, you can tell to django which object you want to update.
If you prefer to do it on another way, you can send the pk or slug of the object in the url :
url(r'^update/(?P<pk>\d+)', views.UpdateProfile.as_view(), name='update')
Here the default get_object method will catch the pk in the args and find the user you want to update.
Note that the first method works only (as i wrote it) if a user want to update his profile and is authenticated (self.request.user) and the second way allows you to actually update whatever user you want, as soon as you have the pk of this user (accounts/update/1, will update user with the pk=1, etc...).
Some doc here, get_object() section
Returns the object the view is displaying.
By default this requires self.queryset and a pk or slug argument
in the URLconf, but subclasses can override this to return any object.
I am building a small application which needs user profiles, I've used the build in user system from Django. But I have a problem regarding that even if you are not logged in you can still view the profile also another thing is that each user should only see his profile not others I need some tips on this
views.py
class UserProfileDetailView(DetailView):
model = get_user_model()
slug_field = "username"
template_name = "user_detail.html"
def get_object(self, queryset=None):
user = super(UserProfileDetailView, self).get_object(queryset)
UserProfile.objects.get_or_create(user=user)
return user
class UserProfileEditView(UpdateView):
model = UserProfile
form_class = UserProfileForm
template_name = "edit_profile.html"
def get_object(self, queryset=None):
return UserProfile.objects.get_or_create(user=self.request.user)[0]
def get_success_url(self):
return reverse("profile", kwargs={"slug": self.request.user})
Since you are using the Class Based Generic View, you need to add decorator #login_required in your urls.py
#urls.py
from django.contrib.auth.decorators import login_required
from app_name import views
url(r'^test/$', login_required(views.UserProfileDetailView.as_view()), name='test'),
Have you checked out the login_required decorator? Docs are here.
Since it seems you are using Class Based Views, you need to decorate in the urlconf, see here for more info.
At this moment you can add LoginRequiredMixin for your custom view.
Example:
class MyListView(LoginRequiredMixin, ListView): # LoginRequiredMixin MUST BE FIRST
pass
Doc: https://docs.djangoproject.com/en/4.1/topics/auth/default/#the-loginrequiredmixin-mixin
The below is what you should typically do
#login_required
def my_view(request, uid):
# uid = user id taken from profile url
me = User.objects.get(pk=uid)
if me != request.user:
raise Http404