Find entities for specific user through multiple tables in Django Admin - python

I searched through stackoverflow about this particular scenario, but could not find a concrete answer, so i'm posting this.
So my problem is that i need to display specific records to a specific user in Django Admin. I'm aware that i can get the concrete logged in user through the get_queryset method extracting it from the request object. But the issue is i need to look through 6 tables to get to the information about the user of the recommendations so i could know which recommendation to display to him.
For example, if the records i need to display come from a Recommendation table, it has a reference to TableA, which has a reference to TableB .... which has a reference to TableF which has a reference to the User.
I'm aware i could do this by executing a plain SQL query with multiple joins, but my guess is that there must be a pythonic or Django sophisticated solution to this. But i may be wrong.
The model is unfortunately not in my control, nor i can change it, so i'm left to work with the state of the model that there is.
Thanks in advance.
EDIT: Unfortunately, i can't share details of it, but i can share the general look of it. So i think this should be enough to have a picture of my problem.
from django.db import models
from django.contrib.auth.models import User
class TableF(models.Model):
information = models.CharField(max_length=256, null=False)
user = models.ForeignKey(User, on_delete=models.CASCADE)
class TableE(models.Model):
information = models.CharField(max_length=256, null=False)
tableF = models.ForeignKey(TableF, on_delete=models.CASCADE)
class TableC(models.Model):
information = models.CharField(max_length=256, null=False)
tableEs = models.ManyToManyField(TableE, through='TableD')
class TableD(models.Model):
information = models.CharField(max_length=256, null=False)
tableC = models.ForeignKey(TableC, on_delete=models.CASCADE)
tableE = models.ForeignKey(TableE, on_delete=models.CASCADE)
class TableA(models.Model):
information = models.CharField(max_length=256, null=False)
tableCs = models.ManyToManyField(TableC, through='TableB')
class TableB(models.Model):
information = models.CharField(max_length=256, null=False)
tableA = models.ForeignKey(TableA, on_delete=models.CASCADE)
tableC = models.ForeignKey(TableC, on_delete=models.CASCADE)
class Recommendation(models.Model):
information = models.CharField(max_length=256, null=False)
tableA = models.ForeignKey(TableA, on_delete=models.CASCADE)

you can use a middleware to include de user to the thread locals and catch this user from get_queryset in the model manager.
from threading import local
_thread_locals = local()
def get_current_user():
return getattr(_thread_locals, 'user', None)
class ThreadLocals(object):
#staticmethod
def process_request(request):
_thread_locals.user = getattr(request, 'user', None)
in the settings
MIDDLEWARE = [
...
'path.to.file.ThreadLocals',
]
from your.path import get_current_user
class TableFManager(models.Manager):
def get_queryset(self):
return super().get_queryset().filter(creator=get_current_user())
class TableF(models.Model):
information = models.CharField(max_length=256, null=False)
user = models.ForeignKey(User, on_delete=models.CASCADE)
objects = TableFManager()

another less invasive option could be to rewrite the get_queryset in the admin class. there you already have the user in the request

def get_rec_user(user):
tes = TableE.objects.filter(tableF__in=TableF.objects.filter(user=user))
aes = TableB.objects.filter(tableE__in=tes).values_list('tableA_id', flat=True)
return Recommendation.objects.filter(
tableA__in=TableA.objects.filter(id__in=aes)
)

Related

Django: Is there a way to make sure that only a unique FK related object can be added/related to the PK object?

Say there is a poll app and I want a user to vote only once for a poll question.
Assume models.py to be as follows,
class PollUser(models.Model):
username = models.CharField(max_length=120, unique=True)
class PollQuestion(models.Model):
question = models.CharField(max_length=250)
issuing_user = models.ForeignKey(PollUser, on_delete=models.CASCADE)
class PollChoice(models.Model):
text = models.CharField(max_length=250)
votes = models.PositiveIntegerField(default=0)
Is there a way to implement this functionality, without making this check in the views?

Is there any way to select a value dynamically for a model's related field in runtime?

I want to achieve a functionality, where I need to select a django model (e.g from a drop down list), and after selecting one, all the objects of that model shows up.
class Thread(models.Model):
sender = models.(???) # This need to be a field that can store a different model on a run time.
receiver = models.(???) # same here.
Is there any way that I can dynamically first select the model and then pick an object of that list. I have seen this functionality in odoo. But is there anything in Django?
Use Inheritance for in your Model and map your foreign key to User, and then pass either a teacher of student object.
You can use the many-to-many filed with multiple available choices of "Student" and "Teacher" from another Model.
class UserRole(models.Model):
STUDENT = 'STUDENT'
TEACHER = 'TEACHER'
ROLE_CHOICES = (
(STUDENT, 'student'),
(TEACHER, 'teacher'),
)
role_name = models.CharField(max_length=255, choices=ROLE_CHOICES)
def __str__(self):
return "{}".format(self.role_name)
class User(AbstractUser):
username = models.CharField(max_length=50, unique=True)
email = models.EmailField(_('email address'))
role = models.ManyToManyField(UserRole)
Class Thread(models.Model):
sender = models.OneToOneField(User, on_delete=models.CASCADE)
receiver = models.OneToOneField(User, on_delete=models.CASCADE)
This way you can only put available roles in sender and receiver fields of Thread.
The solution was possible with ajax too, but there also is another way in django which I was searching for.
class Test(models.Model):
content_type = models.ForeignKey(ContentType, on_delete=models.CASCADE)
object_id = models.PositiveIntegerField()
content_object = GenericForeignKey('content_type', 'object_id')
Have a good one.

Django - Membership matching query does not exist

I'm trying to create a subscription style service on Django (using Django3)
Basically, I had it working..ish, but my stripe customer keys weren't being added in, so I fiddled around to get that sorted.
Now I'm getting this error - Membership matching query does not exist. this is whenever I'm trying to create an account, login or login to the admin of my Django project.
I can't really figure out what the issue is, as I've reverted the changes I made to get the cust-Id (any tips here would be appreciated! lol) working again, but it's still throwing it up at me.
Here's my code in my models, I can't even pinpoint where this issue is coming from if I'm honest. (I got this mostly from the JustDjango tutorial btw!)
The debug thing is saying it's to do with the free_membership variable in the post_save_usermembership_create method though.
So far I just have models.py and admin.py done to get this up & running -
from django.conf import settings
from django.db import models
from django.db.models.signals import post_save
from datetime import datetime
import stripe
stripe.api_key = settings.STRIPE_SECRET_KEY
MEMBERSHIP_CHOICES = (
('Regular', 'reg'),
('Premium', 'premium'),
('Free', 'free')
)
class Membership(models.Model):
slug = models.SlugField()
membership_type = models.CharField(
choices=MEMBERSHIP_CHOICES,
default='Free',
max_length=30)
price = models.IntegerField(default=15)
stripe_plan_id = models.CharField(max_length=40)
def __str__(self):
return self.membership_type
class UserMembership(models.Model):
user = models.OneToOneField(
settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
stripe_customer_id = models.CharField(max_length=40)
membership = models.ForeignKey(
Membership, on_delete=models.SET_NULL, null=True)
def __str__(self):
return self.user.username
def post_save_usermembership_create(sender, instance, created, *args, **kwargs):
user_membership, created = UserMembership.objects.get_or_create(
user=instance)
if user_membership.stripe_customer_id is None or user_membership.stripe_customer_id == '':
new_customer_id = stripe.Customer.create(email=instance.email)
free_membership = Membership.objects.get(membership_type='Free')
user_membership.stripe_customer_id = new_customer_id['id']
user_membership.membership = free_membership
user_membership.save()
post_save.connect(post_save_usermembership_create,
sender=settings.AUTH_USER_MODEL)
class Subscription(models.Model):
user_membership = models.ForeignKey(
UserMembership, on_delete=models.CASCADE)
stripe_subscription_id = models.CharField(max_length=40)
active = models.BooleanField(default=True)
def __str__(self):
return self.user_membership.user.username

how to use temporary database for every user in django

so i am learning Django and making a todo application but i am stuck with a problem. I am storing every task on sqlite3 database(default by django) with models but when anyone store any task it is also visible to other person also how can i fix that?
if you have any alternative solution for that you can also tell that like how to use cookies or anything
models.py:-
from django.db import models
# Create your models here.
class Task(models.Model):
title = models.CharField(max_length=200)
completed = models.BooleanField(default=False, blank=True, null=True)
def __str__(self):
return self.title
Store who the task belongs to,
class Task(models.Model):
title = models.CharField(max_length=200)
completed = models.BooleanField(default=False, blank=True, null=True)
user = models.ForeignKey(
settings.AUTH_USER_MODEL,
on_delete=models.CASCADE,
)
You will have to store the user when creating/updating the Task
For instance,
task = Task.objects.create(title=title, user=user)
Now when you need to show the tasks, show only relavant tasks
tasks = Task.objects.filter(user=request.user)

How to allow only one User to see "UpdateView"?

I have a Users and Jobs. If some User creates a Job, then and only then he/she can edit some information of this Job.
So he visits the url .../job/update/<id>. If the Job is created by him (the User is a ForeignKey in Job, then he can modify data. Otherwise he gets 404 error.
In view function, I would probably get current Users id and compare this id to Jobs ForeignKey.
But there are many patterns and shortcuts in class views so I'm curious how to do that this way.
class EditOrderView(UpdateView):
model = Job
fields = ['language_from','language_to','level','short_description','notes',
'text_to_translate','file']
template_name = 'auth/jobs/update-order.html'
class Job(models.Model):
customer = models.ForeignKey(User, related_name='orders', help_text=u"Zákazník")
translator = models.ForeignKey(User, related_name='jobs', null=True, blank=True, help_text=u"Prekladateľ")
price = models.FloatField(null=True, blank=True, help_text=u"Cena")
language_from = models.ForeignKey(Language, related_name='jobs_from', null=True)
language_to = models.ForeignKey(Language, related_name='jobs_to', null=True)
...
It looks like you can override .get_object() method and include your own logic:
from django.shortcuts import get_object_or_404
class EditOrderView(UpdateView):
model = Job
...
def get_object(self, queryset=None):
return get_object_or_404(self.model, pk=self.kwargs["pk"], customer=self.request.user)

Categories