Accessing a field via a recursive ManyToMany relationship in a Django model - django

Given the following model:
class Project(models.Model):
project_name = models.CharField(max_length=255)
abstract = models.TextField(blank=True, null=True)
full_description = models.TextField(blank=True, null=True)
date_begun = models.DateField(blank=True, null=True)
related_projects = models.ManyToManyField('self', blank=True, null=True)
class Meta:
ordering = ['project_name']
def __unicode__(self):
return self.project_name
How do I access the ID of projects references in the related_projects field. For example, I can get their project_name values by doing something like this:
def transform_related_projects(self, instance):
return [unicode(rp) for rp in instance.related_projects.all()]
But I can't see how to get the if for the Project record, since the def unicode(self) function only return the project name as a unicode string. I know I'm missing something obvious. Thanks

def transform_related_projects(self, instance):
return [rp.id for rp in instance.related_projects.all()]

Related

Query with multiple foreign keys (django)

I'm making a searchbar for a site I'm working on and I'm having trouble when I want to filter different fields from different models (related between them) Here are my models:
class Project(models.Model):
name = models.CharField(max_length=250)
objective = models.CharField(max_length=250)
description = models.TextField()
launching = models.CharField(max_length=100, null=True, blank=True)
image = models.ImageField(
upload_to='imgs/', null=True, blank=True)
image_thumbnail = models.ImageField(
upload_to='thumbnails/', null=True, blank=True)
slug = models.CharField(max_length=250)
class Meta:
db_table = 'project'
def __str__(self):
return self.name
class Institution(models.Model):
name = models.CharField(max_length=250)
project = models.ManyToManyField(Proyecto)
class Meta:
db_table = 'institution'
def __str__(self):
return self.name
And I want to be able to search by the name of the project or the institution, but my code only takes the institution's name.
def searchbar(request):
if request.method == 'GET':
search = request.GET.get('search')
post = Project.objects.all().filter(name__icontains=search, institution__name__icontains=search)
return render(request, 'searchbar.html', {'post': post, 'search': search})
How can I search for all the projects that match by its name OR the institution's name?
BTW, I'm using SQL, not sure if it's relevant, but I thought I should add that info.
You can .filter(…) [Django-doc] with Q objects [Django-doc]:
from django.db.models import Q
Project.objects.filter(Q(name__icontains=search) | Q(institution__name__icontains=search))
or you can work with the _connector parameter:
from django.db.models import Q
Project.objects.filter(
name__icontains=search,
institution__name__icontains=search,
_connector=Q.OR
)

Is it possible in Django to call custom `QuerySet` method on reverse related objects lookup?

E.g. there are next models and custom QuerySet:
from django.db import models
class ActiveQuerySet(models.QuerySet):
def active(self):
'''returns only active objects'''
'''supposing here would be a lot
of more complicated code
that would be great to reuse
'''
return self.filter(is_active=True)
class Category(models.Model):
name = models.CharField(max_length=128, blank=True, null=True, default=None)
class Product(models.Model):
name = models.CharField(max_length=128, blank=True, null=True)
is_active = models.BooleanField(default=True)
category = models.ForeignKey(Category, on_delete=models.SET_NULL, related_name='products', related_query_name="product", blank=True, null=True, default=None)
objects = ActiveQuerySet.as_manager()
Could you tell me if there is a way to call the active() method like this:
category = Category.objects.first()
category.products.active()
instead of doing like this:
category.products.filter(is_active=True)
Or how to implement appropriately such behavior?
You have to add the custom queryset into the parent model, not the _set. You can change custom_products to any other word.
class ActiveQuerySet(models.QuerySet):
def active(self):
'''returns only active objects'''
'''supposing here would be a lot
of more complicated code
that would be great to reuse
'''
return self.products.filter(is_active=True)
class Category(models.Model):
name = models.CharField(max_length=128, blank=True, null=True, default=None)
custom_products = ActiveQuerySet.as_manager()
category.custom_products.active()

How get information from three different tables at once?

I have following models:
class Device(models.Model):
name = models.CharField(max_length=100, blank=False)
description = models.TextField(max_length=500, blank=True)
ip_address = models.GenericIPAddressField(blank=True, null=True)
contact_person = models.ForeignKey(User, on_delete=models.SET_NULL, null=True)
team = models.ForeignKey(Team, on_delete=models.SET_NULL, null=True)
category = models.ForeignKey(Category, on_delete=models.SET_NULL, null=True)
def __str__(self):
return self.name
class TimeSlot(models.Model):
name = models.CharField(max_length=20)
start_slot = models.CharField(max_length=10)
end_slot = models.CharField(max_length=10)
def __str__(self):
return self.name
class Reservation(models.Model):
device = models.ForeignKey(Device, on_delete=models.CASCADE)
time_slot = models.ForeignKey(TimeSlot, on_delete=models.CASCADE)
date_of_reservation = models.DateField()
user = models.ForeignKey(User, on_delete=models.CASCADE)
def __str__(self):
return "{} - {} for device: {} by {}.".format(self.time_slot, self.date_of_reservation, self.device, self.user)
class ForbiddenSlot(models.Model):
device = models.ForeignKey(Device, on_delete=models.CASCADE)
time_slot = models.ForeignKey(TimeSlot, on_delete=models.CASCADE)
def __str__(self):
return str(self.time_slot)
This is simple reservation system. I have problem to understand how create query for three different tables.
I want get all TimeSlots which are not set in ForbiddenSlot and Reservation for given Device name.
I'm not entirely sure if this will work, but I think it will and is definitely worth a shot.
TimeSlot.objects.filter(
forbiddenslot__isnull=True,
reservation__device__name='Device Name',
)
It's not necessarily the easiest thing for me to wrap my head around, but not only does TimeSlot have access to .forbiddenslot_set, it also can filter by forbiddenslot. The same goes for reservation.
I guess changing the structure of your models will be much better, like deleting the model ForbiddenSlot and replacing it with a flag on the reservation model, then you can select all TimeSlots from the reservation model where the forbidden flag is False, like:
reservations = Reservation.objects.only('time_slot').filter(device__name=name_of_the_device,forbidden=False) where forbidden is a boolean field.
Using select_related() will pre-populate the appropriate attributes:
Model.objects.select_related()

join two tables in django admin to get columns for display_list

I am having problem with list_display/joining two table for django admin interface.
I want to have columns- program_name and is_active from SchPrograms model with parameter_name, parameter_description from VisVisitParameters model in django admin. I am able to have those columns which i am using with return in each of these models. I tried to take help from the question that already has been asked. But still i could not able to figured this out.
class SchPrograms(models.Model):
program_id = models.AutoField(primary_key=True)
program_name = models.CharField(max_length=200, blank=True, null=True)
creation_timestamp = models.DateTimeField(blank=True, null=True)
is_active = models.IntegerField()
class Meta:
managed = True
db_table = 'sch_programs'
app_label = 'polls'
def __str__(self):
return self.program_name
class VisVisitParameters(models.Model):
vparameter_id = models.AutoField(primary_key=True)
parameter_name = models.CharField(max_length=300, blank=True, null=True)
parameter_description = models.TextField(blank=True, null=True)
is_active = models.IntegerField(choices=STATUS_CHOICES)
class Meta:
managed = False
db_table = 'vis_visit_parameters'
def __str__(self):
return str(self.vparameter_id)
app_label = 'polls'
class VisVisitParameterMappings(models.Model):
vp_map_id = models.AutoField(primary_key=True)
vparameter = models.ForeignKey(VisVisitParameters,on_delete=models.CASCADE)
program = models.ForeignKey(SchPrograms,on_delete=models.CASCADE)
display_order = models.IntegerField(blank=True, null=True)
is_active = models.IntegerField()
class Meta:
managed = False
db_table = 'vis_visit_parameter_mappings'
app_label = 'polls'
def __str__(self):
return str(self.parameter_name)
model.py
class VisVisitParameterMappings_admin(admin.ModelAdmin):
list_display = ('program_name','is_active','parameter_name','parameter_description ')
To display the required items on the list display page you can write your custom methods, as documented here.
For example, for your field named program_name you can have:
def program_name(self, obj):
if obj.program:
return obj.program.program_name
program_name.short_description = 'Program name'
and for another model field named parameter_name , you may have:
def parameter_name(self, obj):
if obj.vparameter:
return obj.vparameter.parameter_name
parameter_name.short_description = 'Parameter Name'
Hope it helps.

Problem inheriting get_absolute_url in an child model

I have the following sets of models (abbreviated for clarity):
First set:
class Web(Link):
ideas = models.ManyToManyField(Idea, blank=True, null=True)
precedents = models.ManyToManyField(Precedent, blank=True, null=True)
categories = GenericRelation(CategoryItem)
#permalink
def get_absolute_url(self):
return ('resources-link-detail', [str(self.slug)])
which is a child of:
class Link(models.Model):
title = models.CharField(max_length=250)
description = models.TextField(blank=True)
website = models.URLField(unique=True)
slug = models.SlugField(unique_for_date='pub_date')
...
#permalink
def get_absolute_url(self):
return ('link-detail', [str(self.slug)])
Second set
class ResourceOrganization(Organization):
ideas = models.ManyToManyField(Idea, blank=True, null=True)
precedents = models.ManyToManyField(Precedent, blank=True, null=True)
categories = GenericRelation(CategoryItem)
#permalink
def get_absolute_url(self):
return ('resources-org-detail', [str(self.slug)])
which is a child of:
class Organization(Contact):
name = models.CharField(max_length=100)
org_type = models.PositiveSmallIntegerField(choices=ORG_CHOICES)
...
#permalink
def get_absolute_url(self):
return ('org-detail', [str(self.slug)])
which is a child of:
class Contact(models.Model):
description = models.TextField(blank=True, null=True)
address_line1 = models.CharField(max_length=250, blank=True)
address_line2 = models.CharField(max_length=250, blank=True)
slug = models.SlugField(unique=True)
...
class Meta:
abstract = True
The "ResourceOrganization" model is properly overiding the get_absolute_url method and is adding the "categories" generic relation.
The "Web" model is not.
I'm at a loss to figure out why. Would appreciate any insight.
P.S. I'm realizing that there may have been better ways to implement this functionality, but I'm stuck with it for the moment until I can refactor and would like to get it working.
Thanks.
If anyone else is running into this problem, take a look at any custom managers you have defined on the parent model. They will not inherit to the child model in the way you might think.
http://docs.djangoproject.com/en/dev/topics/db/managers/#custom-managers-and-model-inheritance