Sorry for the dumb question but I can't figure it out.
I have a class based view for a form. I like to make some changes if the request.user is equal with something.
I used before in some other views request.user.profile.leader that gives me a boolean answer. Thats OK.
Now in this class based view I like to use a very similar stuff but with another model like this: request.user.trust.group but it gives me nothing. What am I doing wrong?
If you haven't customized your user model, then profile will appear on it as a reverse descriptor of an one-to-one field on another model (by way of related_name having been set or inferred), i.e. you have something like
class Profile(Model):
user = models.OneToOneField(User, related_name="profile")
leader = models.BooleanField(...)
somewhere.
If you expect a trust field to be there, then you'd need something similar:
class Trust(Model):
user = models.OneToOneField(User, related_name="trust")
group = ...
On the other hand, if you do have an entirely custom user model, then those attributes could appear directly on it:
class CustomUser(AbstractBaseUser):
profile = models.ForeignKey(Profile, ...)
trust = models.ForeignKey(Trust, ...)
Related
I dont understand Django Intermediary models at all. Let's say that i want to add one more additional field to User model, and store relationship between two users in another model(intermediary) like this:
class Contact(models.Model):
user_from = models.ForeignKey(User...)
user_to = models.ForeignKey(User...)
...
And the field i want to add is:
following = models.ManyToManyField('self',
through=Contact,
related_name='followers',
symetrical=False)
What really happen when i call user_object.followers.all() and what is the difference between user_object.following.all() are they both the same?
Using Django we have two types of Users (Teachers and Students) with common fields and uncommon fields
In our wizard we first POST the common fields to /users with an extra type_field
Every operation after this should be able to figure out which model (Teacher or Student) it needs to use.
We are thinking of making two models ( Teacher and Student ) with an one-to-one field.
But how do we hookup the type_field to the right Model on every operation?
You dont have to go for an extra field since you are already having two different classes for students and teachers. A simple approach may looks like below.
from django.contrib.auth.models import User
class Teacher(User):
extra_field_1 = models.Fieldtype()
...
...
class Student(User):
extra_field_1 = models.Fieldtype()
...
...
You can provide both type of users same registration form and upon clicking next take them to next page based on the value of I am a teacher/student field. In that case I suggest you to use atomic blocks if you dont want to save data in case registration procedure fails at some point or user have selected a wrong choice and they want to go back. By this approach each inherited models have username, first_name, last_name and email that you dont have to insert any of these to Teacher or student model.
Then you have to create forms for each model. You may use modelform A much better approach will be using class based views since that reduce a lot of code and stick to dry principles.
You may use something like:
class Person(models.Model):
first_name = models.CharField(max_length=255)
last_name = models.CharField(max_length=255)
# more common fields
class Student(Person):
specific_field_to_student = models.CharField(max_length=255)
# more fields
class Teacher(Person):
specific_field_to_teacher = models.CharField(max_length=255)
# more fields
In your database you will have 3 tables (yourapp_person, yourapp_student and yourapp_teacher). Now, if type_field value is student, you will use Student model to create user, if it is teacher, you will use Teacher model.
Note: You may need to make Person model above a subclass of the built-in User model.
Edit:
I have edited the model above to take into account the requirements in the comments below.
Now, to retrieve user by id, you can use the following code in your view:
user = Person.objects.get(id=id) # id is the view param
if hasattr(user, 'student'):
print("Student")
else: # hasattr(user, 'teacher')
print("Teacher")
In my project I have to deal with different type of users e.g. costumers and employers. Each type of user have its own fields and permissions: costumer can buy things whereas employer can not.
I have read the Django docs and it looks like there are two options:
Costumize the AbstractUser class and adding all the fields of costumers and employers. Then use the permission system to grant/revoke permission or create a group for each type of user. The downside here is that there unused fields.
Adopt the proxy model:
from django.contrib.auth.models import User
from django.db import models
class Costumer(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
class Meta:
db_table = 'costumers'
permissions = (
("access_this", "User may access this"),
)
ordering = []
class Employee(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
class Meta:
db_table = 'employers'
permissions = (
("access_that", "User may access that"),
)
ordering = []
This case seems more reasonable but I don't know how to deal with the permissions. Consider I'd like to use #permission_required instead of checking the type (if the user has a specific field) because it seems more legit for Django system.
So in the end, what is the best way to approach such scenario?
The first solution is much better.
The downside here is that there unused fields.
I disagree with this, you don't have to store all the fields within the User model. Also, if you're talking about 5 fields for example, that doesn't really matter.
You can extend AbtractUser and also use some composition; you don't have to put all the fields there:
class User(AbstractUser):
email = ...
...
# for the employer, let's say you want to save the company details
company = models.ForeignKey('myapp.Company', null=True, blank=True)
...
# for the customer
customer_details = models.ForeignKey('...')
This way you could record a user_type if you want or deduce the type from the foreign key (if there is a company, it's an employer).
To help you more with the model, I need to know what differentiate an employer from a customer in your application. Note that with that solution, an instance of User could be both.
Concerning the permissions, I feel like it's a separate problem; I'd recommend you to sort it last. If the design you pick is close to the reality and you get the features working; adding custom permissions will be really easy.
Say, for example, I have two models:
class Person:
name = models.CharField(max_length=20)
address = models.CharField(max_length=20)
class PhoneNumber:
person = models.ForeignKey(Person)
number = models.CharField(max_length=20)
So, when a user is going to modify a PhoneNumber, I'd like to show, in the form, the address of the person. I'm doing the editing through formsets, so that makes it passing the information directly to the template a bit trickier, how could I know which address belongs to which form? Or how else could I achieve this? This should be shown in a different place than the ModelChoiceField, since I want it to be hidden.
Within your template is it possible to loop over the forms in a formset. See https://docs.djangoproject.com/en/1.7/topics/forms/formsets/#using-a-formset-in-views-and-templates.
So I would make a FormSet containing PhoneNumber modelforms. While looping over the forms, use form.instance.person.address.
For a simple activation key for an account, I have to create the key from random numbers while making sure that I'm not using the same key as another account. Right now, this is what I have:
def get_random_word():
word = ''
i = 0
while i in range(10) and User.objects.filter(activation_key = word).exists():
word += random.choice('ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789')
i+=1
return word
The problem, I realize now, is that I use django's built in User class with a user profile like this:
def create_user_info(sender, instance, created, **kwargs):
if created:
UserInfo.objects.create(user=instance)
post_save.connect(create_user_info, sender=User)
class UserInfo(models.Model):
user = models.OneToOneField(User)
pen_name = models.CharField(max_length=30)
activated = models.BooleanField()
activation_key = models.CharField(max_length=40)
def __unicode__(self):
return self.email + '-' + self.pen_name
I need to filter by the user profile. So, in short, how do I filter by a key or, more specifically, a user profile.
first of all, add a related_name to your UserInfo:
class UserInfo(models.Model):
user = models.OneToOneField(User, related_name='profile')
...
https://docs.djangoproject.com/en/dev/ref/models/fields/#django.db.models.ForeignKey.related_name
and then you can do something like this:
User.objects.filter(profile__activation_key=word).exists()
hope it helps :)
I am not 100% sure what exactly you want to achieve, but here are two answers which might be fitting your needs:
Generally
First you need to connect the Django built-in user model with your UserProfile model. This is done in settings.py setting the AUTH_PROFILE_MODULE setting
AUTH_PROFILE_MODULE = 'myapp.UserProfile' # replace `myapp` with your application name
Answer 1
You can get the user profile for a specific user via user.get_profile() assuming user is a already existing instance of django.contrib.auth.User.
Answer 2
You can query your UserProfile model first by whatever key you want to query for and then map the result set back to your user directly, e.g.:
from myapp.models import UserProfile
profiles = UserProfile.objects.filter(activation_key='abcdef')
for profile in profiles:
print profile.user # this is the profiles connected user instance
First, you don't really care if 2 users have the same activation key. This case is so rare that it can't be a target for any kind of attack.
Second, why not include the username in the activation URL?
This way you are assured to have an unique activation URL for each user.
ex: yourwebsite.com/users/activate/{username}/{activationcode}.
Third, you can use an UUID instead of random. UUID are granted to be unique (well not exactly but 99.99% of the time).
http://docs.python.org/library/uuid.html
Fourth, do you really need to keep the activation code in the profile informations? Why not create an independent activation table, you can even set the primary key to be the activation code. Most of the time, it is better to separate informations that won't be used much from the ones you will use often.
Fifth, You don't really need to query the User table at all. You just need to query the UserProfile table and check if the activation key exists. Then and only then, you can use the OneToOne relation to map to the original user.
You don't even need to add the related_name value to the user relationship. The following query works for your profile model.
User.objects.filter(userinfo__activation_key=word).exists()