CRUD users in django , outside of django Admin - django

In my current project, I'd like to CRUD users OUTSIDE of django's Admin interface.
Let's explain my question as following:
1- I'm using the UserProfile for storing additional attributes for users (their schools, birthday, etc.)
2- The problem is that by deleting a user, I can delete the profile rather than actual User.
Please take at the code for Listing and Deleting Users:
def user_list(request):
''' Shows all of Students '''
return object_list(request,
queryset = UserProfile.objects.all() ,
template_name = 'user_list.html' ,
template_object_name = 'student'
)
def user_delete(request , id):
''' Deletes a student based on his/her ID '''
return delete_object(request,
model = UserProfile ,
object_id = id ,
template_name = 'delete_student.html' ,
post_delete_redirect = reverse("user_list")
)
It looks normal that I'm deleting UserProfile rather than User. But I intended it to be a proxy to actual User. Do I miss something here ?
3- Generally speaking, should I reference each models to User or UserProfile ? For example assume that I have a model for Course. Which of these is the correct way?
class Course(models.Model):
#stuff
student = models.ForeignKey(Urer)
# OR ??
student = models.ForeignKey(UserProfile)

It looks normal that I'm deleting UserProfile rather than User. But I intended it to a proxy to actual User
Why not delete the User directly? By default, Django will CASCADE DELETE to get rid of the UserProfile as well.
Generally speaking, should I reference each models to User or UserProfile
I think this is more a question of personal preference, but I usually tie to User directly as it saves a step when getting to the object you want (you don't need to do user.get_profile().student and can call user.student instead). It also makes more sense to me anyway: the student is a property of the user, not the user's profile.

Related

How can I access a value from one model and pass to another model in Django?

I have one model called Weight (filled by User input/choice) and another called Enterprise.
class Weight(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE, related_name="weights")
weight_of_history = models.IntegerField(null=True, blank=True)
class Enterprise(models.Model):
...
The weight is saved, one per user, and replaced everytime the user choose new one.
Inside the Enterprise class, I am creating an property that must get the "weight_of_history" (depending on the user, who has chosen the weight) from Weight class, but the models have no Foreign key or related name between them.
class Enterprise(models.Model):
...
#property
def ranking(self):
weight_of_history = <-- HERE I NEED TO TAKE WEIGHT_HISTORY FROM THE FIRST MODEL
THEN I COULD CALCULATE
How could I do that? Thank you!
You can use django's powerful query functionality and fetch the required objects from the db. Here are the docs that might help you with that. Django docs are amazing, so I would recommend that you read up on queries, models, and forms to have easier time with you project.
For your example we can fetch all the weights for the user in one query by filtering the weights by user. In fact, django ORM allows for chaining filters and you can create really sophisticated queries
class Enterprise(models.Model):
...
#property
def ranking(self):
weight_of_history = Weight.objects.filter(user=some_user)
If you do not know the user beforehand, then you can do inside the view and grab the user that makes the request and filter using this user:
#views.py
user_making_request = request.user
weight_of_history = Weight.objects.filter(user=user_making_request)

Retrieving multiple rows from seperate model in django relationships

I've been struggling with this puzzled for a few hours. Here's a schema of what I'm trying to do.
I have a user model and a profile model, it's a one-to-one relationship, but I'd like to be able to query a user and retrieve all the email addresses (from the User model) for users that share the same company (from the Profile Model). To be fair, my understanding of django is limited, but I went through the serializer relations guide and tried my hands at most approach described there, to no avail. At this point, I'm not even sure I'm on the right path.
So, my understanding of it is
From the user, I need to fetch the profile (a source='profile' approach may work)
From that profile, I need to retrieve the company
From that company, I need to retrieve all the user_id that belongs to that company
From those user_ids, I need to lookup the email fields of all those users
I need to also filter out the email address of the user making the request
Does this make any sense? At this point, I'm trying to accomplish all of that from the serializer, but was unsuccessful. Here are some snippets of code I tried, but I doubt any of them will point towards any form of solution, unfortunately.
class TeamEmailsSerializer(serializers.ModelSerializer):
class Meta:
model = User
fields = ['email']
class UserSerializer(serializers.ModelSerializer):
...
# only one of them was present at a time, but none gave any promising results
test_one = Profile.objects.filter(source=profile.company.id).values_list('user_id', flat=True)
test_one = serializers.RelatedField(source='profile.company.id', read_only=True)
test_one = TeamEmailsSerializer(many=True, read_only=True)
test_one = serializers.PrimaryKeyRelatedField(source='email', queryset=User.objects.filter())
class Meta:
model = User
fields = (
'test_one'
)
I'm grateful for any clue that may lead towards a solution.
First, you should add company FK on your user as well, it will make things much easier for you.
Then you can define a new method on User model:
class User(AbstractBaseUser):
...
def other_users_emails(self):
return self.company.users.exclude(pk=self.id).values_list('email', flat=True)
Then in your serializer add 'other_users_emails' to the fields list.
Alternatively you could modify to_representation method on your serializer and add 'other_users_emails' attribute directly there

Django how to implement a one-to-many self-dependent foreign key

I am implementing a User referral system, which existing users can refer other people to register an account with the link they provided. After the new user registers, the new user will be stored to the field 'referred_who' of the existing user.
I have tried using the following method:
class CustomUser(AbstractBaseUser):
...
referred_who = models.ManyToManyField('self', blank=True, symmetrical=False)
class ReferralAward(View):
def get(self, request, *args, **kwargs):
referral_id = self.request.GET['referral_id']
current_referred = self.request.GET['referred']
// referrer
user = get_user_model().objects.filter(referral_id=referral_id)
// user being referred
referred_user = get_user_model().objects.filter(username=current_referred)
for item in user:
previous_referred = item.referred_who
previous_referred.add(referred_user[0])
user.update(referred_who=previous_referred)
And I got the following error:
Cannot update model field <django.db.models.fields.related.ManyToManyField: referred_who> (only non-relations and foreign keys permitted).
I am not sure if this method even works. I have check the Django Admin backend and I realized the 'Referred who' field actually contains all the users. It seems that it only highlightes the user being referred instead of only showing the referred users.
Also, I tried to access the 'referred_who' field in the back-end and it returns 'None'.
Is there a way to stored the users in the 'referred_who' field so that I can see all of the user being referred and access them in the back-end? For instance:
referral_id = self.request.GET['referral_id']
user = get_user_model().objects.filter(referral_id=referral_id)
print(user[0].referred_who)
Can someone show me a better way to do it? Thanks a lot!
You ask how to create a 1-Many field, but in your models you're trying to create m2m. Just change field to FK.
referred_who = models.ForeignKey('self', blank=True).
In case you need to have multiple fks to the same model, you need to specify related_name as well. You can use name of the field for it. More in docs.

Django forms and registration: insert data to other tables

In my app, I've got 2 types of users: Student and Teacher. I want to store additonal information about each of them in separate table.
class Student(models.Model):
user = models.ForeignKey(User)
nr_indeksu = models.BigIntegerField()
def __unicode__(self):
return unicode(self.user)
Let's assume i want to register user as student - In that case, i need to expand User registration form, so it will contain fields from Group and Student model, and during registration i want to insert Student.nr_indeksu with Student.user_id(FK) into student table, and Group.name into User_Groups.
I've created StudentForm by using Meta Class and rendered it in template in the same form where UserCreationForm is, but i don't know how to handle saving into database, because UserCreationForm creates user_id that it's supposed to go into Student mode. Any pointers?
I had a similar issue. Solved it by making the model look a little different:
class Student(User):
nr_indeksu = models.BigIntegerField()
def __unicode__(self):
return unicode(self.user)
This way, when you define the Django form, all needed fields will be rendered for this model. This is because you are saying The student is a user , as opossed to the former the student has a user
The form could look like:
class StudentForm(forms.ModelForm):
class Meta:
model = Student
Edit:
Use a similar approach for teacher model.
If you want to avoid the rendering of some fields, use the fields attribute in the Meta class.
Second Edit:
If you want to preserve the validations and checks of the User form, the form should also inherit from UserCreationForm.

For all my foreignKeys, should i use User or UserProfile in Django?

Here is the sutuation i hit.
I have both User and ProfileUser. I would like to add additional logic to the model and since I can't add it to the Django User model, I have to add it to the ProfileUser. Currently all my models however have ForeignKey(User). Should I keep them like that or should I user ForeignKey(UserProfile) on my other models?
Example for my view if I keep the ForeignKey(User):
class myview(request):
user = request.user
userProfile = user.get_profile()
neededStuff = userProfile.get_needed_stuff()
and then in the UserProfile model:
def get_needed_stuff(self):
user= self.user # Or actually, is this right
goals = Goal.objects.get(<conditions that i wont bother writing here>)
return goals
So for this case, and for further development of the site, which foreign key should i use?
I think You should use User. UserProfile should be custom and can differ on each project. So if you will use same code for another project you can probably fail because of that. Also it is always easy to get user object in code and from that you have no problems to get profile user.get_profile() as you show (and profile is not always needed). So ingeneral I think it will be easier to use other modules and passing them just user object (or id) and not the profile.
What is also could be the solution - write your own class which will be responsible for the users. Just write methods to return profile, return stuff_needed or whatever you want and everything just by passing user object and additional parameters about what you want.
So in short, I'm for using User for Foreign keys, because in my opinion it just more logical, while the User model is always the main one (you always have it) and UserProfile is just extension.
Ignas
If you just want all the goals belonging to a specific user add a foreign key to User in your Goal model.
class Goal(models.Model):
user = models.ForeignKey(User)
def myview(request):
goals = Goal.objects.filter(user=request.user)
Or alternately save all the goals for a user on your UserProfile model and do
def myview(request):
user_profile = user.get_profile()
goals = user_profile.goals
...or use a method to do processing to calculate them
goals = user_profile.calculate_goals()
I've been pondering the same thing myself for one of my sites but i decided to use UserProfile rather than User.
Not sure if its the right decision but it just seems more flexible.