I am little bit new to django and was working on my first instagram clone project all by myself. I got confused in a place where I needed to fetch user data based on 127.0.0.1:8000/username and I found a useful but useless answer(for me) from medium(.com) .The author was using class based view. In class based view, I didnot get any documentation to use multiple models as much as I searched so i had to do it with function based view as I have not learned class based view yet.I had to use post model, profile model and User model to get data for profile page.
This is the code that somehow worked but should I use this view?
from django.contrib.auth.models import User
from .models import Profile
#profile view
def profile_data(request, username):
mydata = User.objects.get(username=username)
myprofile = Profile.objects.filter(user=mydata)
mycontext ={'profile': myprofile}
return render(request,'firstapp/profile.html', context=mycontext)
#in urls.py,
from firstapp import views
path('<str:username>/', views.profile_data , name='profile'),
#in models.py,
from django.contrib.auth.models import User
class Profile(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE,unique=True)
fullname = models.CharField(max_length=100)
def __str__(self):
return self.fullname
In firstapp/profile.html,
<a href="#" class="text-3xl mt-5 text-center">{{user.profile.fullname}}
But I got confused on how to attatch my Profile model in it. So I created this, my own function-based view for it after few hours of researching . Is this ok to use or will give any error in my back? Thank you
I am expecting to get new ways or the correction or additon in my code if possible.
It seems ok, but be careful about the url part, because you will have problems when adding new urls (eg: /login) because it might be treated as a username.
You could get away by editing the order in your urlpatterns so the profile page is the last but now you have an issue if a user has the same username as a url in your page.
For example if a user has "login" as username, you won't be able to go to their profile page.
A solution is to use a prefix for the profile pages (eg: /u/<username> or /#<username>).
Some other improvements:
mydata = User.objects.get(username=username)
myprofile = Profile.objects.filter(user=mydata)
Can be rewriten with only one request:
user = User.objects.get(username=username).select_related("profile")
myprofile = user.profile
See the documentation for select_related: https://docs.djangoproject.com/en/4.1/ref/models/querysets/#select-related
You should also handle the case where the user is not found:
try:
user = User.objects.select_related("profile").get(username=username)
except User.DoesNotExist:
raise Http404("No User matches the given query.")
myprofile = user.profile
Related
I'm trying to customize allauth's default SignUpView and SignUpForm to allow me to create other users while already logged in. The default behavior prevents me from doing this: in other words, I can only sign up for a new account if I'm not authenticated.
How do I override this behavior?
I presume I'll have to override the SignupView in views.py but I'm not sure what to look for... I played around with RedirectAuthenticatedUserMixin, but to no avail.
Forms.py
from allauth.account.forms import SignupForm
class SubUserForm(SignupForm):
USER_TYPES = [
(2,'customer'),
(3,'vendor'),
(4,'supplier')
]
first_name = forms.CharField(max_length=45)
last_name = forms.CharField(max_length=45)
user_type = forms.CharField(widget=forms.Select(choices=USER_TYPES))
Views.py
from allauth.account.views import SignupView
class SubUserSignupView(SignupView):
template_name = 'accounts/new_user_signup_form.html'
form_class = SubUserForm
view_name = 'sub_user_signup'
sub_user_signup = SubUserSignupView.as_view()
urls.py
urlpatterns = [
path('sub_user/',views.sub_user_signup,name='sub_user_signup'),
]
To put in context
My app allows for a 'parent' user to sign up multiple 'children' users (called 'subuser' in the code above) using allauth. In my case, an organization can create several customers, merchants, suppliers, etc. When a parent user creates a child user, a verification email is sent to the child user, who then activates his account and is prompted to enter a password. I use 2 signup forms; the default allauth signup (for parent accounts), and a customized signup form (for children accounts), which also extends from allauth.
Although the registration flow above works well, a parent user can only sign up new children users (trigger email verification) when logged out. I'm struggling to identify what I need to prevent this from happening.
Navigate to the allauth directory, under app settings, set this to False
ACCOUNT_AUTHENTICATED_LOGIN_REDIRECTS (=True)
The default behaviour is to redirect authenticated users to LOGIN_REDIRECT_URL when they try accessing login/signup pages.
By changing this setting to False, logged in users will not be redirected when they access login/signup pages.
This also worked
Navigate to the allauth folder, under views find SignupView.
Deleting the redirectAuthenticatedUsermixin works
New issue is that you are logged in as the new user, fixing that currently.
First of all, this article maybe useful:
https://tech.serhatteker.com/post/2020-06/custom-signup-view-in-django-allauth/
The reason you can only sign up for a new account if you're not authenticated is because of this Allauth's mixin: RedirectAuthenticatedUserMixin (as suggested by Anthony M).
So, you have to override this mixin and the allauth's signup view with your own code.
It is very important that you register the url before allauth urls.
Hope it helps.
So let me start with the registration process in my web page. The user would register first, and then right after registration, he/she is redirected to a page where the user has to input his/her personal info, such as self-introduction, full name, etc. When the user completes filling his/her personal info in, then the user will be redirected to home page.
So what I wanted to do is this: When the user tries to access home page, check if he/she is logged in. If yes, check if he/she has filled in the personal info. If no, redirect the user to register page. If the user has filled in (=matching query exists), redirect him/her to the home page. If not, redirect him/her to the personal info page, to fill the fields in. And here's my code in views.py
def userHome(request):
if request.user.is_authenticated:
current_user = request.user
if PersonalInfo.objects.get(authuser_id=current_user.id).exists():
context = {
'thisUser' : thisUser,
'newSeed' : newSeed
}
return render(request, '/userhome.html', context)
else:
return redirect('/inputpersonalinfo')
else:
return redirect('/register')
models.py
from django.db import models
from django.contrib.auth.models import User
class PersonalInfo(models.Model):
objects = models.Manager()
authuser = models.OneToOneField(User, on_delete=models.CASCADE, related_name = 'personalinfo', null=True, default=None)
name = models.CharField(max_length=50)
...
I keep getting an error saying PersonalInfo matching query deos not exist. I do understand why this occurs, but can't think of the solution. Please help.
You have to use filter instead of get when you check if PersonalInfo exists:
PersonalInfo.objects.filter(authuser_id=current_user.id).exists()
get throws an error if there's no object matching the query. filter will return an empty queryset.
See the example in the documentation, and a question about get vs. filter
Even if the answer already provided works, I would avoid simply using exists() simply because I'm often likely to use the result of the query and exists() doesn't return the object. In your case I would rather do something like that:
try:
info = PersonalInfo.objects.get(authuser_id=current_user.id)
context = {
'thisUser' : thisUser,
'newSeed' : newSeed,
'someinfo' : info.whatever
}
return render(request, '/userhome.html', context)
except PersonalInfo.DoesNotExist:
return redirect('/inputpersonalinfo')
I want to display the home page of my site based on the user type (admin, guest, student, etc.). It would be nice to display a link to the login page for guest users, but this link should be hidden for already authenticated users. For admins there should be a link to django-admin. Besides that there also some differences in the home page for other user roles.
What is a good way to implement this? I have several options for that:
Create html page for each user role: home_guest.html, home_admin.html, ...
Create a single html page but put some if-clauses inside it like {% if user.is_authenticated %}
You can start with the documentation, using:
from django.contrib.auth.decorators import user_passes_test
def email_check(user):
return user.email.endswith('#example.com')
#user_passes_test(email_check)
def my_view(request):
...
which roughly means that if the user passes the test - provided on the email endswith here - then they will be able to see a view. In my case, I deviated a bit from this and created a
class User(AbstractBaseUser):
status: 1,2 per se, in my model:
student=1
teacher=2
STATUS_CHOICES = ((student, "student"),(teacher, "teacher"),)
status = models.IntegerField(choices = STATUS_CHOICES)
This lets you create an is_status property:
#property
def is_status (self):
return self.status
And then in your login view, you can play along with the properties. If it is 1, display this view, otherwise, display this other one.
I'm trying to set up user profiles in my site so we have:
www.example.com/someuser
www.example.com/anotheruser2
in my urls.py
url(r'^(?P<profile>[0-9A-Fa-f]{1,36})/', 'site.views.profile),
and my view:
def profile(request, profile):
... do something ...
There are two questions:
Is this the correct way to do this or is there a better way?
How should I handle other urls, like "aboutus", etc.
For Point 2, I would do:
url(r'^aboutus/', 'site.views.aboutus'),
url(r'^(?P<profile>[0-9A-Fa-f]{1,36})/', 'site.views.profile),
So now profile will be the catchall for everything else in the site, and I have to check for a valid profile then throw a 404 if a password is not found.
Again, is there a better way to do this?
It's not a good idea to use site.views.profile as a catchall. It's not good separation of responsibilities, it shouldn't be its job. How about something like this instead:
url(r'^profile/$', 'site.views.profile_self'),
url(r'^profile/(?P<profile_name>[0-9A-Fa-f]{1,36})/$', 'site.views.profile'),
url(r'^aboutus/', 'site.views.aboutus'),
For the catchall, use a custom 404 page, or you could let the server raise a 404 error.
accounts/models.py
from django.db import models
class User():
def get_profile(self):
return UserProfile.objects.get_or_create(user_id=self.id)
class UserProfile(models.Model):
user = models.OneToOneField(User)
# another fields
accounts/urls.py
url(r'^profile/$', 'site.views.profile'),
accounts/views.py
from django.contrib.auth.decorators import login_required
#login_required
def profile(request):
# get current logged user profile
profile = request.user.get_profile()
this way the user logged only can see his own profile.
and for the point 2, what's wrong with this?
url(r'^about_us/$', 'site.views.about_us'),
--UPDATE--
ah, ok. then, you are right. but why not with the username?
accounts/urls.py
url(r'^(?P<username>[-\w]+)/$', 'site.views.profile'),
I would like to add to my app a way for users to create their own url. So, what I mean by this, is that if a user wants to go to their webpage, they could go to http://www.projectdomain.com/JimmyJohn
In my model I have
class Person(models.Model):
username = models.CharField(max_length=30) #username = JimmyJohn
....
Is the best way to do this by just adding a method that catches everything after / in urls.py? Or is there a way to more tightly integrate my models with the urls.py?
Just add a url to your main urls.py accepting a first alphabetic argument (consider adding any other urls of your app above this, and validating usernames so your urls are not valid usernames):
urlpatterns = patterns('',
# ... other fixed urls before
url(r'^(\w+)/$', 'website.views.user_page', name='user_page'),
)
Then query for a User in your view matching the given username:
def user_page(request, username):
user = get_object_or_404(User, username=username)
return render(...)