I have the following models:
class Article(models.Model):
title = models.CharField(max_length=200, unique=False, null=False)
rating = models.IntegerField(default=0, null=False, unique=False)
class Shared(models.Model):
sender = models.ForeignKey(User)
article = models.ForeignKey(Article)
class SharedMap(models.Model):
item = models.ForeignKey(Shared)
receiver = models.ForeignKey(User)
Now I execute the following query:
def get_shared_feed(self):
return Article.objects.filter(shared__sharedmap__receiver=self)
And I actually get the list of articles as expected. However:
{{ article.shared_set.count }}
Gives me more than 1 if the articles was shared before. I want to get the list of articles with a single sender(e.g. friend) for each. Instead, I receive the list of articles with the set of every user that shared this article.
The solution was really easy. I just had to specify fields I want to return using values:
blog_feed = Article.objects.filter(shared__sharedmap__receiver=self).values('title', 'rating', 'shared__sender')
Then on the template:
{{ article.shared__sender }}
Related
Here i have a Model Recommenders:
class Recommenders(models.Model):
objects = None
Subject = models.ForeignKey(SendApproval, on_delete=models.CASCADE, null=True)
Recommender = models.CharField(max_length=20, null=True)
Status = models.CharField(null=True, max_length=8, default="Pending")
Time = models.DateTimeField(auto_now_add=True)
And another model Approvers:
class Approvers(models.Model):
objects = None
Subject = models.ForeignKey(SendApproval, on_delete=models.CASCADE, null=True)
Approver = models.CharField(max_length=20, null=True)
Status = models.CharField(null=True, max_length=8, default="Pending")
Time = models.DateTimeField(auto_now_add=True)
And my SendApproval model as:
class SendApproval(models.Model):
Subject = models.CharField(max_length=256)
Date = models.DateField(null=True)
Attachment = models.FileField(upload_to=get_file_path)
SentBy = models.CharField(null=True, max_length=100)
Status = models.CharField(null= True, max_length=8, default="Pending")
Now my problem is that I have to display the Subject and Attachment from SendApproval table only when all the recommender's Status in Recommenders table related to that subject is "Approved"
Don't know how can I know that...Thanks in advance...
Actually not have any Idea about the solution but the best answer will be appreciated...By the way, I am new to StackOverflow...So please let me know if there is some ambiguity in my question.
Offer two ways.
1.Here the Recommenders model is filtered by the Status='Approved' field. By the Subject field, which is associated with the primary model, I get access to the SendApproval fields.
Replace bboard with the name of the folder where your templates are placed.
I have this: templates/bboard which are in the application folder.
views.py
def info(request):
recomm = Recommenders.objects.filter(Status='Approved')
return render(request, 'bboard/templ.html', {'context': recomm})
urls.py
urlpatterns = [
path('info/', info, name='info'),
]
templates
{% for a in context %}
<p>{{ 'Subject' }} : {{ a.Subject.Subject }} {{ 'Attachment' }} : Link
{{ 'id SendApproval' }} : {{ a.Subject.id }}</p>
{% endfor %}
2.You can also filter by primary model by fields from a secondary model that is linked to the primary. Here, I passed in the filter the name of the model in lower case and the search field.
In the primary model, by default, a property is created to refer to the secondary model, this is the name of the model in lower case and the _set prefix. In the outer loop, all received rows of the primary model are sorted out, and in the inner loop, through recommenders_set.all(), we get the Status. As you can see it is Approved.
sa = SendApproval.objects.filter(recommenders__Status='Approved')
print(sa)
for i in sa:
for k in i.recommenders_set.all():
print('status', k.Status)
I have a Blog Post Model and I have defined a function to calculate the no of likes.
The Model is as follows ->
class Post(models.Model):
user = models.ForeignKey(User, on_delete=models.PROTECT)
title = models.CharField(max_length=255)
description = models.CharField(max_length=1000,null=True)
Tags = models.CharField(max_length = 255,null=True,blank=True)
Created_date = models.DateTimeField(auto_now_add=True)
Updated_date = models.DateTimeField(auto_now=True)
category = models.ForeignKey(Category, on_delete=models.PROTECT)
Likes = models.ManyToManyField(to=User, related_name='Post_likes')
def __str__(self):
return self.title
def likesCount(self):
return self.Likes.count()
Now I am querying the Post Model from the DB to get all the Posts as follows ->
posts = Post.objects.select_related().prefetch_related('images_set','comments_post').annotate(Count('comments_post')).all()
Here when I loop over the posts I can call the likesCount function and it gives me the correct result as well but I want to return the No of likes to the template.
How can I do that?
in your template, try this:
{{ post.likes_set.count }}
and please make the field names lowercase, they are not Classes
I'm trying to get my head around how Django understands m2m relationships, in SQL you would just add some joins through the intermediate table.
I have a Container which contains various Samples. A Sample can be spread over various Containers.
So in my container I add a alias samples m2m field (essentially a book mark to the other table).
What I can do is get a single Container and display the form information, I would like to add the Sample columns to the form, if I do this for the samples m2m field it returns a multifield, but how do I access the other related fields through the m2m sample_id >=< container_id ?
class Container(models.Model):
container_id = models.AutoField(primary_key=True)
samples = models.ManyToManyField(Sample, through='JoinSampleContainer', through_fields=('container_id', 'sample_id'), related_name='container')
location_id = models.ForeignKey(Location, db_column='location_id', on_delete = models.PROTECT)
icon_desc = models.ForeignKey(Icon, db_column='icon_desc', null=True, blank=True, default='Box',on_delete = models.PROTECT)
container_name = models.CharField(max_length=50, blank=True, null=True)
container_type = models.CharField(max_length=50, blank=True, null=True)
In my Sample table I add the containers alias to act as a bookmark to the other table
class Sample(models.Model):
sample_id = models.AutoField(primary_key=True)
containers = models.ManyToManyField(Container, through='JoinSampleContainer', through_fields=('sample_id', 'container_id'), related_name='sample')
sample_number = models.IntegerField()
material_type = models.CharField(max_length=200, default='', blank=True, null=True, choices = MATERIALS)
weight = models.DecimalField(max_digits=6, decimal_places=2)
description = models.CharField(max_length=500, default='', blank=True, null=True)
recovery_method = models.CharField(max_length=200, default='', blank=True, null=True, choices = RECOVERY_METHODS)
comments = models.CharField(max_length=1000, default='', blank=True, null=True)
In this case I am managing the through table:
class JoinSampleContainer(models.Model):
id = models.AutoField(primary_key=True)
container_id = models.ForeignKey(Container, db_column='container_id', on_delete = models.PROTECT)
sample_id = models.ForeignKey(Sample, db_column='sample_id', on_delete = models.PROTECT)
So now I want to display the contents of a single container through a form. I have the url's setup to pass the container_id.
# views.py
def containercontents(request, pk):
post = get_object_or_404(Container, pk=pk)
# objects = Container.samples.all()
if request.method == "POST":
form = ContainerContentsForm(request.POST, instance=post)
if form.is_valid():
post = form.save(commit=False)
#post.user = request.user
#post.datetime = datetime.datetime.now()
post.save()
return redirect('allcontainer')
#, pk=post.pk)
else:
form = ContainerContentsForm(instance=post)
return render(request, 'container/containercontents.html', {'form': form})
The Form
# form.py
class ContainerContentsForm(forms.ModelForm):
class Meta:
model = Container
fields = (
'location_id',
'container_name',
'container_type',
'icon_desc',
'samples',
)
N.B. The samples seems to list everything regardless of the container.
Then the html
# html
contents
which passes to:
# html
<div class="">
{{ form }}
</div>
Your models are defined wrongly: You should not define the ManyToManyField on both models, only on one of them. So remove the containers field on Sample and only keep it on Container. Set the related_name to "containers" (plural). That way the relationship Container -> Sample is container.samples.all() and the reverse one is sample.containers.all().
Now the purpose of a form is to allow you to select which Samples you want to associate to a Container. So by default the field will be represented by a ModelMultipleChoiceField. The already associated Samples should be pre-selected when you initialise the form with a Container instance.
You can narrow the samples to select from by specifying the queryset for the field, by overriding the default field in the form:
class ContainerContentsForm(forms.ModelForm):
class Meta:
# same code here
samples = forms.ModelMultipleChoiceField(
queryset = Sample.objects.filter(...)
)
You say you want to "display the contents of a Container through the form", if you just want to display, why use a form? To just display the contents, loop through the related samples and display them:
{% for sample in form.instance.samples.all %}
{{ sample.sample_id }}
{% endfor %}
Note: You should rename your ids to id. sample.sample_id is bad programming style. But I already told you that.
class PlannedOTList(models.Model):
patient = models.ForeignKey(Patient, on_delete=models.CASCADE)
date_added = models.DateTimeField(auto_now_add=True)
planned_surgery = models.TextField(verbose_name='diagnosis and planned surgery', blank=True) # decided by the committee
planned_date_of_surgery = models.DateField('date of surgery', null=True, blank=True)
planned_date_of_admission = models.DateField('date of admission', null=True, blank=True)
remarks = models.TextField(blank=True)
surgery_set = models.BooleanField('required surgery set', default=False)
# to_be_admitted = models.BooleanField(default=False)
hide = models.BooleanField(default=False)
objects = PlannedOTListQS.as_manager()
class Meta:
db_table = 'planned_ot_list'
ordering = ['-date_added']
class Admission(models.Model):
# general info
date_admission = models.DateTimeField(auto_now_add=True)
modified = models.DateTimeField(auto_now=True)
patient = models.ForeignKey(Patient, on_delete=models.CASCADE)
class OperationNotesList(models.Model):
admission=models.ForeignKey(Admission,on_delete=models.CASCADE,null=True)
#patient=models.ForeignKey(Patient,on_delete=models.CASCADE)
date_added=models.DateTimeField(auto_now_add=True)
procedure_code=models.CharField(max_length=7)
diagnosis_code=models.CharField(max_length=10)
created_by = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE, null=True, related_name='op_created_by')
pre_operation_list=models.CharField(max_length=70,blank=True)
intra_operation_list=models.CharField(max_length=70,blank=True)
post_operation_list=models.CharField(max_length=70,blank=True)
is_done=models.BooleanField(default=False)
class Meta:
db_table='operationNotesList'
class Patient(models.Model):
patientid_generated_part = models.CharField(max_length=5, default='', blank=True)
date_recorded = models.DateTimeField(default=timezone.now)
modified = models.DateTimeField(auto_now=True, null=True)
first_name = models.CharField(max_length=50)
class Meta:
db_table = 'patients'
ordering = ['-modified']
HTML Code:
<div class="row">
<div class="col-xs-6 col-md-3"><label >Proposed Operation:  
{{ operationnoteslist.admission.patient.planned_ot_list.planned_surgery }}</label></div>
<div class="col-xs-6 col-md-3"><label >Weight:  
{{ operationnoteslist.admission.weight }} (kg)</label></div>
<div class="col-xs-6 col-md-3"><label >Height:  
{{ operationnoteslist.admission.height }} (cm)</label></div>
<div class="col-xs-6 col-md-3"><label >BMI:  
{{ operationnoteslist.admission.bmi }}</label></div>
</div>
the html code above has the main model operationnoteslist.
I am trying to get values from planned_ot_list. I don't know what I am missing.
I thought the way to go is: MyownModelTable.foreignTablename.foreignTablename.field
The Proposed operation does not retrieve any values.
(As reply to the comment: There is no need for a planned_ot_list in the Patient model.)
Reverse relations (one to many) have by default a _set suffix. Also, in your PlannedOTList model, patient has not the unique flag so a patient can have several of those related to them. And on top, the model relation name in lowercase has no underscores (camel case is simply lower cased). So the reverse relation name should be:
patient.plannedotlist_set
(You can print out the available properties using dir(patient), the output will include the reverse relation properties.)
This returns a query manager and you cannot simply write patient.plannedotlist_set.planned_surgery. Instead, you have to decide whether to display the complete list or only one of its entries. If they have a natural order and you want to use the first or last, you can do this:
patient.plannedotlist_set.first # in the template or first() in view
patient.plannedotlist_set.last
To iterate over all of them use:
patient.plannedotlist_set.all # template or all() in view
Note that you should give the PlannedOTList an ordering to make this work, either by adding a Meta property like this:
Meta:
ordering = ('field1', 'field2', ...) # use '-field1' for reverse
Or, if the ordering is dependent of the view, order in the view and add the list to the template context explicitly.
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