Load data from model in view.py Django - python

I just started with Django and Python and I still don't understand it very well. Would it be possible to access all the information stored in Persons, showing also orderstext and archivename, I can't manage to do it :( my idea is to get all the information and save it as JSON, but I'm not getting the info from orderstext and archivename, it would be great if someone could show me the right way.
models.py
from django.db import models
class Order(models.Model):
order_id = models.PositiveIntegerField(blank=True, null=True)
orderstext = models.CharField(max_length=250, blank=True, null=True, )
order_start = models.DateTimeField(blank=True, null=True)
order_end = models.DateTimeField(blank=True, null=True)
#property
def default(self):
return self.orderstext
class Meta:
managed = False
db_table = 'order'
class Archives(models.Model):
archive_id = models.AutoField(primary_key=True, null=False)
archivename = models.CharField(max_length=50, unique=True, blank=True, null=True)
deleted = models.IntegerField(blank=True, null=True)
def __str__(self):
return self.archivename
#property
def default(self):
return self.archivename
class Meta:
managed = False
db_table = 'archives'
class Clients(models.Model):
name = models.CharField(max_length=20, verbose_name="Name")
lastname = models.CharField(max_length=50, blank=True, null=True, verbose_name="Lastname")
archives = models.ForeignKey('Archives', db_column='archive_id', on_delete=models.CASCADE, null=True, verbose_name="Archives")
order = models.ForeignKey('Order', db_column='order_id', on_delete=models.CASCADE, null=True, verbose_name="Order")
coments = models.CharField(max_length=250, blank=True, null=True, verbose_name="Coments")
class Meta:
managed = False
db_table = 'clients'
views.py
from django.http import JsonResponse
from .models import Clients
def data_json:
info = list(Clients.objects.all().values())
response = {'clients': info}
return JsonResponse(response)
urls.py
from django.urls import path
from . import views
urlpatterns = [
path('clients-info/', views.data_json, name='data_json'),
]
JSON Response
{
"clients": {
"id": 4,
"name": "First",
"lastname": "Last Name",
"archive_id": 6,
"order_id": 3,
"coments": "No comments"
}
}

You can annotate..[Django-doc] the clients queryset with the orderstext and archivename along side F-expressions..[Django-doc] like this:
from django.db.models import F
Clients.objects.annotate(
archivename=F("archives__archivename"),
orderstext=F("order__orderstext"),
).values()
Although instead of using values I highly recommend using something like DRF serializers..[DRF-doc] to handle serialization of your data.

If I'm understanding correctly, you'd want to get a certain field data on the FK field on each client object, but what you're getting is the pk value of Order and Archive models on each Client objects.
{
"clients": {
"id": 4,
"name": "First",
"lastname": "Last Name",
"archive_id": 6, # foreign key pk field reference
"order_id": 3, # foreign key pk field reference
"coments": "No comments"
}
}
If I'm correct, then one approach you could use is to change the reference name to reference the fields orderstext and archivename respectively instead of order_id and archive_id.
So I wouldn't change anything else but just the two foreign key fields on the Client model. Updating the reference where db_column points:
class Clients(models.Model):
...
archives = models.ForeignKey('Archives', db_column='archivename', on_delete=models.CASCADE, null=True, verbose_name="Archives")
order = models.ForeignKey('Order', db_column='orderstext', on_delete=models.CASCADE, null=True, verbose_name="Order")
...
You can read more from the doc on db-column.

There're several answers in this 12-years old question. I believe more of one might solve your problem.
Below one example of solution:
from django.http import JsonResponse
from django.core.serializers import serialize
from .models import Clients
def data_json(request):
info = Clients.objects.all()
response = serialize('json', info)
return JsonResponse(response, safe=False)
I recommend you read the documentation about JSON request and response objects and serialization formats.

Related

Trouble combining CustomUser and Profile into single endpoint in django

I have a CustomUser model and two separate Models for profile two types of User. I'm trying to combine the attribute of CustomUser and one of the Profile into single endpoint from which the user can see/update/delete the user/profile. For instance there are 2 types of users, doctor & patient. so if the user is doc then the endpoint will return the attributes of CustomUser+DoctorProfile and same for the Patient CustomUser+PatientProfile. Below is the code. I will explain the issue in the code base with comments. I will enormously appreciate any suggestion. One thing to mention is that I split the models.py file into 3 different folder and imported all of them into __init__.py of models folder.
CustomUser Model:
class CustomUser(AbstractBaseUser, PermissionsMixin):
class Types(models.TextChoices):
DOCTOR = "DOCTOR", "Doctor"
PATIENT = "PATIENT", "Patient"
# what type of user
type = models.CharField(_("Type"), max_length=50, choices=Types.choices, null=True, blank=False)
avatar = models.ImageField(upload_to="avatars/", null=True, blank=True)
email = models.EmailField(max_length=255, unique=True)
name = models.CharField(max_length=255)
is_active = models.BooleanField(default=True)
is_staff = models.BooleanField(default=False)
objects = CustomBaseUserManager()
USERNAME_FIELD = 'email'
REQUIRED_FIELDS = ['name', 'type'] #email is required by default
def get_full_name(self):
return self.name
def __str__(self):
return self.email
DoctorProfile Model:
class DoctorProfile(models.Model):
class DoctorType(models.TextChoices):
"""Doctor will choose profession category from enum"""
PSYCHIATRIST = "PSYCHIATRIST", "Psychiatrist"
PSYCHOLOGIST = "PSYCHOLOGIST", "Psychologist"
DERMATOLOGIST = "DERMATOLOGIST", "Dermatologist"
SEXUAL_HEALTH = "SEXUAL HEALTH", "Sexual health"
GYNECOLOGIST = "GYNECOLOGIST", "Gynecologist"
INTERNAL_MEDICINE = "INTERNAL MEDICINE", "Internal medicine"
DEVELOPMENTAL_THERAPIST = "DEVELOPMENTAL THERAPIST", "Developmental therapist"
owner = models.OneToOneField(CustomUser, on_delete=models.CASCADE, related_name='doctor_profile')
doctor_type = models.CharField(
_("Profession Type"),
max_length=70,
choices=DoctorType.choices,
null=True,
blank=False)
title = models.IntegerField(_('Title'), default=1, choices=TITLES)
date_of_birth = models.DateField(null=True, blank=False)
gender = models.IntegerField(_('Gender'), default=1, choices=GENDERS)
registration_number = models.IntegerField(_('Registration Number'), null=True, blank=False)
city = models.CharField(_('City'), max_length=255, null=True, blank=True)
country = models.CharField(_('Country'), max_length=255, null=True, blank=True)
def __str__(self):
return f'profile-{self.id}-{self.title} {self.owner.get_full_name()}'
Serializer:
class DoctorProfileFields(serializers.ModelSerializer):
"""To get required attributes from DoctorProfile model"""
class Meta:
model = DoctorProfile
fields = ('doctor_type', 'title', 'date_of_birth', 'registration_number', 'gender', 'city', 'country', )
class DoctorProfileSerializer(serializers.ModelSerializer):
"""Above Serializer is used in a new attribute profile. So that I can combine the CustomUser and DoctorProfile."""
profile = DoctorProfileFields(source='*')
"""
if I use source in the above line the serializer returns the json in the
expected format while I use get method, otherwise it return error saying profile
is not an attribute of CustomUser. but for put method the json payload is getting
received in a wrong formation. attributes of nested Profile object is getting
combined in the same level of Custom user,
{"name": "jon", "avatar": null, "doctor_type": "anything"}
but it has to receive like this
{"name": "jon", "avatar": null, "profile": {"doctor_type": "anything}}
"""
class Meta:
model = User
fields = ('name', 'avatar', 'profile', )
#transaction.atomic
def update(self, instance, validated_data):
ModelClass = self.Meta.model
"""print("=======validated_data=========: ", validated_data). I found in this
line that the payload is wrong"""
profile = validated_data.pop('profile', {})
"""print("=======profile=========: ", profile) profile is not in validated data
that's why profile = {}"""
ModelClass.objects.filter(id=instance.id).update(**validated_data)
if profile:
DoctorProfile.objects.filter(owner=instance).update(**profile)
new_instance = ModelClass.objects.get(id = instance.id)
return new_instance
On the other hand if I don't use source the error is same for both get and put method.
View:
class DoctorProfileAPIView(generics.RetrieveUpdateDestroyAPIView):
"""To get the doctor profile fields and update and delete"""
serializer_class = DoctorProfileSerializer
queryset = User.objects.all()
def get_object(self):
return get_object_or_404(User, id=self.request.user.id, is_active=True)
After using source the get method returns in the expected format:
{
"name": "Maruf updated again",
"avatar": null,
"profile": {
"doctor_type": null,
"date_of_birth": null,
"registration_number": null,
"city": null,
"country": null
}
}
But the problem is with the Put method.
Another note: with using source and not overriding the update method in the serializer, only the CustomUser attributes is getting updated.
my objective is to get both CustomUser+Profile in the same endpoint.
And when updating, the CustomUser and the Profile will be updated in their own table but through the same endpoint.

Filter a queryset using a function in Django

I have this models.py file in my Django project
from django.db import models
from django.urls import reverse
from django.utils.timezone import now
class Campaign(models.Model):
class Meta:
db_table = 'campaign'
campaign_id = models.AutoField(primary_key=True)
name = models.CharField(max_length=255, default='')
topic = models.CharField(max_length=255, default='')
sender = models.CharField(max_length=255, default='')
start_date = models.DateTimeField(default=now)
is_active = models.BooleanField(default=False)
draft = models.BooleanField(default=True)
content = models.TextField(default='')
footer = models.CharField(max_length=255, default='')
unsubscribe_message = models.CharField(max_length=255, default='')
#property
def get_completion_percent(self):
return 70
And I'm trying to use the get_completion_percent function in my views.py as a filter right here
def finished_ads_view(request):
queryset = Campaign.objects.filter(get_completion_percent=100)
context = {
'object_list': queryset,
}
return render(request, 'campaigns_in_progress.html', context)
But the error I'm getting is this:
FieldError at /finished_campaigns/
Cannot resolve keyword 'get_completion_percent' into field. Choices are: campaign_id, content, draft, footer, is_active, name, sender, start_date, topic, unsubscribe_message
Can anyone help me make this work?
You can't filter a property.
If you need a percentage you can use .annotate() and filter the field.
Campaign.objects.annotate(percentage=70).filter(percentage=100)
If you need to make operation on fields of the same record, you can get the values with F() expression
I try to give a solution. It's not tested, so you should try it and let me know if it works. I am trying to understand which is your final goal and, as far as I understand, is to display something if it reaches the completion percentage of 100.
I would add another model like this:
class Percentage(models.Model):
campaign= models.ForeignKey(
Campaign, on_delete=models.CASCADE, null=True, blank=True)
percentage= models.IntegerField(default=0, blank=True, null=True) #I don't know if you need integer or float
With this foreign key, you can now do the calculations (in the view I suppose) to get the percentage. An example would be:
from django.db.models import Sum # remember this import
def finished_ads_view(request, pk):
campaign = Campaign.objects.filter(campaign_id=pk)
percentages = Percentage.objects.filter(campaign=campaign).aggregate(Sum(percentage))
if percentages == 100:
context = {
'object_list': percentages,
} #this context is idented inside the if statement
else:
percentages = 'Not completed' # or whatever you want display if the percentage is not 100
context = {
'object_list': percentages,
}
return render(request, 'campaigns_in_progress.html', context)
It's just a try, let me know if it works. I didn't test the code so there might be some mistakes but I'd do something like that

ValueError: Field 'id' expected a number but got string in Django Rest Framework

In DRF I am facing an issue, whenever I do a POST request on the endpoint, on the field "name" which is a text field I get an exception "Field 'id' expected a number but got 'TITLE'", but when I change the value of "name" to an integer the request is successful I don't understand it becauses name is TextField in model and why its mixing Id and Name field with each other. I have deleted the migration files from the Project and DB and re-run the Migrations, but still facing this issue.
Following is my code:
models.py
class Project(models.Model):
admin = models.ForeignKey(User, on_delete=models.CASCADE, related_name='project_crated_by')
name = models.TextField(max_length=225, blank=False, null=False)
project_members = models.ForeignKey(User, on_delete=models.CASCADE, verbose_name='members', null=True, blank=True)
created_on = models.DateField(default=timezone.now)
tags = ArrayField(models.CharField(max_length=225, default=''), blank=True)
def __str__(self):
return self.name
objects = models.Manager()
views.py
class ProjectView(viewsets.ViewSet):
def create(self, request):
project_name_exist = Project.verify_project_name(request.data['admin'], request.data['name'])
if project_name_exist:
return Response({'message': 'You already have a project with this name',
'status': status.HTTP_200_OK})
serialized_project = ProjectSerializer(data=request.data)
if serialized_project.is_valid():
serialized_project.save()
return Response({'message': 'Project Created Successfully', 'status': status.HTTP_201_CREATED})
else:
return Response({'error': serialized_project.errors, 'status': status.HTTP_400_BAD_REQUEST})
serializer.py
class ProjectSerializer(serializers.ModelSerializer):
class Meta:
model = Project
fields = '__all__'
A more generic and non-DIY solution is to use UniqueTogetherValidator on your serializer and let Django sort it out.
from rest_framework.validators import UniqueTogetherValidator
class ProjectSerializer(serializers.ModelSerializer):
class Meta:
model = Project
fields = '__all__'
validators = [
UniqueTogetherValidator(
queryset=Project.objects.all(),
fields=['admin', 'name'],
message='You already have a project with this name'
)
]
And/or add it to the model for enforcing it on the database.
class Project(models.Model):
admin = models.ForeignKey(User, on_delete=models.CASCADE, related_name='project_crated_by')
name = models.TextField(max_length=225, blank=False, null=False)
project_members = models.ForeignKey(User, on_delete=models.CASCADE, verbose_name='members', null=True, blank=True)
created_on = models.DateField(default=timezone.now)
tags = ArrayField(models.CharField(max_length=225, default=''), blank=True)
def __str__(self):
return self.name
objects = models.Manager()
class Meta:
unique_together = ("admin", "name")

How to display data from parent model using foreign key django

I want to display the child model data with the parent model data as well in a queryset.
This is my models in model.py
class Shareholders(models.Model):
sharehold_IC = models.CharField(primary_key=True, unique=True, validators=[RegexValidator(r'^\d{12,12}$'), only_int], max_length=12)
sharehold_name = models.CharField(max_length=100, null=True)
sharehold_email = models.CharField(max_length=50, null=True, unique=True)
sharehold_address = models.TextField(null=True, blank=True)
password = models.CharField(max_length=100)
def __str__(self):
return self.sharehold_name
class Meeting(models.Model):
MEETING_STATUS = (
('Coming Soon', 'Coming Soon'),
('Live', 'Live'),
('Closed', 'Closed')
)
meeting_ID = models.CharField(primary_key=True, max_length=6, validators=[RegexValidator(r'^\d{6,6}$')])
meeting_title = models.CharField(max_length=400, null=True)
meeting_date = models.DateField()
meeting_time = models.TimeField()
meeting_desc = models.CharField(max_length=500, null=True)
meeting_status = models.CharField(max_length=200, null=True, choices=MEETING_STATUS)
date_created = models.DateTimeField(default=timezone.now, null=True)
def __str__(self):
return self.meeting_ID
class Question(models.Model):
question_ID = models.AutoField(primary_key=True)
question = models.CharField(max_length=400, null=True)
meeting_id = models.ForeignKey(Meeting, on_delete=CASCADE)
shareholder_IC = models.ForeignKey(Shareholders_Meeting, on_delete=CASCADE, related_name='shareholder_ic')
date_created = models.DateTimeField(default=timezone.now, null=True)
def __str__(self):
return str(self.meeting_id)
I try to display all the data from the Question model with the shareholders details such as sharehold_name from the Shareholders model.
This is how I try to do in Views.py.
Views.py
def getMessages(response, meeting_id):
meeting = Meeting.objects.get(meeting_ID=meeting_id)
questions = Question.objects.filter(meeting_id=meeting.meeting_ID)
# print(list(questions.values('shareholder_IC_id')))
for i in questions:
print(i.shareholder_ic.all())
return JsonResponse({"questions":list(questions.values())})
But somehow I got this error AttributeError: 'Question' object has no attribute 'shareholder_ic'.
I want to get the result like this:
{'question_ID': 141, 'question': "I'm good. How are you?", 'meeting_id_id': '731404', 'shareholder_IC_id': '122311221231', 'date_created': datetime.datetime(2021, 10, 7, 3, 40, 12, 160029, tzinfo=<UTC>), 'sharehold_name':'John Steve', 'sharehold_email':'john#gmail.com'}
How do I fix this or is there any other way to display the data?
Thanks in advance
To begin with, you're not using the related_name attribute in your Question model correctly. It's not to use an alternative name to refer to the related model, the opposite, it's the name you want to use to refer to the Question model from the related model, Shareholders in your case. You have to remake your model:
class Question(models.Model):
question_ID = models.AutoField(primary_key=True)
question = models.CharField(max_length=400, null=True)
meeting_id = models.ForeignKey(Meeting, on_delete=CASCADE)
shareholder_IC = models.ForeignKey(Shareholders_Meeting, on_delete=CASCADE, related_name='questions')
date_created = models.DateTimeField(default=timezone.now, null=True)
def __str__(self):
return str(self.meeting_id)
Then, in your views.py you need to use the correct attribute name in the Question model, which is shareholders_IC:
def getMessages(request, meeting_id): # <- Shouldn't the first param be request?
meeting = Meeting.objects.get(meeting_ID=meeting_id)
# No need to use meeting.meeting_ID here, you can use the meeting instance
questions = Question.objects.filter(meeting_id=meeting)
for i in questions:
print(i.shareholder_IC) # <- No .all(), a question has only one shareholder
return JsonResponse({"questions":list(questions.values())})
However, to achieve what you want, you should either use Django REST Framework, or serialize yourself the different instances that you'll get:
def getMessages(request, meeting_id):
meeting = Meeting.objects.get(meeting_ID=meeting_id)
questions = Question.objects.filter(meeting_id=meeting)
questions_list = []
for i in questions:
questions_list.append(
{
"question_ID": i.question_ID,
"question": i.question,
"shareholder_IC_id": i.shareholder_IC.shareholder_IC,
...
}
)
return JsonResponse(questions_list)
I would recommend two main things:
Learn about relationships in Django and how to represent them in your models. You shouldn't have an attribute meeting_id, for example, in your Question. Although internally the id is indeed being used to query the Meeting, the attribute has a relationship to the model, not to the ID.
Use DRF. It will really help you a lot.
You must use backward relations
questions = Question.shareholder_ic.filter(meeting_id=meeting.meeting_ID)
Do not touch it on the object
For other settings, create the required query set in manager

Why am I still getting 'DeferredAttribute' object has no attribute 'objects'?

After a few days of searching, I still am unable to get over this hurdle. I'm just trying to print a list of descriptions from Sellers as a view. Here's what I'm working with...
models.py:
from django.db import models
class Sellers(models.Model):
index = models.BigIntegerField(blank=True, null=False)
seller = models.TextField(db_column='SELLER', blank=False, null=False,
primary_key=True)
block = models.TextField(db_column='BLOCK', blank=False, null=False)
street = models.TextField(db_column='STREET', blank=False, null=False)
space = models.TextField(db_column='SPACE', blank=False, null=False)
description = models.TextField(db_column='DESCRIPTION', blank=True, null=True)
document_with_idx = models.TextField(blank=False, null=False)
document_with_weights = models.TextField(blank=False, null=False)
class Meta:
managed = False
db_table = 'Sellers'
def __str__(self):
return self.index
'''
views.py:
from django.http import HttpResponse
from search.models import Sellers
def search(request):
output = Sellers.description.objects.all()
return HttpResponse(output)
'''
Any direction would be appreciated, I feel like I've read every related post related to this. Figured it was about time to post a question with my exact setup. Thanks!
Sellers.description refers to the field, so you get basically the TextField object, not one of the descriptions of an object, since Sellers is a class, not a Sellers object. You can obtain the description values with:
from django.http import JsonResponse
from search.models import Sellers
def search(request):
output = Sellers.objects.values_list('description', flat=True)
return JsonResponse({'data': list(output)})
Furthermore you can not simply wrap that in a HttpResponse, since that expects a string/bytes-like object. You can for example JSON encode it with a JsonResponse.

Categories

Resources