Show data from specific table in my view django - 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")

Related

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.

how to allow users to rate a product only once,

a Reviews model linked to Users and Product, nothing special,
users can vote as much as they want which is working,
but i'm stuck restricting the rating to just once
the view so far:
class ReviewCreateView(CreateView):
model = Review
form_class = ReviewForm
template_name = "form.html"
success_url = reverse_lazy('product_list')
def form_valid(self, form):
form.instance.user = self.request.user
return super().form_valid(form)
model
class Review(models.Model):
product = models.ForeignKey(Product, on_delete=models.PROTECT, null=True,related_name='reviews')
user = models.ForeignKey(User, on_delete=models.PROTECT, null=True,related_name='reviewers')
rating = models.IntegerField(null=True, blank=True, default=0)
comment = models.TextField(null=True, blank=True)
created = models.DateTimeField(auto_now_add=True)
updated = models.DateTimeField(auto_now=True)
the other models wouldn't help that muc ,Product just describe a product ,and default (regular) User model
the form is ModelForm based on the Review Model itself
any suggestion is welcome, even if i have to redo the model, thank you very much
set db constraint like so:
class Meta:
constraints = [
UniqueConstraint([fields=['user', 'product'], name='product_user_unique'),
]
the condition for your views would be like this:
def get(self, request, product):
if (Review.objects.filter(user=request.user)
.filter(product_id=product).exists():
# probably, you'd want to pass some
# conditional data to the template's context here
do_something()
That could be it. You restrict non-unique reviews by UI, but if it's somehow bypassed, user will get a server error. Of course, you could also apply validation in your CreateView (or analogous).
From architectural standpoint, you can always create a review_user table which will have the Product ID, and the ID of the users who voted on that product.. and upon second vote, you check if there's already a vote in the table.
Once you have this understanding, I am sure that you will find a way to incorporate the logic within your code.

How to filter post objects in django according to a particular user model field?

I'm currently creating a Social platform with Django. Right now, I'm developing homepage and want to show posts matching a userfield.
This is my Post model:
class Discussion(models.Model):
title = models.CharField(max_length=100)
author = models.ForeignKey(Account, on_delete=models.CASCADE)
post = models.TextField()
date = models.DateTimeField(default=timezone.now)
This is user account model:
class Account(AbstractBaseUser):
email = models.EmailField(verbose_name='email', max_length=60, unique=True)
username = models.CharField(max_length=30, unique=True)
classid = models.CharField(max_length=10)
This is view:
#login_required(login_url='login')
def home(request):
if request.method == 'GET':
discussions = Discussion.objects.get(post=Account.classid).order_by('-date')
form = PostDiscussionForm()
return render(request, 'app/home.html', {'discussions':discussions,'form':form})
else:
form = PostDiscussionForm(request.POST)
newdisscussion = form.save(commit=False)
newdisscussion.author = request.user
newdisscussion.save()
return redirect('home')
I want to show only logged users matching their classid (from user account model)
What I gather from here, is that you want to show which users are currently online/logged in? For that you'll need to store additional information when logging like, add a boolean field in the user model indicating whether or not the user has logged in and then filter based on that field.
class Account(AbstractBaseUser):
email = models.EmailField(verbose_name='email', max_length=60, unique=True)
username = models.CharField(max_length=30, unique=True)
logged_in = models.BooleanField(default=False)
classid = models.CharField(max_length=10)
Now add additional logic which sets this field to true when the user eventually logs in from your /login route.
Then Filter using:
$ return Account.objects.filter(logged_in==True)
This will return you all users that have currently logged in, if you're not using any serializers, than use value_list for getting the values only rather than the whole user objects.
$ return Account.objects.filter(logged_in==True).values_list('classid', flat=True)

Pulling and showing data from associate table in Django rest framework

I am trying to build an API using Django Rest Framework. Which i am not familiar with. I want to know how I can pull data using references and associated tables. I have three models Users, Company and Reviews. I am storing and Auth_token in user table and I want to be able to pull reviews by a certain user by putting the auth token in the address bar.
my models are
class User(models.Model):
user_name = models.CharField(max_length=45)
email = models.CharField(max_length=255)
auth_Token = models.CharField(max_length=100,default=uuid.uuid4)
created_at = models.DateTimeField(auto_now_add = True)
updated_at = models.DateTimeField(auto_now = True)
def __str__(self):
return self.user_name
class Company(models.Model):
company_name = models.CharField(max_length=255)
created_at = models.DateTimeField(auto_now_add = True)
updated_at = models.DateTimeField(auto_now = True)
def __str__(self):
return self.company_name
class Review(models.Model):
title = models.CharField(max_length=64)
rating = models.IntegerField(blank=False)
summary = models.TextField(max_length=10000)
ip = models.GenericIPAddressField()
company = models.ForeignKey(Company)
user = models.ForeignKey(User)
created_at = models.DateTimeField(auto_now_add = True)
updated_at = models.DateTimeField(auto_now = True)
def __str__(self):
return self.title
I am currently able to pull reviews using following apiview:
class ReviewView(APIView):
def get(self,request):
reviews = Review.objects.all()
serializer = ReviewSerializer(reviews, many=True)
return Response(serializer.data)
and the following serilaizer:
class ReviewSerializer(serializers.ModelSerializer):
class Meta:
model = Review
fields = ('title','company', 'rating', 'summary','user')
Please ignore the indentations. However this results in me getting back the company id and user id only. I basicaly want to know two things here.
First how do i pull data where auth token is passed as the url
url(r'^reviews/(?P<auth_Token>[\w-]+)/$', ReviewView.as_view()),
and second how do i display company name and user name instead of ids. Any help would be great. Thanks
How do I filter reviews based on the user's auth token?
I will suggest using a ReadOnlyModelViewSet. It will greatly reduce your view code and allow for easy filtering. Most of the mundane and tiring code of handling requests, validating and so on has already been written in these viewsets and therefore, you can just focus on your business logic rather than server side details.
Instead of using an auth_Token in the URL param itself (eg. reviews/XXX/), I have placed it as a query param (eg. reviews/?auth_Token=XXX). The reason behind this is because the URL param itself should return a specific review resource but you need to return a list of filtered reviews mapped to one user.
from rest_framework import viewsets
class ReviewView(viewsets.ReadOnlyModelViewSet):
serializer_class = ReviewSerializer
def get_queryset(self):
"""
This function is called whenever someone tries to retrieve reviews.
You do not need to worry about serialization or handling the response
as the viewset has set that up with your specified serializer_class
"""
auth_Token = self.query_params.get("auth_Token", None)
if auth_Token: # They provided an auth token so we need to filter.
reviews = Review.objects.filter(user__auth_Token=auth_Token)
else:
reviews = Review.objects.all()
return reviews
In your urls:
url(r'^reviews/$', ReviewView.as_view({"get":"list"})),
How do I show the company name and user name in retrieved reviews and not show their ids?
You need to use a SlugRelatedField (http://www.django-rest-framework.org/api-guide/relations/#slugrelatedfield). This field allows you to replace the typical id with another attribute found in the associated table. Please see the new ReviewSerializer below:
class ReviewSerializer(serializers.ModelSerializer):
company = serializers.SlugRelatedField(read_only=True, slug_field="company_name")
user = serializers.SlugRelatedField(read_only=True, slug_field="user_name")
class Meta:
model = Review
fields = ('title','company', 'rating', 'summary','user')

Django - Linking my models to profiles (UserProfile) model

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.