Assign value to one-to-many field through django code - django

I am trying to assign value to a database entry that is defined using the models.ForeignKey. How should I refer to the variables in the referred model?
In the code below, the assignment update_user.appointments.requester_name = requesting_user does not work. Googling has not helped me find the right solution. How should one refer to such variables from django/python?
Below is my models.py
class AppointmentRequest(models.Model):
my_name = models.TextField(default='')
requester_name = models.TextField(default='')
meeting_year = models.TextField(default='')
class CustomUser(AbstractUser):
firstname = models.TextField(default='')
lastname = models.TextField(default='')
appointments = models.ForeignKey(AppointmentRequest, on_delete=models.CASCADE, default='', blank=True, null=True)
I want to modify the value of appointments entry, i.e., my_name, requester_name, etc.
Below is the code in views.py
def book_appointment(request):
requesting_user = request.GET['requesting_user']
update_user = CustomUser.objects.get(username=requested_user)
update_user.appointments.requester_name = requesting_user

The reason you're probably getting the "NoneType" object has not attribute "requester_name" is that update_user.appointments is probably null
appointments = models.ForeignKey(AppointmentRequest, on_delete=models.CASCADE, default='', blank=True, null=True)
That says your ForeignKey can be null, so that's what it's probably returning to you.
What you should really do is:
if update_user.appointments:
update_user.appointments.requester_name = request.GET['requesting_user']
else:
apt_request = AppointmentRequest()
apt_request.requester_name = request.GET['requesting_user']
apt_request.save()
update_user.appointments = apt_request()
update_user.save()
This creates an AppointmentRequest object that you use to set the appointments ForeignKey IF update_user.appointments is null.
ALSO, in this code:
appointments = models.ForeignKey(AppointmentRequest, on_delete=models.CASCADE, default='', blank=True, null=True)
I'm pretty sure default='' does nothing and it defaults to null. So you can omit that part of the code.
Cont in comments...:
Oh. Another thing. I wouldn't use ForeignKeys for this. I would Use ManyToMany unless the user is only allowed ONE appointment ever.

requesting_user = request.GET['requesting_user']
in this part you are getting the user as json not a django model instance, so when you apply
update_user = CustomUser.objects.get(username=requested_user)
it doesn't get any thing.
you should use django serializer to make a userSerializer then use it to convert the json user to model instance then when you apply
update_user = CustomUser.objects.get(username=requested_user)
this should work.

Related

Fetching data from models using OneToOneField in Django

well my college is making us go learn a framework and make a website with it in a month, and it's really killing me, because of that I couldn't really get a good understanding of the Django framework as I am making progress while watching YouTube vids and reading docs.
Anyways my models are all messed up which made the job even harder, and whenever I solve a problem another one arises, but the deadline is close and making any changes to the models will cost me a great deal of time. This time my problem is about fetching data.
The concerned models are the following:
The User class for authentication
class User(AbstractBaseUser, PermissionsMixin):
id = models.AutoField(primary_key=True,null=False)
username = models.CharField(max_length=50)
email = models.EmailField(unique=True)
nom = models.CharField(max_length=255)
prenom = models.CharField(max_length=255)
usertype = models.CharField(choices=types,max_length=20,default="user")
date_joined = models.DateTimeField(auto_now_add=True)
last_login = models.DateTimeField(auto_now=True)
is_superuser = models.BooleanField(default=False)
is_staff = models.BooleanField(default=False)
is_active = models.BooleanField(default=True)
student_data = models.OneToOneField(Etudiant, on_delete=models.CASCADE,blank=True, null=True,related_name='Etudiant_access')
Prof_data = models.OneToOneField(Prof, on_delete=models.CASCADE,blank=True, null=True)
objects=UserManager()
def __str__(self):
return self.prenom + " " + self.nom
USERNAME_FIELD = 'email'
REQUIRED_FIELDS = ['username']
The Students(Etudiant) class for managing the students:
class Etudiant(models.Model):
filiere = models.ForeignKey(Filiere, on_delete=models.DO_NOTHING)
classe = models.ForeignKey(Classe,null=True, on_delete=models.DO_NOTHING)
notes = models.ManyToManyField(note,blank=True, null=True)
The class Classe (LMAO) for managing the different classes:
class Classe(models.Model):
#Cla_id = models.AutoField(primary_key=True, null=False)
Designation = models.CharField(max_length=100)
filiere = models.ForeignKey(Filiere, on_delete=models.CASCADE)
Epreuve = models.ManyToManyField(Epreuve,blank=True, null=True)
def __str__(self):
return self.Designation
The thing is that I wanna fetch all data of the Users that are students (which means that their Prof_data attribute is blank/null and their student_data attribute is pointing to the Etudiant(Student) class while having an Etudiant.classe attribute equals to a value in the view's parameters
I've solved a great deal of it but I'm stuck at the end
This is my view function:
#login_required
def class_info(request,design):
#getting the Classe(s) from the url which Designation == design
classe_now = Classe.objects.get(Designation=design)
print(classe_now) # This works like a charm
#getting the Students objects that are part of the class_now
Etudiants = Etudiant.objects.filter(classe=classe_now)
print(Etudiants) # This works too. It returns the 'Etudiant' objects from where i wanna access to the Users data
#getting the User data of the student objects (This is where i get confused)
students_to_show = User.objects.filter(student_data=Etudiants)
pprint(students_to_show)
return render(request, 'Prof/class_info.html')
I am really confused, you are truly my last hope in this, and thank you for your time.
You can filter your User model by selecting all users that do have empty/null relation to Prof model and nonempty/null relation to Etudiant model.
student_users = User.objects.filter(Prof_data__isnull=True, student_data__isnull=False)
then for each stident_user, you can fetch its student data in the following manner:
student_user = student_users[0]
student_user.student_data.filiere
student_user.student_data.classe
student_user.student_data.notes
You can then pass the queryset result to the render function as a context variable. Check this brief tutorial on how to pass data to templates.

Django admin list filter on reverse relationship

I have two django models:
class Order(models.Model):
date = models.DateTimeField()
customer = models.ForeignKey(Customer, on_delete=models.CASCADE, related_name='orders')
shipping_address = models.CharField(max_length=200)
phone_number = models.CharField(max_length=9)
comment = models.CharField(max_length=100, blank=True, null=True)
class OrderStatus(models.Model):
STATUS_ACCEPTED = 1
STATUS_PROCESSING = 2
STATUS_DELIVERING = 3
STATUS_COMPLETED = 4
CODE_CHOICES = (
(STATUS_ACCEPTED, 'accepted'),
(STATUS_PROCESSING, 'processing'),
(STATUS_DELIVERING, 'delivering'),
(STATUS_COMPLETED, 'completed'),
)
date_created = models.DateTimeField(auto_now_add=True)
code = models.PositiveSmallIntegerField(choices=CODE_CHOICES)
order = models.ForeignKey(Order, on_delete=models.CASCADE, related_name='status_list')
Normally if I wanted to get all the orders with 'accepted' status I could write Order.objects.filter(orderstatus__code=1).
But how can I make django admin to create OrderStatus list filter?
I have googled a lot and found only one answer here on stackoverflow, which claims simply adding reverse model ('orderstatus' in my case) to list_filter tuple should work, but I get an error message: The value of 'list_filter[1]' refers to 'orderstatus', which does not refer to a Field.
What am I doing wrong?
Did you try by you self before posting question here, because there are lots of question related to this one, Any way i think this link will help you.
https://books.agiliq.com/projects/django-admin-cookbook/en/latest/many_to_many.html
The value of 'list_filter[1]' refers to 'orderstatus', which does not refer to a Field.
This is because orderstatus is not a field in your model. Either change order field to orderstatus or change the name passed to list_filter to the name of your field.

django get associated data one to one field

I'm working in Django 2.0
I have a model Note to save note and two another models to add color labels to the note.
class Note(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE)
title = models.CharField(max_length=250, blank=True, default='Untitled')
content = models.TextField(blank=True)
class ColorLabels(models.Model):
title = models.CharField(max_length=100, unique=True)
value = models.CharField(max_length=100)
default = models.BooleanField(default=False)
class NoteLabel(models.Model):
note = models.OneToOneField(Note, on_delete=models.CASCADE)
color_label = models.OneToOneField(ColorLabels, on_delete=models.CASCADE)
with the object of Note
note = Note.objects.get(pk=1)
I want to access associated ColorLabels's title and value fields or the NoteLabel object.
since they are one to one field. I tried doing
note.note_label
note.NoteLabel
note.note_label_set
But all returns error as
AttributeError: 'Note' object has no attribute 'note_label_set'
Unless you define related_name in your OneToOneField, Django will use lowercased model name to access related object. So, note.notelabel should work.

Django: Converting a GenericForeignKey Relationship to a ForeignKey Relationship

I'm working to remove an existing GenericForeignKey relationship from some models. Id like to change it to the Reformatted Model below. Does migrations provide a way to convert the existing content_type and object_ids to the respective new ForeignKey's? (to keep existing data). Basically brand new at programming, so pardon me if I'm asking a stupid question.
class Donation(models.Model):
amount_id = models.CharField(max_length=12, unique=True, editable=False)
date_issued=models.DateField(auto_now_add=True)
description=models.TextField(blank=True, null=True)
content_type = models.ForeignKey(ContentType)
object_id = models.PositiveIntegerField()
content_object = generic.GenericForeignKey('content_type','object_id')
class Individual(BaseModel):
first_name = models.CharField(max_length=50)
middle_name = models.CharField(max_length=50, blank=True,
null=True)
last_name = models.CharField(max_length=50)
suffix = models.CharField(max_length=50, blank=True, null=True)
contributor = generic.GenericRelation(Donation, related_query_name='individual')
class Organization(models.Model):
name = models.CharField(max_length=100)
contributor = generic.GenericRelation(Donation, related_query_name='organization')
Reformatted Model
class Donation(models.Model):
amount_id = models.CharField(max_length=12, unique=True, editable=False)
date_issued=models.DateField(auto_now_add=True)
description=models.TextField(blank=True, null=True)
contributor_group = models.ForeignKey(Organization, null=True, blank=True, on_delete=models.CASCADE)
contributor_individual = models.ForeignKey(Individual, null=True, blank=True, on_delete=models
Based on your model definition of Donation Model, one of fields contributor_group , contributor_model will always be Null post migration.
I hope you have taken that into you consideration.
Just to be safe Do this in two phases.
1. Keep the content_type and object_id and add the two new fields.
2. Next step remove the generic fields post data population.
There are two ways to populate those new fields
Django migrations provides you a way to populate new fields with values during the migrations. You can look it up. I haven't done that before either.
For more control and some learning as well. You can populate that via scripting as well. You can setup django-extensions module in your project. And write a script to do that population for you as well. A sample script would look like.
from myproject.models import Donation, Individual, Organization
from django.contrib.contenttypes.models import ContentType
def run():
organization_content_type = ContentType.objects.get_for_model(Organization)
individual_content_type = ContentType.obejcts.get_for_model(Individual)
donations = Donation.objects.all()
for donation in donations:
if donation.content_type_id == organization_content_type.id:
donation.contributor_group = donation.object_id
elif donation.content_type_id == individual_content_type.id:
donation.contributor_individual = donation.object_id
else:
print "Can't identify content type for donation id {}".format(donation.id)
donation.save()
Check the values are correct and then remove the generic fields.
Facing some issues with formatting here.

Filtering on foreign key relationship - Django

I want to find the number of articles for which a specific user has created articlehistory records.
The models for that look like this:
class Article(models.Model):
"""The basic entity of this app.)"""
documentID = models.CharField(blank=True, max_length=1000)
cowcode = models.IntegerField(blank=True, null=True)
pubdate = models.DateField(default=datetime.datetime.today)
headline = models.CharField(blank=True, max_length=1500)
source = models.CharField(blank=True, max_length=5000)
text = models.TextField(blank=True, max_length=1000000)
assignments = models.ManyToManyField(Assignment)
class Meta:
ordering = ['pubdate']
def __unicode__(self):
return self.headline
class ArticleHistory(models.Model):
"""(Modelname description)"""
article = models.ForeignKey(Article, related_name='Article History')
coder = models.ForeignKey(User, related_name='Article History')
last_updated = models.DateTimeField(default=datetime.datetime.now)
def __unicode__(self):
return self.last_updated
The way I'm trying to do this at the moment is like this:
assignment.finished_articles = Article.objects.filter(cowcode=country).filter(pubdate__range=(start_date,end_date), articlehistory__coder=request.user.id).count()
This doesn't work, however and exhibits another weird behaviour:
I try to do this:
for assignment in assignments:
country = assignment.country.cowcode
start_date = assignment.start_date
end_date = assignment.end_date
articles = Article.objects.filter(cowcode=country).filter(pubdate__range=(start_date,end_date)).select_related()
assignment.article_num = articles.count()
#assignment.finished_articles = Article.objects.filter(cowcode=country).filter(pubdate__range=(start_date,end_date), articlehistory__coder=request.user.id).count()
This works fine, unless I try to include finished_articles, then article_num gets shortened to one result.
It would be really great if anyone has a pointer to who to solve this.
Make use of reverse relation of ForeignKey created by parameter related_name:
Rename attribute related name to "article_history_set".
Now, it gives you easy pointer: user.article_history_set is a set of Article History objects where coder is set to this user.
Then you can find which article it is related to by doing article_history.article.
At the end, you have to get rid of repetition and get length of that list.
Here you have more about related_name attribute: https://docs.djangoproject.com/en/dev/ref/models/fields/#django.db.models.ForeignKey.related_name