I have a CustomUser and a Profile app in my profile app i have following models:
class Profile(models.Model):
user = models.OneToOneField(MyUser,unique=True)
name = models.CharField(_('Name'),max_length=100)
work = models.CharField(_('Position'),max_length=200)
company = models.CharField(_('Company'),max_length=200)
gender = models.CharField(_('Gender'),max_length=10)
photo = models.ImageField(_('Profile Pic'),upload_to='images/',blank=True)
bio = models.TextField(_('Bio'),max_length=300)
def __str__(self):
return self.name
My main problem is when i include user field in forms it displays a drop down list of all user who are registered with the app.
And i want to show only loggedin user
I think this approach is better and saves a time:
user = MyUser.objects.filter(username__icontains=request.user)
form.fields['user'].queryset = user
This is a question specific to the form you are using, rather than the model. What you want to do is specify a queryset for the field user.
You may do this after instantiating your initial form. The following would go in your view, where you declare your form for get requests:
# Obtain set of authenticated users (see [1] below)
authenticated_users = []
users = User.objects.all()
for user in users:
if user.is_authenticated():
authenticated_users.append(user)
# Instantiate form and update `user` queryset
form = SomeForm()
form.fields['user'].queryset = authenticated_users
[1] I don't believe it's possible to filter the User object manager by whether a user is authenticated or not, unfortunately, so you must iterate through the queryset and check for each user. If anyone knows such a query, then I'd be happy to change my answer to it.
This will limit the dropdown to authenticated users.
Related
I have an app I am developing that has 2 types of user (A & B) and I have a page that I want to redirect users that are not authenticated and not type B. The user type is set in a relational database.
My two db tables for this are
User - pk, etc...
Profile - pk, uid (user pk), account_type
What I have done so far:
I have already used #login_required in my views.py doc to verify authentication successfully.
I can filter for the content where pid is set manually:
Profile.objects.filter(user__pk=1)
And I can get the current user id with request.user.id
What I am struggling with
What I have attempted to do is create a conditional, where I am using the request.user.id with the filter to find that user and then verify account type. I am not sure how to pull the account_type and at this point my code is becoming a mess, and probably ineffective. I've searched for this, but everything I have found using the keywords I have here has revealed different problems than what I am trying to solve.
Edited additional info
I have 2 apps at use here, 1 is accounts one is listings, the page I am doing this for is for posting a listing, that is in the listing app; I only want one type of user (B) to be able to post it.
in the accounts I have this class:
class Profile(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
location = models.CharField(max_length=30, blank=True)
account_type = models.CharField(max_length=30)
In the listing app I have not yet created a relevant model, my understanding was that this filtering would happen in the view.
In the view I am doing:
#login_required
def post(request):
current_user = request.user
if : #here is where I want to filter, but haven't been able to get it to work
else:
return redirect('index')
You will get the account type value directly as
account_type = request.user.profile.account_type
So, you could able to do the stuff according to the account_type value as below,
#login_required
def post(request):
account_type = request.user.profile.account_type
if account_type == "B"
# do your stuff
else:
return redirect('index')
Starting from your model design, if your system has the criteria that one user has only one profile. Then set uid in Profile model as OnetoOneField so that you can easily access account_type by User.objects.filter(id=request.user.id).profile.account_type.
Else, if your system has the criteria that one user can have multiple profile. Then you first need to access it profiles, and select the particular profile by adding more filter, then you access the account_type:
User.objects.filter(id=request.user.id).profile_set.all() gives you user's all profile.
User.objects.filter(id=request.user.id).profile_set.get(your_filter) gives you user's particular profile.
User.objects.filter(id=request.user.id).profile_set.get(your_filter).account_type gives you access to particular user's profile's account_type.
One to One relationship description here
Foreign (many to one) key description here
I have a custom user setup like this:
class CustomUser(AbstractUser):
pass
class Employee(CustomUser):
user = models.OneToOneField(settings.AUTH_USER_MODEL)
# other fields
In settings.py, I then add the following key:
AUTH_USER_MODEL = 'myapp.CustomUser'
I want to identify who logged in redirect them to appropriate views or urls.
In my account activation view, after the logging them in I redirect them to their appropriate page like this
if hasattr(user, 'employee'):
return redirect('edit_employee', slug=user.employee.slug)
else:
return redirect('index')
But this doesn't feel that right as I need to use this in other places like showing a different profile page link in the templates.
How do I better identify the regular user and employee in views and templates?
AFAIK you should not store different types of users in different tables. It will make your life pretty hard when defining relationships between other models and your users model.
My suggested approach would be having different profile models for different types of users and using a generic FK or some sort of other similar approaches to find out the user type and get their profile.
class CustomUser(AbstractUser):
USER_TYPE_EMPLOYEE = 'employee'
USER_TYPES = (
(USER_TYPE_EMPLOYEE, _('Employee')),
)
user_type = models.CharField(max_length=max(map(len, map(operator.itemgetter(0), CustomUser.USER_TYPES))), choices=CustomUser.USER_TPYES)
#property
def profile_model(self):
return {
USER_TYPE_EMPLOYEE: EmployeeProfile
}[self.user_type]
#property
def profile(self):
return self.profile_model.objects.get_or_create(user_id=self.pk)
class EmployeeProfile(models.Model):
user = models.OneToOneField(settings.AUTH_USER_MODEL, related_name='employee_profile')
The idea of extending the User Model to create an Employee Model doesn't seem good to me. Instead of this, you can use Django Group Model and add the user to the employee group. In this way, you can easily check if a user belongs to Employee group or not.
Additionally, you can also use django permissions here.
Assign your custom permissions to the employee group and restrict other users to view employee pages.
I've followed https://docs.djangoproject.com/en/1.5/topics/auth/customizing/#extending-the-existing-user-model to add a ManyToMany field for what games a user has played.
class Profile(models.Model):
""" Extended authentication profile storing specific info """
user = models.OneToOneField(User)
owned = models.ManyToManyField(OwnedStruct)
then add to admin by the following
class ProfileInline(admin.StackedInline):
""" Show profile inline with user """
model = Profile
verbose_name_plural = 'profile'
class UserProfileAdmin(UserAdmin):
""" Add inline to User """
inlines = (ProfileInline,)
...
admin.site.unregister(User)
admin.site.register(User, UserProfileAdmin)
In the database things look fine, but in the admin I see two fields representing the ManyToMany OwnedStruct. Before messing with the user, it shows the first as "Profile #1" and the second as "Profile #2". After selecting some options from Profile 1's M2M and clicking save, it appears to update that field correctly. If I update Profile#2, it does not save or work or appear to change anything. I'd expect it to only show one. What could cause two Profiles?
If I understand correctly the problem is that for some reason django admin doesn't care about OneToOneField and create more than one inline forms for the Profile. You can try to fix that with adding max_num = 1 to your ProfileInline class.
It must look something like:
class ProfileInline(admin.StackedInline):
""" Show profile inline with user """
model = Profile
max_num = 1
verbose_name_plural = 'profile'
I have a Django model:
class Project(models.Model):
user = models.ForeignKey(User)
zipcode = models.CharField(max_length=5)
module = models.ForeignKey(Module)
In my views.py:
def my_view(request):
...
project = Project.objects.create(
user=request.user,
product=product_instance,
...
)
project.save()
I want to be able to save user as an authenticated user OR an AnonymousUser (which I can update later). However, if I'm not logged in I get this error:
ValueError: Cannot assign "<django.utils.functional.SimpleLazyObject object at 0x1b498d0>": "Project.user" must be a "User" instance.
I guess that Django won't save the AnonymousUser because it is not a User as defined in the User model. Do I need to add the anonymous user to the User model, or am I missing something?
Any assistance much appreciated.
The user field is a ForeignKey. That means it must reference some user.
By definition, the AnonymousUser is no user: in Django, there is no AnonymousUserA and AnonymousUserB. They're all the same: AnonymousUser.
Conclusion: you can't put an AnonymousUser in a User ForeignKey.
The solution to your issue is pretty straightforward though: when the User is anonymous, just leave the field blank. To do that, you'll need to allow it:
user = models.ForeignKey(User, blank = True, null = True)
I have a User Profile which is currently shown in the Admin via a Stacked Inline. However because I have fields such as last_name_prefix and last_name_suffix (for foreign names such as Piet van Dijk to cover proper sorting by last name) I would like to be able interleave the user profile fields with the normal change user fields. So in the Change User admin interface it would appear like this:
First Name:
Last Name Prefix:
Last Name
Last Name Suffix:
I have tried this solution: http://groups.google.com/group/django-users/browse_thread/thread/bf7f2a0576e4afd1/5e3c1e98c0c2a5b1. But that just created extra fields in the user form that weren't actually coming from the user profile (they stayed empty even though they should get values from the user profile).
Could someone explain to me if this could be done and how?
Thanks very much!
I'm pretty sure you'd need to overwrite normal User admin.
What I would actually do is create a special forms.ModelForm for UserProfile called, say UserProfileAdminForm which included fields from the User model as well. Then you'd register UserProfile for admin and the save function for the UserProfileAdminForm would capture the user-specific fields and either create or update the User record (This is left as an exercise to the OP).
More info
When I say add more fields to a form, I mean manually add them:
class UserProfileAdminForm(forms.ModelForm):
username = forms.CharField(...)
email = forms.EmailField(...)
first_name = ...
last_name = ...
def __init__(self, *args, **kwargs):
super(UserProfileAdminForm, self).__init__(*args, **kwargs)
profile = kwargs.get('instance', None)
if profile and profile.user:
self.user = profile.user
self.fields['username'].initial = self.user.username
self.fields['last_name'].initial = ...
...
class Meta:
model = UserProfile
This question has been solved by the new Django version 1.5: https://docs.djangoproject.com/en/1.5/topics/auth/customizing/#auth-custom-user.