Please help me to limit model team choices based on the company. Right now I put test value "1" and it's working correctly (function _limit_function). But how to limit it dynamically based on the selected company?
class CustomCompany(models.Model):
name = models.CharField(max_length=30,
default="None",
unique=True
)
class CustomTeam(models.Model):
name = models.CharField(
max_length=30,
default="None"
)
company = models.ForeignKey(
CustomCompany,
on_delete=models.CASCADE,
)
class CustomUser(AbstractUser):
def _limit_function():
return {"company__id":1}
phone = models.CharField(
max_length=20,
blank=True
)
company = models.ForeignKey(
CustomCompany,
on_delete=models.CASCADE,
default=1
)
team = models.ForeignKey(
CustomTeam,
on_delete=models.CASCADE,
default=1,
limit_choices_to = _limit_function()
)
So, I need to limit variants of team values, based on the selected company. Please help to understand how to do this.
I think this is something you cannot do in models.py
The form is rendered in the client browser, which has no access to your models.py file during data entry, unless you click submit multiple times while entering the data.
The best way is, to write a little Java-Script function with a event listener (something like: teamfield.addEventListener("keydown...,on key code==113)) which monitors the form field and changes the choices object based on the selected company.
Related
i am trying to filter a data set based on a custom user model and having some difficulty with the data.
Basically, i have a registration form in which i am making user select the company they are associated with. So i have created a custom user model with a foreign key association to the company table.
Now, i am trying to query a second dataset so when user logs in, the application looks up the users company association and filters the data to only show results that are associated to the user's company choice.
any suggestion on how i can do this?
my user model is below:
class Account(AbstractBaseUser):
email = models.EmailField(verbose_name="email", max_length=60, unique=True)
username = models.CharField(max_length=30, unique=True)
is_admin = models.BooleanField(default=False)
is_active = models.BooleanField(default=True)
customer = models.ForeignKey(Customer, on_delete=models.SET_NULL, null=True, blank=True)
the table that i am trying to query on has model below:
class Order(models.Model):
customer = models.ForeignKey(Customer, on_delete= models.SET_NULL, null=True)
product = models.ForeignKey(Product, on_delete= models.SET_NULL, null=True)
date_created = models.DateTimeField(auto_now_add=True, null=True, blank=True)
requestorname = models.CharField(max_length=100, null=True)
requestorage = models.CharField(max_length=2,null=True, blank=True)
child_id = models.ForeignKey(ChildID, on_delete=models.SET_NULL, null=True, blank=True)
comments = models.CharField(max_length=100,null=True, blank=True)
requestdate_create = models.DateTimeField(auto_now_add=True)
note that both table has association to customer table using a foriegn key, so i want the user to only see the order associated to the company he/she belongs to.
appreciate any directions to help write the view. Thanks
So I was able to solve my own problem. I had to pass the request in as an argument. posting it here so folks with the same question can find answer. the view goes something like this.
def externalrequest(request):
args = request.user.customer_id
external = Order.objects.filter(customer=args)
context = {'external':external}
return render(request, 'accounts/external.html', context)
I am having a bit of trouble with the logic of how this should work so I am hoping it is possible.
I figured out 1 possible solution that is written as an answer below, I will accept it in a few days, but if someone comes up with a better solution, I will negate any answer I post.
Overall I am working on an Apartment Move-Out/Move-In Inspection Application in Django, and in both portions I have universal Locations that must be inspected for each report. I have allowed the InspectionLocations objects to be updated/submitted by clients, which is presenting an issue in how submitted reports should be stored in my Database.
What I want is to use the InspectionLocations table as a blueprint to build an Inspection Report for Move-Ins where the form-fields are generated based on the InspectionLocations objects' location, status, and information attributes/fields.
My issue is right at this point, how do I reference those values as a blueprint to build a report submission when the number of fields in the InspectionLocations can change?
from django.db import models
from apps.units.models import Unit
class Inspections(models.Model):
class Meta:
abstract = True
id = models.AutoField(primary_key=True)
inspection_date = models.DateField()
submitted_by = models.ForeignKey(
'users.CustomUser',
default=None,
null=True,
on_delete=models.SET_NULL,
db_column='submitted_by')
last_update = models.DateTimeField(auto_now=True)
date_added = models.DateTimeField(auto_now_add=True, editable=False)
class MoveInInspections(Inspections):
unit = models.ForeignKey(Unit, on_delete=models.CASCADE, db_column='unit_id')
# should have reference to all InspectionLocation items as reference for submission, how?
class MoveOutInspections(Inspections):
unit = models.ForeignKey(Unit, on_delete=models.CASCADE, db_column='unit_id')
date_notice_given = models.DateField(blank=True, null=True, default=None)
date_vacated = models.DateField(blank=True, null=True, default=None)
# should have reference to all InspectionLocation items as reference for submission, how?
class InspectionLocations(models.Model):
'''
Defualt Inspection Locations are created when a
client is created using code like this:
InspectionLocation.objects.get_or_create(location='Living Room')
InspectionLocation.objects.get_or_create(location='Dining Room')
InspectionLocation.objects.get_or_create(location='Kitchen')
InspectionLocation.objects.get_or_create(location='Bedroom')
InspectionLocation.objects.get_or_create(location='Bathroom')
InspectionLocation.objects.get_or_create(location='Other')
'''
id = models.AutoField(primary_key=True)
location = models.CharField(max_length=50)
status = models.BooleanField(default=None)
information = models.TextField(default=None, blank=True)
I have tried ManyToMany fields and FKs but I cannot seem to get the logic working as anytime an object references an InspectionLocations object it is universally changing data for every report, which is leading be to the idea that I somehow need to use it as a blueprint.
I didn't post this in my question because it was getting long, but my best option so far seems to be to use a Django JSONField (as I am using Postgres), like so:
from django.contrib.postgres.fields import JSONField
class MoveInInspections(Inspections):
unit = models.ForeignKey(Unit, on_delete=models.CASCADE, db_column='unit_id')
data = JSONField()
class MoveOutInspections(Inspections):
unit = models.ForeignKey(Unit, on_delete=models.CASCADE, db_column='unit_id')
date_notice_given = models.DateField(blank=True, null=True, default=None)
date_vacated = models.DateField(blank=True, null=True, default=None)
data = JSONField()
To where I store the values of the InspectionLocations object's in a Dictionary
I'm using a 'Task' Model to create operations/administrative tasks in my dashboard. Each task has an assignee, and a reviewer. The assignee completes the task by passing several checks, and the reviewer verifies their work, both of these require each user to edit a check, but neither user should be able to access or modify the other's result.
If the assignee views the Task (with checks inline), they should only be able to modify the "result" and "comment" elements of the check, where as the reviewer can only edit the "review_result" and "reviewer_comment" elements.
To validate this I need to use the fact that given a check, the current user editing the page is equal to check.task.assignee or check.task.reviewer.
I cannot find a simple way to do this, even using django-guardian, as this requires field-level permissions, rather than object level. I considered using modelForm validation, but cannot find a way to access the user from within the model with some hacks such as django-cuser.
Is there another architecture which would allow this? The only way forward that I can see is to use django-guardian combined with two checks, a check and a checkReview, and set object level permissions as the assignee and reviewer are chosen.
class Task(PolymorphicModel):
date_created = models.DateTimeField(auto_created=True)
date_accepted = models.DateTimeField(null=True)
date_reviewed = models.DateTimeField(null=True)
date_closed = models.DateTimeField(null=True)
state = FSMField(default="open")
assignee = models.ForeignKey(
settings.AUTH_USER_MODEL,
on_delete=models.CASCADE,
null=True,
related_name="assigned_tasks",
related_query_name="assigned_task",
)
reviewer = models.ForeignKey(
settings.AUTH_USER_MODEL,
on_delete=models.CASCADE,
null=True,
related_name="review_tasks",
related_query_name="review_task",
)
class Check(PolymorphicModel):
result = models.BooleanField(null=True)
comment = models.CharField(max_length=500, null=True, blank=True)
review_result = models.BooleanField(null=True)
reviewer_comment = models.CharField(max_length=500, null=True)
task = models.ForeignKey(Task, on_delete=models.CASCADE)
The correct method to achieve this is to override the get_readonly_fields method of InlineModelAdmin (In your Inline class).
def get_readonly_fields(self, request, obj=None):
if obj is None:
logger.error("An admin has created a check from the dashboard (this should not happen)!")
return []
user = request.user
fields = [field.name for field in self.opts.local_fields]
if user == obj.assignee:
fields.remove(['result', 'comment'])
elif user == obj.reviewer:
fields.remove(['review_result', 'reviewer_comment'])
return fields
I am using Django sites framework (Django 2.1) to split an app into multiple sites. All of my models except the User model are site-specific. Here is my Post model:
post.py
class Post(models.Model):
parent = models.ForeignKey(
'self',
on_delete=models.CASCADE,
related_name='children',
related_query_name='child',
blank=True,
null=True,
)
title = models.CharField(
max_length=255,
blank=True,
)
body_raw = models.TextField()
body_html = models.TextField(blank=True)
user = models.ForeignKey(
settings.AUTH_USER_MODEL,
on_delete=models.CASCADE,
)
site = models.ForeignKey(Site, on_delete=models.CASCADE)
on_site = CurrentSiteManager()
I have no problem separating posts out by site. When I want to get the posts, I call:
posts = Post.on_site.filter(...)
I have a separate model called UserProfile. It is a many-to-one profile where there is a unique profile created for each user-site combination (similar to profile implementation at SE). The profile has a reputation attribute that I want to access when I get any post. This reputation attribute should be different for each site (like how on SE you have different rep on each site you are a member of).
user_profile.py
class UserProfile(models.Model):
user = models.ForeignKey(get_user_model(), on_delete=models.CASCADE)
reputation = models.PositiveIntegerField(default=1)
site = models.ForeignKey(Site, on_delete=models.CASCADE)
on_site = CurrentSiteManager()
How do I access the user's username (on the User model) as well as the user's reputation (on the UserProfile model) when I get Posts from a query?
I'd like to do something like:
Post.on_site.filter(...)
.select_related('user__userprofile')
.filter_related(user__userprofile.site == get_current_site())
How do I filter a Many-To-One related model?
Better to make UserProfile -> User relationship to be OnetoOne,
because Django doesn't know which of many profiles to show
(but you also need to define related_name)
models.OneToOneField(get_user_model(), related_name='userprofile_rev')
Then you will be able to do this
qs = Post.on_site.filer().select_related('user', 'user__userprofile_rev')
for post in qs:
print(post.user.username, post.user.userprofile_rev.reputation)
If you don't want to change your DB structure you can do like this
(but you need to specify which profile to return)
qs = Post.on_site.filer().select_related('user').prefetch_related('user__userprofile_set')
for post in qs:
print(post.user.username, post.user.userprofile_set[0].reputation)
I am creating an application manages an interview process. In one interview, a candidate can be interviewed by one or more interviewer and an interviewer can interview one or more candidates. This is similar to a "round table" interview. The simplified version of the models are:
class Interviewer(models.Model):
interviewer_id = models.AutoField(primary_key=True)
first_name = models.CharField(max_length=200, blank=False, null=False)
last_name = models.CharField(max_length=200, blank=False, null=False)
candidates = models.ManyToManyField('Candidate', through='Interview')
class Candidate(models.Model):
candidate_id = models.PositiveIntegerField(
primary_key=True, blank=False, null=False)
first_name = models.CharField(max_length=200, blank=False, null=False)
last_name = models.CharField(max_length=200, blank=False, null=False
class Interview(models.Model):
interview_name = models.CharField(max_length=200, blank=True, null=True)
candidates = models.ForeignKey(
Candidate, on_delete=models.CASCADE, blank=True, null=True, related_name='candidates')
interviewers = models.ForeignKey(
Interviewer, on_delete=models.CASCADE, blank=True, null=True, related_name='interviewers')
In Django admin, for the Interview model, adding an entry for an interview would mean that I would have to create the entry for each candidate and interviewer. This process is cumbersome if there are a lot of candidates and/or interviewers. What I would like to do is to add all candidates and the interviewers for a particular interview.
I changed my model to use ModelMultipleChoiceField form instead of the default SelectField for Django uses for Foreign Keys.
class InterviewAdminForm(forms.ModelForm):
interviewers = forms.ModelMultipleChoiceField(
queryset=Interviewer.objects.all(),
widget=FilteredSelectMultiple(
verbose_name='interviewers', is_stacked=False
)
)
candidates = forms.ModelMultipleChoiceField(
queryset=Candidate.objects.all(),
widget=FilteredSelectMultiple(
verbose_name='candidates', is_stacked=False
)
)
class Meta:
model = Interview
fields = '__all__'
#admin.register(Interview)
class InterviewAdmin(admin.ModelAdmin):
form = InterviewAdminForm
This now displays a ModelMultipleChoiceField with a FilteredSelectMultiple widget which I can use to select the candidates and interviewers for a particular interview.
The problem is when I click on save it shows the following error
Cannot assign "<QuerySet [<Candidate: 11111111(John Doe)>, <Candidate: 22222222(Mary Moe)>]>": "Interview.candidates" must be a "Candidate" instance.
I reckon that it is getting all the candidates I chose from the ModelMultipleChoiceField as a query set and trying to add it to the database.
How can I instruct Django admin to add it as 2 separate records?
Edit: To make my question clearer
I am looking for a shorthand way to auto add multiple records as per my model definition.
Also, if my model definition isn't correct for what I would like to achieve, it would be great if you could provide me with a correct model definition.
Hopefully this isn't asking two questions in one.