Django getting database fields with one query - django

I have a few models in django (User(standard), Member(extended user), Calculations, Subscription, Type) as follows :
class Member(models.Model):
user = models.ForeignKey(to=User)
..........
class Calculations(models.Model):
user = models.ForeignKey(to=User)
.....
class Type(models.Model):
limit = models.IntegerField()
name = models.CharField(max_length=50)
default = models.BooleanField()
class Subscription(models.Model):
started = models.DateField()
type = models.ForeignKey(Type)
member = models.OneToOneField(Member)
Thus,
Calculations is connected to User with ForeignKey
Member is also connected to user with ForeignKey
Subscriptions is connected to Member and with Type with ForeignKey
In my view I want to query the database and to access information from all those models.
Thus I want all members except the currently logged in, and I want to get the number of the calculations and the type of the subscription.
I'm trying to do it with one query.
I tried something like :
#login_required
def members(request):
// That's how I get all information about user and members, but I also need the calculation and subscription
members_list = Member.objects.select_related('user').all().exclude(user=request.user)
context = {'members': members_list}
return render(request, 'master/members.html', context)
Any advice how can I do that?

Access all elements from related Models.
qv = Member.objects.exclude(user=request.user).values('user__subscription__started', 'user', 'user__calculations__user')

Related

Pulling data associated with user account in Django

I'm creating a model in Django with the following syntax. The model has a foreign key of registered users. However, I want to serialize this model that will return a Json file only associated with the logged in user. Can you give your recommendations? Or is there an alternative way to extract the information from the model using different approach?
class Education(models.Model):
user = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
school = models.CharField(max_length=50)
year = models.CharField(max_length=10)
Sample photo
For instance, it will only show the first field associated with the account
To filter objects related to a user, simply get hold of the user and apply filter based on the user.
user_education_queryset = Education.objects.filter(user=user)
if you are doing this in the view where user objects is available in request context, you could simply do user=request.user Note: the user has to be logged in, else this will return anonymouse user object which will fail to query the database.
Summary:
Get the user object and filter by the user field in education model using the user object obtained.
mike = User.objects.get(id=1) # or mike = User.objects.get(username='mike')
then
mike_education_query = Education.objects.filter(user=mike)
Because of the suggestions, I was able to query the results per user with this code:
class EducationViewSet(viewsets.ModelViewSet):
serializer_class = EducationSerializer
def get_queryset(self):
user = self.request.user
account = User.objects.get(id=user.id)
return Education.objects.filter(user=account)

Django - Update field values in extended user model after a request is performed

My project is a social networking site that can send requests to friends and make friends.
I have extended django's existing user model using oneToone field .
So far i've been able to do the above said thing but when ever a user accepts the request , Both the user who sent request and also the user accepted it must increment a value in their extended user model which stores the value of their friends count .
I'm facing difficulties trying to solve this .
I've also used signals but it doesn't work .
Here is my code:
models.py:
class Friends(models.Model):
"""Model for saving relationship of user and friends"""
request_id = models.ForeignKey(User,on_delete=models.CASCADE,related_name='current_user')
friend_id = models.ForeignKey(User,on_delete=models.CASCADE,related_name='user_friend')
created_on = models.DateTimeField(auto_now_add=True,auto_now=False)
class Meta:
verbose_name_plural = "Friends"
def __str__(self):
return str(self.friend_id)
class Profile(models.Model):
user = models.OneToOneField(User,related_name='profile',on_delete=models.CASCADE)
location = models.CharField(max_length=30,blank=True)
friends_count = models.PositiveIntegerField(default=0)
profile_pic = models.ImageField(upload_to='profile_pics/',blank=True,null=True)
def natural_key(self):
return (self.user.username,)
signals.py:
#receiver(post_save,sender=Friends)
def update_friends_count(sender,instance,created,**kwargs):
if created:
user_profile = Profile(user = instance.request_id)
user_profile.friends_count=F('friends_count')+1
user_profile.save()
Any help would be greatly appreciated!!!!! Thank you in advance!!!
You were initializing a new instance of Profile every time a friend is made. Instead you can use get_or_create to generate a profile or retrieve the one associated with that id. Next, you want to update both users so fetch the other update the counts and save.
#receiver(post_save,sender=Friends)
def update_friends_count(sender,instance,created,**kwargs):
if created:
user_profile, profile_created = Profile.objects.get_or_create(user = instance.request_id)
user_profile.friends_count=F('friends_count')+1
user_profile.save()
friend_profile, profile_created = Profile.objects.get_or_create(user = instance.friend_id)
friend_profile.friends_count=F('friends_count')+1
friend_profile.save()
With Q filter and update
Profile.objects.filter(
Q(user=instance.request_id) |
Q(user=instance.friend_id)
).update(
friends_count=F('friends_count')+1
)
This last query uses the django.db.models Q object to make an SQL OR statement to retrieve the two profile instances; that of the requested and the requester: the update call acts on the query and updates all instances in the list

Change / Filter dropdown list based based on ownership

This has got to be a common requirement but nothing I've found on SO or in Django docs that works for me. I'm really new to Django. My problem: I need to change the list of Areas that are presented in a form dropdown list according to the company that has Area ownership.
In my app:
Accounts (i.e Users) are members of Company. A Company manages an Area. Within the Area are a number of Routes. Routes can be added/updated/removed or assigned to different Areas by the Company.
So on my forms I want to make sure that only Areas that belong to a Company are displayed in the dropdown list. Essentially a user would select an Area, then CRUD routes associated with the Area.
class Company(models.Model):
name = models.CharField(...
account_number = models.CharField(...
...
class Account(models.Model):
name = models.OneToOneField(User...
company = models.ForeignKey(Company)
...
class Area(models.Model):
owner = models.ForeignKey(Company)
number = modes.PositiveIntegerField(...
class Route(models.Model):
owner = models.ForeignKey(Company)
area = models.ForeignKey(Area)
In forms.py
class RouteCreateForm(forms.ModelForm):
class Meta:
model= Route
fields= [
'area',
'route_number',
...
]
Adding:
self.fields['area'].queryset = Area.objects.filter(owner_id = 2)
provides the correct filtering but of course is not dynamic.
I've a lot of variations on :
def __init__(self, *args, **kwargs):
??how to pass in user to ultimately get to owner_id??
self.fields['area'].queryset = Area.objects.filter(owner_id = owner_id)
but can't get the middle right. I've also tried passing in 'user' but the only results in a TypeError at /account/setup/route/create
init() missing 1 required positional argument: 'user'
If you are using generic CreateView, you can modify your form per request by overriding get_form() on your view. That would look like this:
class RouteCreateView(generic.CreateView):
form_class = RouteCreateForm
def get_form(self):
form = super(RouteCreateView, self).get_form()
form.fields['area'].queryset = Area.objects.filter(owner=self.request.user)
return form

How do I represent two models on one page of form wizard?

I'm struggling to figure out how best to approach this.
I have two models that need to be represented on one page within a form wizard:
class BookingItem(models.Model):
assignedChildren = models.ManyToManyField('PlatformUserChildren', related_name = "childIDs", null=True)
quantity = models.PositiveSmallIntegerField(max_length=2,blank=True, null=True)
class PlatformUserChildren(models.Model):
child_firstname = models.CharField('Childs first name', max_length=30,blank=True, null=True)
The relationship between the models when presenting them on the page is NOT one-to-one. It is governed by quantity attribute and therefore there may be more BookingItems than PlatformUserChildren objects presented on the page (e.g. 4 BookingItems and 2 PlatformUserChildren objects). I loop through each object multiple times based on quantity.
I also need to bind to a queryset of the PlatformChildUser model based on the current logged in user.
My question: how do I best present these two models on the first page of my form wizard?
I have looked at inline_formsets, but they rely on foreign key relationships only.
I have tried a modelformset_factory for one model, and an additional identifier for the other model with some backend reconciliation later, but I'm stuck on how to get a queryset based on user in there
i have attempted the get_form_instance method but I'm not 100% sure if it supports querysets
finally, I have attempted overloading init however most of the examples are not based on form wizard, and supply external arguments.
My current (rather vanilla) code is below:
forms.py
class checkout_PlatformUserChildren(forms.ModelForm):
#activity_id = forms.IntegerField()
class Meta:
model = PlatformUserChildren
fields = ('child_age','child_firstname')
class Meta:
model = PlatformUserChildren
fields = ('child_age','child_firstname')
widgets = {
'child_firstname': SelectMultiple(attrs={'class': 'form-control',}),
'child_age' : TextInput(attrs={'class': 'form-control',}),
}
checkout_PlatformUserChildrenFormSet = modelformset_factory(
PlatformUserChildren,
form = checkout_PlatformUserChildren,
fields=('child_firstname', 'child_age'),
extra=1, max_num=5, can_delete=True)
views.py (done method not shown)
note: getUser is an external function that is currently working
checkoutForms = [
("assign_child", checkout_PlatformUserChildrenFormSet),
("address_information", addressInfo),
]
checkoutTemplates = {
"assign_child": "checkout/assign_child.html",
"address_information": "checkout/address_information.html",
}
class checkout(SessionWizardView):
def get_form_instance(self, step):
currentUser = getUser(self.request.user.id)
if step == 'assign_child':
self.instance = currentUser
return self.instance

django: how do I query based on GenericForeignKey's fields?

I'm new in using GenericForeignKey, and I couldn't make it to work in a query statement. The tables are roughly like the following:
class Ticket(models.Model):
issue_ct = models.ForeignKey(ContentType, related_name='issue_content_type')
issue_id = models.PositiveIntegerField(null=True, blank=True)
issue = generic.GenericForeignKey('issue_ct', 'issue_id')
class Issue(models.Model):
scan = models.ForeignKey(Scan)
A scan creates one issue, an issue generates some tickets, and I made Issue as a foreign key to Ticket table. Now I have a Scan object, and I want to query for all the tickets that related to this scan. I tried this first:
tickets = Tickets.objects.filter(issue__scan=scan_obj)
which doesn't work. Then I tried this:
issue = Issue.objects.get(scan=scan_obj)
content_type = ContentType.objects.get_for_model(Issue)
tickets = Tickets.objects.filter(content_type=content_type, issue=issue)
Still doesn't work. I need to know how to do these kind of queries in django? Thanks.
The Ticket.issue field you've defined will help you go from a Ticket instance to the Issue it's attached to, but it won't let you go backwards. You're close with your second example, but you need to use the issue_id field - you can't query on the GenericForeignKey (it just helps you retrieve the object when you have a Ticket instance). Try this:
from django.contrib.contenttypes.models import ContentType
issue = Issue.objects.get(scan=scan_obj)
tickets = Ticket.objects.filter(
issue_id=issue.id,
issue_ct=ContentType.objects.get_for_model(issue).id
)
Filtering across a GenericForeignKey can by creating a second model that shares the db_table with Ticket. First split up Ticket into an abstract model and concrete model.
class TicketBase(models.Model):
issue_ct = models.ForeignKey(ContentType, related_name='issue_content_type')
issue_id = models.PositiveIntegerField(null=True, blank=True)
class Meta:
abstract = True
class Ticket(TicketBase):
issue = generic.GenericForeignKey('issue_ct', 'issue_id')
Then create a model that also subclasses TicketBase. This subclass will have all the same fields except issue which is instead defined as a ForeignKey. Adding a custom Manager allows it to be filtered to just a single ContentType.
Since this subclass does not need to be synced or migrated it can be created dynamically using type().
def subclass_for_content_type(content_type):
class Meta:
db_table = Ticket._meta.db_table
class Manager(models.Manager):
""" constrain queries to a single content type """
def get_query_set(self):
return super(Manager, self).get_query_set().filter(issue_ct=content_type)
attrs = {
'related_to': models.ForeignKey(content_type.model_class()),
'__module__': 'myapp.models',
'Meta': Meta,
'objects': Manager()
}
return type("Ticket_%s" % content_type.name, (TicketBase,), attrs)