Django - Linking my models to profiles (UserProfile) model - django

I'm trying to create a small app for users to have contacts. I'm using django-profiles as a base for my profiles. Now everything works well until I try to submit the edit contact form and I receive this error.
Cannot assign "<Contact: Contact object>": "Contact.user" must be a "UserProfile" instance.
Being pretty new to Django, I'm not even sure if I'm taking the right approach here. My end goal is for the user to be able to add as many contacts as neccessary.
Any advice is appreciated.
My UserProfile model which extends User looks like:
class UserProfile(models.Model):
#User's Info
user = models.ForeignKey(User, unique=True)
first_name = models.CharField("first name", max_length=30)
last_name = models.CharField("last name", max_length=30)
home_address = models.CharField(max_length=50)
primary_phone = PhoneNumberField()
city = models.CharField(max_length=50)
state = USStateField()
zipcode = models.CharField(max_length=5)
birth_date = models.DateField()
gender = models.CharField(max_length=1, choices=GENDER_CHOICES, blank=True)
and my contact model looks like this:
class Contact(models.Model):
user = models.ForeignKey(UserProfile)
contact_description = models.CharField("Relation or Description of Contact", max_length=50, blank=True)
contact_first_name = models.CharField("contact first name", max_length=30)
contact_last_name = models.CharField("contact last name", max_length=30)
contact_primary_phone = PhoneNumberField("contact primary phone number")
contact_secondary_phone = PhoneNumberField("contact secondary phone number",blank=True)
and my view:
def editContact(request, username, object_id=False, template_name='contacts/edit.html'):
user = UserProfile.user
AddContactFormset = inlineformset_factory(UserProfile,Contact, extra=1)
if object_id:
contact=Contact.objects.get(pk=object_id)
else:
contact=Contact()
if request.method == 'POST':
f= ContactForm(request.POST, request.FILES, instance=contact)
fs = AddContactFormset(request.POST, instance=contact)
if fs.is_valid() and f.is_valid():
f.save()
fs.save()
return HttpResponse('success')
else:
f = ContactForm(instance=contact)
fs = AddContactFormset(instance=contact)
return render_to_response(template_name ,{'fs':fs,'f':f,'contact': contact}, context_instance=RequestContext(request))

Basically, django-profiles is for something else - it's just helping to create and manage user profiles across an application.
First of all - you should link Contact models directly to the django.contrib.auth.models.User via ForeignKey. This way you can access given User's contacts by a simple query ie. User.contact_set.all() - it will return to you a list of User's contacts. This will also get rid off your error.
Second - fields like first_name, last_name are already definied in django.contrib.auth.models.User, so there is no need to define them again in UserProfile. Read the source of User model here
Third - if your user can only have one Profile and you're not intend to use very old versions of django then you should be using OneToOneField instead of ForeignKey.
Fourth thing - you could probably omit usage of RequestContext() by using one of the generic views bundled with django - read about that here
Last thing - remember that main model for handling the Users is the User model itself. Any custom Profile is just an extension, so link everything which is related to the User to the User model itself.
Happy coding!

To elaborate on bx2's answer, your Contact model should look more like this:
class Contact(models.Model):
user = models.ForeignKey(User, related_name='contacts')
contact_description = models.CharField("Relation or Description of Contact", max_length=50, blank=True)
contact_first_name = models.CharField("contact first name", max_length=30)
contact_last_name = models.CharField("contact last name", max_length=30)
contact_primary_phone = PhoneNumberField("contact primary phone number")
contact_secondary_phone = PhoneNumberField("contact secondary phone number",blank=True)
Your view, frankly, does not make much sense. In general an inline formset is meant to represent records related to some parent record. In your case, it would be the user record, with the contacts being the "children" records. But having both a Contact form and an AddContactFormset doesn't make a lot of sense.
Also, I'd recommend against using variable names like f and fs in Django. Apart from variables like indexes, counters, etc. it doesn't serve any purpose to use short 1-2 character variable names. Go ahead and use longer variable names like form and formset, or even contact_form and contact_formset. It makes it much, much easier to debug the code in the future.

Related

Show data from specific table in my view django

I want only the requests from the Hospital.
How can I achieve this?
Example:
User from Hospital
class CustomUser(AbstractBaseUser, PermissionsMixin):
email = models.EmailField(_('email address'), unique=True)
FKbelongs_to = models.ForeignKey('HospitalViewRoleForUsers', on_delete = models.CASCADE, null=True, blank=True)
Hospital Model
class HospitalViewRoleForUsers(models.Model):
RequestsFromLab = models.ForeignKey('request', on_delete=models.PROTECT)
Requests from the Hospital
FKHospitalRequests = models.ForeignKey('HospitalViewRoleForUsers', on_delete = models.PROTECT)
user_request = models.ForeignKey('customuser', on_delete= models.PROTECT)
In my View I need to validate which Hospital the user belongs to and,
Pass only the request information from that hospital to my user view.
The user view that I am trying to build
def Get_UserRequestByHospital(request, pk):
user = request.user
items = requests.objects.filter(FKHospitalRequests = 1).values_list('id', flat = True)
return render(request, 'user_profile/list-user-request.html', {'items': items})
In Jupyter testing data it appears like this
user_hospital2 = requests.objects.filter(FKHospitalRequests = 1).values_list('id', flat = True)
<QuerySet [1]>
As we can see, Jupyter returns the request id. Which is linked to the Hospital. But, I am confused and I need help thinking on a solution. I am new to Django, so. I suppose I need to pass the PK to the view, and then, create a filter to check if PK is equal to FK from the Hospital Request? But, also, How I know this user belongs to the Hospital? Thank you. I am really lost and I am new to Django.
-- Edit: Users from the same hospital can see others users requests.
I solved by doing this:
In my view of requests I added a FK to check if is equal to the User FK.
With this method I can make only users from Hospital 1, to see the requests of Hospital 1.
def Get_UserRequest(request, FKbelongs_to_id):
user = request.user
if CustomUser.objects.filter(FKbelongs_to_id = FKbelongs_to_id):
items = requests.objects.filter(FKHospitalRequests_id = FKbelongs_to_id)
else:
return HttpResponseNotAllowed("Not Allowed")

Django ORM Query Optimization Issue

I am making a blog website and I am facing some issues with the Query performance.
I have 3 models
User Model -> Users (To store user email, Password etc)
Post Model -> Actual Posts
people Model -> (To store users extra information)
Post Model ->
class Post(models.Model):
user = models.ForeignKey(User, on_delete=models.PROTECT)
category = models.ForeignKey(Category, on_delete=models.PROTECT)
title = models.CharField(max_length=255,null=True)
description = models.CharField(max_length=1000,null=True)
Likes = models.ManyToManyField(to=User, related_name='Post_likes')
favourites = models.ManyToManyField(to=User,blank=True,related_name="favourite")
People Model ->
class People(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
photo = models.ImageField(upload_to='profile_pics', blank=True,null=True)
Phone_number = models.CharField(max_length=255,null=True,blank=True)
Birth_Date = models.DateField(null=True,blank=True)
Created_date = models.DateTimeField(auto_now_add=True)
Updated_date = models.DateTimeField(auto_now=True)
Now as both of these models are connected to User model. I want to query the Post model and get the user photo in the template. Now when I use post.user.people.photo then for every post it generates a seperate query to DB resulting in slowness. I would like to use Join here to combines multiple tables and fetch all the records at once.
I am currently using following Query ->
posts = Post.objects.select_related().prefetch_related('images_set').annotate(comments_Count = Count('comments_post',distinct=True)).annotate(Count('Likes',distinct=True)).all().order_by('-id')
You can perform a .select_related(…) [Django-doc] on the user and the people with user__people, so:
posts = Post.objects.select_related(
'user__people', 'category'
).prefetch_related('images_set').annotate(
comments_Count = Count('comments_post',distinct=True),
Count('Likes',distinct=True)
).order_by('-id')
Note: It is normally better to make use of the settings.AUTH_USER_MODEL [Django-doc] to refer to the user model, than to use the User model [Django-doc] directly. For more information you can see the referencing the User model section of the documentation.

Is partial form a good practice in Django?

I'm new in Django and I try to find out if saving partial forms are a good practice or not. For example, I have Poll App and Candidate model with four fields: name, surname, targets andbiography. And I have a form where I have to fill all these fields. But if user only finished fill name, surname and targets, but even din't start filling biography field, how can I save his draft to user can finish it later and don't make any security mess?
models.py:
class Candidate(models.Model):
name = models.CharField(max_length=50)
surname = models.CharField(max_length=50)
biography = models.TextField()
targets = models.CharField(max_length=1000)
forms.py
class CandidateForm(ModelForm):
class Meta:
model = Candidate
fields = [
'name',
'surname',
'biography',
'targets',
]
widgets = {
'biography': forms.Textarea(attrs={'rows': 3})
}
I will be happy to see all ideas.
how can I save his draft to user can finish it later and don't make
any security mess?
You can either save the data to DB if you have designed the models to accept null or blank values, Or you can use Django sessions to temporarily store the form data until the form is completed...
In both case the security is not an issue since just like a DB access the django session data is also stored in a database and not in the browser... and so the end users cannot easily mess with the data...
check the following answer if you would like to know more...
Your problem is here :-
models.py:
class Candidate(models.Model):
name = models.CharField(max_length=50)
surname = models.CharField(max_length=50)
biography = models.TextField()
targets = models.CharField(max_length=1000)
If you put default='your default value':-
models.py:
class Candidate(models.Model):
name = models.CharField(max_length=50)
surname = models.CharField(max_length=50)
biography = models.TextField(default=' ')
targets = models.CharField(max_length=1000)
I think this is right what you need

Retrieving all database objects and its related objects Django

I am currently learning Django, and I am finding it a bit difficult wrapping my head around the ManyToMany fields. I am using an intermediate model to manage my relationships.
I have three models; Ticket, User, and TicketUserRelation.
I want to be able to query the ticket model, and retrieve both its corresponding user objects and the ticket object. How would I go about doing this?
In Laravel I would do something along the lines of
Ticket::where('id', '1')->with('contributors')
But I can't really figure out how to do this in Django
The models:
class User(models.Model):
name = models.CharField(max_length=50)
def __str__(self):
return self.name
class Ticket(models.Model):
contributors = models.ManyToManyField(User, through=TicketUserRelation, related_name='tickets')
name = models.CharField(max_length=50)
created_at = models.DateField()
def __str__(self):
return self.name
class TicketUserRelation(models.Model):
id = models.AutoField(primary_key=True, db_column='relation_id')
ticket = models.ForeignKey(Ticket, on_delete=models.CASCADE)
user = models.ForeignKey(User, on_delete=models.CASCADE)
EDIT: I am using an intermediate model so that I can easily add things like join date later.
You don't need the TicketUserRelation model when using Django ORM. You could simply use a ForeignKey in the Ticket model, or use the ManyToManyField already defined, if one ticket can be assigned to multiple users.
class Ticket(models.Model):
# For one user, use ForeignKey
user = models.ForeignKey(User, on_delete=models.CASCADE, related_name='tickets')
# For multiple users, use ManyToManyField
contributors = models.ManyToManyField(User, related_name='tickets')
name = models.CharField(max_length=50)
created_at = models.DateField()
def __str__(self):
return self.name
You can then get all tickets for a user u with:
u.tickets.all()
Figured it out myself, using prefetch_related. I was having trouble understanding how prefetch_related works. For those that are confused too, from my understanding it works like this:
Ticket.objects.all().prefetch_related('contributors')
This returns a queryset, something along the lines of this
<QuerySet [<Ticket: Testing ticket one>, <Ticket: Testing ticket two>, <Ticket: Testing ticket three'>, <Ticket: Testing ticket four>]>
When you then access the elements in the queryset, you can then call .contributors on the object, like so:
# Get the queryset
tickets_with_contribs = Ticket.objects.all().prefetch_related('contributors')
# Print the contributors of the first ticket returned
print(tickets_with_contribs[0].contributors)
# Print the contributors of each ticket
for ticket in tickets_with_contribs:
print(ticket.contributors)
Looking back at it this should have been pretty self explanatory, but oh well.

Store List(s) in a database

My Users has phone contact LIST(s) - [3121234567,2121234567,6601234567]
Now, I want each user to be able to store as many LIST as possible. Each List must have a name(or description) attached to them under each USER account. Note: the number of LIST is dependent on Users needs. Example:
Students
[3121234567,2121234567,6601234567]
Club Member
[8101234567,8151234567,8171234567]
Now, how do I store it in a database.
Django User Model
class CustomUser(AbstractBaseUser):
username = models.CharField(max_length=254, unique=True)
first_name = models.CharField(max_length=24)
last_name = models.CharField(max_length=30)
phone = models.CharField(max_length=10)
email = models.EmailField(max_length=128)
street = models.CharField(max_length=128)
city = models.CharField(max_length=128)
state = models.CharField(max_length=2, choices=STATE_CHOICES, default=STATE)
zip_code = models.IntegerField(max_length=5, null=True, blank=True
USERNAME_FIELD = 'email'
REQUIRED_FIELD = ['username', 'first_name', 'last_name', 'phone', 'street', 'city', 'state']
objects = CustomUserManager()
Edit(Added):
I am not looking to create Student or ClubMember models. This name is use to identify the python phone contact list. PhoneAddress one can be labelled(named) as Student for one user but called "Conference Attendant" for another. Each user have different # of Lists.
PhoneAdress PhoneAdress2 PhoneAdress3
[3121234567,2121234567,6601234567] [4121234567,3121234567,6601234567] [7121234567,8121234567,9601234567]
Lemme guess, you're coming from a NoSQL background where the database is a document in a JSON form?
If so, I am sorry, in a Relational Database, used by Django in the likes of PostgreSQL or MySQL, they call something Foreign Keys, and that is your way of storing multiple "Lists" related to a particular field.
If you want many users to store as many lists as possible, you're looking at something like this, roughly speaking:
class myUserModel(models.Model):
# your arbitrary fields here
# then you do something like this:
class Student(models.Model):
user = models.ForeignKey(User)
class clubMember(models.Model):
user = models.ForeignKey(User)
With the above setup, you can add as many Student objects associated to the myUserModel class, so as the clubMember
However, if you wish to use PostgreSQL specifically, as your backend (perhaps as perpetual storage backend), you might find some sense in using Django's support for the ArrayField
And ooh, you might need to extend the Django User Model to add any extra fields easily, unless you're willing to go down the road of a custom User Model.
More info:
Django ForeignKey
This SO answer on 'OneToManyFields', similar to adding multiple items to a single field.
I hope the above helps
Create some models:
class Club(models.Model):
name = models.CharField(max_length=256,blank=True,null=True)
date_open = models.DateField()
class Institution(models.Model):
name = models.CharField(max_length=256,blank=True,null=True)
address = models.CharField(max_length=256,blank=True,null=True)
type = models.CharField(max_length=256,blank=True,null=True) #university, college
Rather than using
class CustomUser(AbstractBaseUser):
username = models.CharField(max_length=254, unique=True)
first_name = models.CharField(max_length=24)
last_name = models.CharField(max_length=30)
use composition in the form of OneOnOneField
class UserProfile(models.Model):
user = models.OneOnOneField(User,blank=True,null=True)
club_member = models.ManyToManyField(Club,blank=True, null=True)
institutions = models.ManyToManyField(Institution,blank=True, null=True) # student in
Once you have this, you will be able to get and add as many institutions and clubs to the lists:
user = User.objects.get(id=user_id)
club = Club.objects.get(id=club_id)
institution = Institution.objects.get(id=institution_id)
user.profile.clubs.add(club)
user.profile.institutions.add(institution)
So to verify if the user is a member of a club
club = user.proile.clubs.get(id=club_id)
and to verify the user is a student in an institution use
institution = user.profile.institutions.get(id=institution_id)