REST Framework writing custom fields validation - python

Is it possible to add a custom fields validation on the serializers that will only show a specific field in the views depending on the condition stated. e.g from the model below there is a visit class that accounts for patient visits. Depending on the following statuses below,one will only view certain specific fields e.g suppose a patient arrives, one should only see the visit_start_date, the status_time will be recorded etc.
STATUSES=('
('ARRIVED','Arrived'),
('CHECKED_IN','Checked In'),
('IN_ROOM','In Room'),
('CANCELLED','Cancelled'),
('COMPLETE','Complete')
)
class Visit(models.Model):
patient = models.ForeignKey(
settings.AUTH_USER_MODEL,
related_name='rel_visits')
discharge_notes = models.TextField(
default=None,
blank=True,
null=True)
discharged = models.NullBooleanField(default=False, null=True, blank=True)
admitted = models.NullBooleanField(default=False, null=True, blank=True)
current = models.NullBooleanField(default=False, null=True, blank=True)
status_time = models.DateTimeField(auto_now_add=True)
status = models.ChoiceField(max_length=20,choices=STATUSES)
visit_start_time = models.DateTimeField(blank=True)
visit_duration = models.IntegerField(blank=True)
session_start_time = models.DateTimeField(blank=True)
session_end_time = models.DateTimeField(blank=True)
check_in = models.BooleanField(default=False)
check_out = models.BooleanField(default=False)
Here is how the complete form looks like :

In your visit model patient is an auth_user_model(Django user) so you can add permission in patient(auth_user_model),
1)create custom permission of auth user then
2)create a group called patient, add custom permission on this group.
then write a query in views.py according to permission.

Related

Integrity Error NOT NULL constraint failed even though I have set blank=True, null=True in my model

Im getting a NOT NULL constraint error in my code when trying to save my model form, even though the fields I have left empty are optional (have set blank=True, null=True) in models.py
Im very confused, what am I doing wrong?
The error is popping up when I leave the first optional field blank (description). Filling any of them manually before work.save() pushes the issue to the next field, and passes when all fields are filled.
EDIT: this also happens when trying to create a work instance from the admin dashboard.
models.py
class Work(models.Model):
## core fields
creator = models.ForeignKey(User, on_delete=models.CASCADE, blank=True, null=True,
default=None)
created = models.DateTimeField()
modified = models.DateTimeField()
work_slug = models.SlugField(max_length=50) # slug -> TBD: find way to assign default value to slug = archival number.
archive = models.ForeignKey(Archive, on_delete=models.CASCADE)
# superfolder -> replaces category, series etc with dynamic hierarchical database
folder = models.ForeignKey(Folder, on_delete=models.CASCADE)
# basic metadata fields
name = models.CharField(max_length=50)
year = models.CharField(max_length=50)
medium = models.CharField(max_length=50)
description = models.CharField(max_length=1200, blank=True, null=True)
# optional metadata
authors = models.CharField(max_length=50, blank=True, null=True)
classification = models.CharField(max_length=50, blank=True, null=True)
location = models.CharField(max_length=50, blank=True, null=True)
link = models.URLField(max_length=50, blank=True, null=True)
record_creator = models.CharField(max_length=50, blank=True, null=True) # revisit ->
# custom descriptors
cd1_name = models.CharField(max_length=50, blank=True, null=True)
cd1_value = models.CharField(max_length=50, blank=True, null=True)
cd2_name = models.CharField(max_length=50, blank=True, null=True)
cd2_value = models.CharField(max_length=50, blank=True, null=True)
cd3_name = models.CharField(max_length=50, blank=True, null=True)
cd3_value = models.CharField(max_length=50, blank=True, null=True)
cd4_name = models.CharField(max_length=50, blank=True, null=True)
cd4_value = models.CharField(max_length=50, blank=True, null=True)
cd5_name = models.CharField(max_length=50, blank=True, null=True)
cd5_value = models.CharField(max_length=50, blank=True, null=True)
cd6_name = models.CharField(max_length=50, blank=True, null=True)
cd6_value = models.CharField(max_length=50, blank=True, null=True)
cd7_name = models.CharField(max_length=50, blank=True, null=True)
cd7_value = models.CharField(max_length=50, blank=True, null=True)
# Standardized Metadata
# Methods
def __str__(self):
return 'Work: {}'.format(self.name)
def save(self, *args, **kwargs):
''' On save, update timestamps '''
user = get_current_user()
if not self.id: # if the model is being created for the first time:
self.creator = user # assign the currently logged in user as the creator
self.created = timezone.now() # set the 'created' field to the current date and time
# self.slug = **archival id of work (automatically determined)**
self.modified = timezone.now() # set the modified field to the current date and time. This is reassigned everytime the model is updated.
return super(Work, self).save(*args, **kwargs)
forms.py
class WorkForm(ModelForm):
class Meta:
model = Work
fields = ['name', 'year', 'medium', 'description', 'authors', 'classification', 'location', 'link', 'record_creator', 'cd1_name', 'cd1_value', 'cd2_name', 'cd2_value', 'cd3_name', 'cd3_value', 'cd4_name', 'cd4_value', 'cd5_name', 'cd5_value', 'cd6_name', 'cd6_value', 'cd7_name', 'cd7_value']
views.py
def add_work(request, folder_pk):
'''
Add a work to the filesystem.
folder_pk: the primary key of the parent folder
Checks if the user is logged in and if the user is the creator of the folder. If so, the user is allowed to add a work to the folder. Otherwise, the user is redirected to the login page.
'''
# add work to the database
parent = Folder.objects.get(pk=folder_pk)
mediaFormSet = modelformset_factory(MediaFile, fields=('name', 'alt_text', 'caption', 'media'), extra=1)
if request.method == "POST" and parent.archive.creator == get_current_user():
# if the form has been submitted
# Serve the form -> request.POST
form = WorkForm(request.POST)
# mediaFormSet = mediaFormSet(request.POST)
if form.is_valid(): # if the all the fields on the form pass validation
# Generate archival ID for work
# archival ID is random, unique 6 digit number that identifies the work
archival_id = get_archival_id()
# create a new work with the parameters retrieved from the form. currently logged in user is automatically linked
work = form.save(commit=False)
work.work_slug = archival_id
work.folder=parent
work.archive=parent.archive
work.save()
# Redirect to dashboard page
return redirect('add_media_to_work', work_pk=work.pk)
else:
# If the form is not submitted (page is loaded for example)
# -> Serve the empty form
form = WorkForm()
return render(request, "archival/add_edit_work.html", {"workForm": form})
i was facing the same problem as you, i made a sign up form, and it was giving me the same error because the .save() method was getting executed before i fill in the fields, there was no data to save, because of that: the fields type was None. so i just implemented an if else statement to make sure that the .save() method won't be executed if the type of the field isnNone,
here is a snippet:
if field == None:
pass
else:
form.save()

message_set of Django model

i'm new with Django and as I read the code, I don't understand the message_set attribute of Django model(called Room):
def room(request, pk):
room = Room.objects.get(id=pk)
**room_messages = room.message_set.all()**
participants = room.participants.all()
portion of Models:
class Room(models.Model):
host = models.ForeignKey(User, on_delete=models.SET_NULL, null=True)
topic = models.ForeignKey(Topic, on_delete=models.SET_NULL, null=True)
name = models.CharField(max_length=200)
description = models.TextField(null=True, blank=True)
participants = models.ManyToManyField(
User, related_name='participants', blank=True)
updated = models.DateTimeField(auto_now=True)
created = models.DateTimeField(auto_now_add=True)
class Message(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE)
room = models.ForeignKey(Room, on_delete=models.CASCADE)
body = models.TextField()
updated = models.DateTimeField(auto_now=True)
created = models.DateTimeField(auto_now_add=True)
If you define a ForeignKey from Message to Room, Django will add a relation in reverse to the from the Room model to its related Messages. By default this relation is named modelname_set with modelname the name of the origin of the model. You can specify another name by overriding the related_name=… parameter [Django-doc].
If you thus access the relation in reverse, you get all Message objects with room as there room, an equivalent query to room.message_set.all() is thus Message.objects.filter(room=room).

Django - limit choices to foreign key

I have the following model in Django
class Transfer(models.Model):
user = models.ForeignKey(User, on_delete=models.PROTECT, limit_choices_to={'is_accepted':True})
amount = models.IntegerField(default=0)
transfer_date = models.DateTimeField(default=timezone.now)
company = models.ForeignKey(Company, on_delete=models.PROTECT)
I would like to filter the users based on is_accepted field. The problem is, that this field is declared in a model called Employee, which is in onetoone relationship with user.
Is there any possibility to reach Employee fields and filter them in this manner?
You can normally define a filter like:
class Transfer(models.Model):
user = models.ForeignKey(
User,
on_delete=models.PROTECT,
limit_choices_to={'employee__is_accepted': True}
)
amount = models.IntegerField(default=0)
transfer_date = models.DateTimeField(default=timezone.now)
company = models.ForeignKey(Company, on_delete=models.PROTECT)

Django Field Error cannot resolve keyword 'is_staff

Cannot resolve keyword 'is_staff' into field. Choices are: dob, experience, id,user, user_id
I get the above error when adding trainer as a Foreign Key to the Subscription model and then accessing any record for Subscription model from admin panel
class Subscription(models.Model):
client = models.OneToOneField(ClientProfile, on_delete=models.CASCADE)
trainer = models.ForeignKey(TrainerProfile, null=True, blank=True,
on_delete=models.SET_NULL, limit_choices_to={'is_staff': True})
plan = models.ForeignKey(Plan, on_delete=models.CASCADE)
transaction = models.OneToOneField(PaymentHistory, on_delete=models.CASCADE)
start_date = models.DateTimeField()
end_date = models.DateTimeField()
class TrainerProfile(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
dob = models.DateField(null=True)
experience = models.PositiveIntegerField(default=0)
You're trying to access an attribute is_staff, which does not exist on the TrainerProfile model. is_staff is an attribute of User, which you reference in your TrainerProfile model's user field.
In order to access this property, you need to "traverse" the relationship from Subscription -> TrainerProfile -> User. Django allows you to do this by using double-underscore notation, like this: some_fk_field__fk_field_attribute.
In your example, you need to change your limit_choices_to option on trainer to traverse the relationship to the user, like so:
class Subscription(models.Model):
client = models.OneToOneField(ClientProfile, on_delete=models.CASCADE)
trainer = models.ForeignKey(TrainerProfile, null=True, blank=True,
on_delete=models.SET_NULL, limit_choices_to={'user__is_staff': True})
plan = models.ForeignKey(Plan, on_delete=models.CASCADE)
transaction = models.OneToOneField(PaymentHistory, on_delete=models.CASCADE)
start_date = models.DateTimeField()
end_date = models.DateTimeField()
class TrainerProfile(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
dob = models.DateField(null=True)
experience = models.PositiveIntegerField(default=0)
You are referencing the nested relationship in wrong way
class Subscription(models.Model):
# other fields
trainer = models.ForeignKey(TrainerProfile, null=True, blank=True,
on_delete=models.SET_NULL,
limit_choices_to={'user__is_staff': True})
That is, it should be user__is_staff instead of is_staff

Checking if any object in a queryset is in a ManyToMany relation

What I'd like to be able to do is similar to this pseudo-code - I'm just completely unaware of how to do this in python:
user_groups = request.user.participant_groups.all()
if group in user_groups not in self.object.settings.groups.all():
Basically, I'd like to check if any of the objects in user_groups are in self.object.settings.groups.all(). Is there a simple way to do this?
Models:
class Group(models.Model):
participants = models.ManyToManyField('auth.User', null=True, blank=True, related_name='participant_groups')
title = models.CharField(max_length=180)
date = models.DateTimeField(null=True, blank=True, editable=False)
modified = models.DateTimeField(null=True, blank=True, editable=False)
class Settings(models.Model):
user = models.ForeignKey('auth.User', related_name='settings_objects')
groups = models.ManyToManyField('groups.Group', null=True, blank=True)
participants = models.ManyToManyField('auth.User', null=True, blank=True, related_name='accessible_objects')
private = models.BooleanField(default=True)
What I'm trying to do is check if any of a user's participant_groups (reverse relation to user on group model) are in a settings objects groups manytomany relation.
Try this -
common_groups = user.participant_groups.annotate(
num_settings=Count('settings_objects')
).filter(num_settings__gt=0)
# You can get a count like this
count_of_above = common_groups.count()
I'm assuming self.object.settings is an instance of Settings for the current user. You should make it clear.

Categories

Resources