I'm working on the development of a web with Django and PostgreSQL and I'm using the app django-tables2 to create HTML tables.
class SampleTable(ColumnShiftTableBootstrap4):
class Meta:
model = Sample
fields = ("name", "sample_id_sex", "pools", "indexes", "gene_cand_lists",)
My database collects Next Generation Sequencing (NGS) data. sample_id_sex is a foreign key (1:N relationship) while pools, indexes and gene_cand_lists are many-to-many fields, the combination of these three rows are unique: in other words, they are related.
My problem is that in each row the values are ordered by default. For example, the sample X belongs to the pool CES001 and has the index B2 and the gene list list3 but it also belongs to the pool CES002 with the index A1 and list1. In the table, they should appear like this (, as the separator in the many-to-many columns):
sample
sex
pools
indexes
gene_lists
12-009
male
CES001, CES002
B2, A1
list3, list1
But they appear like this:
sample
sex
pools
indexes
gene_lists
12-009
male
CES001, CES002
A1, B2
list1, list3
The relationships between the three fields are broken. Is there a way to correct this? And the separator could be a newline and not a comma?
Edit: I think the question is not clear enough. The model of the sample table is:
class Sample(models.Model):
id_sample = models.AutoField(primary_key=True)
name = models.CharField(unique=True, max_length=20)
indexes = models.ManyToManyField(Index, through='SamplePoolIndexCand', blank=True)
pools = models.ManyToManyField(Index, through='SamplePoolIndexCand', blank=True)
gene_lists = models.ManyToManyField(Index, through='SamplePoolIndexCand', blank=True)
And the intermediate table:
class SamplePoolIndexCand(models.Model):
sample_id = models.ForeignKey(Sample, null=True, blank=True, on_delete=models.CASCADE, db_column='id_sample',
verbose_name='Mostra')
pool_id = models.ForeignKey(Pool, null=True, blank=True, on_delete=models.CASCADE, db_column='id_pool',
verbose_name='Pool')
index_id = models.ForeignKey(Index, null=True, blank=True, on_delete=models.CASCADE,
db_column='id_index', verbose_name='Índex')
gene_cand_list_id = models.ForeignKey(GeneCandList, null=True, blank=True, on_delete=models.CASCADE,
db_column='id_gene_cand_list', verbose_name='Llista de gens candidats')
You can use ordering tag in your models particular class of many to many fields
class gene_lists(models.Model):
priority = models.PositiveSmallIntegerField(default=16383)
class indexes(models.Model):
contents = models.ManyToManyField(gene_lists, blank=True, null=True)
class Meta:
ordering = ['priority', 'contents']
Related
I want to make a flexible online shop which will allow it's admins to create products and add custom product fields without need to program. I did it, but the final database structure is so complicated that I can't figure out how to filter it.
Let's say there are categories with some products attached to it. Each category has only one unique template, the template holds custom fields names and types(int, char). When a product is created, the corresponding template-like fields are written to another model that holds custom fields names and values.
So, how to filter the product model considering its custom fields values? To clarify, let's say someone created smartphones category, created template with fields "Brand" and "Screen size", added some smartphones and wants to filter phones with brand="Apple" and screen size > 4.5 inches.
I hope that makes sense ^_^
Database structure:
class Category(models.Model):
name = models.CharField(max_length=63)
class Product(models.Model):
category = models.ForeignKey(Category, on_delete=models.CASCADE)
name = models.CharField(max_length=63)
price = models.IntegerField(validators=[MinValueValidator(0), MaxValueValidator(1073741823)], null=True, blank=True)
#Template
class CategoryTemplate(models.Model):
category = models.ForeignKey(Category, on_delete=models.CASCADE, null=True)
name = models.CharField(max_length=255, null=True, blank=True)
#Model that holds template custom fields
class TemplateField(models.Model):
template = models.ForeignKey(CategoryTemplate, on_delete=models.CASCADE)
name = models.CharField(max_length=255, null=True, blank=True)
is_integer = models.BooleanField(blank=True, default=False)
#Values of custom char product fields
class ProductPropertiesChar(models.Model):
product = models.ForeignKey(Product, on_delete=models.CASCADE)
property_name = models.CharField(max_length=255, null=True, blank=True)
property_value = models.CharField(max_length=255, null=True, blank=True)
#Values of custom integer product fields
class ProductPropertiesInteger(models.Model):
product = models.ForeignKey(Product, on_delete=models.CASCADE)
property_name = models.CharField(max_length=255, null=True, blank=True)
property_value = models.IntegerField(validators=[MinValueValidator(0), MaxValueValidator(1073741823)], null=True, blank=True)
Maybe this will work. Firstly, I'd strongly recommed using explicit related names!
class ProductPropertiesChar(models.Model):
product = models.ForeignKey(Product, on_delete=models.CASCADE,
related_name='charprop')
...
Simple case: all Products related to a single specified ProductPropertiesChar (the default related name is too horrible to type)
results = Product.objects.filter( charprop__property_name='Brand',
charprop__property_value='Apple' )
You can combine several values with __in or use the other usual __ lookups. You should also be able to .exclude(...).
results = Product.objects.filter( charprop__property_name='Brand',
charprop__property_value__in = ['Apple','Samsung','Google'] )
You ought to be able to use Q objects
q1 = Q( charprop__property_name='Brand',charprop__property_value='Apple' )
q2 = Q( intprop__property_name='ScreenSize', intprop__property_value__gte=130 )
I'm pretty sure or will work
results = Product.objects.filter( q1 | q2 )
I'm not quite so sure about and because you are following the related name to two different objects
results = Product.objects.filter( q1 & q2 ) # not sure
You may instead need to use .intersection (doc here)
qs1 = Product.objects.filter( q1)
qs2 = Productr.objects.filter( q2)
results = qs1.intersection( qs2)
See also .union, .difference
At this poimt I'll admit I'm talking about things I have read about but never tried. You will have to experiment, and read the Django docs over and over again!
I have three models such as the one below and I am trying to write a query that allows me to access all the Day_Type associated to the Day objects that are pointing to a specific JobProject.
I know that I can get all the Day pointing at a JobProject by querying project.jobproject_days.all() and I can get the values of the Day_Type by doing project.jobproject_days.values_list('day_type__name', flat=True)
BUT how can I get the Day_Type themselves?
class JobProject(models.Model):
......
class Day_Type(models.Model):
name = models.CharField(max_length=30)
class Day(models.Model):
....
day_type = models.ForeignKey(Day_Type, blank=True, on_delete=models.CASCADE, null=True, related_name='day_type')
project = models.ForeignKey(JobProject, blank=True, on_delete=models.CASCADE, related_name='jobproject_days', null=True)
You can fetch it like this:
daytypes = Day_Type.objects.filter(day_type__project=project)
These two classes have Foreign Key to each other and class OrderRow is representing a row which belongs to an Order, I want to know is there any way to set "rows" attribute inside class Order to show a list or query-set of all related order rows by calling it on an object or instance of class Order?
class OrderRow(models.Model):
product = models.ForeignKey(Product, on_delete=models.CASCADE)
order = models.ForeignKey('Order', on_delete=models.CASCADE)
amount = models.IntegerField(default=0)
class Order(models.Model):
customer = models.ForeignKey(Customer, on_delete=models.CASCADE)
order_time = models.DateTimeField(auto_now_add=True)
total_price = models.IntegerField(null=True, blank=True)
**rows = models.ForeignKey('OrderRow', on_delete=models.CASCADE, related_name='order_rows')**
You should have ForeignKey in OrderRows with related_name="rows". Like this:
class OrderRow(models.Model):
# rest of the fields
order = models.ForeignKey('Order', on_delete=models.CASCADE, related_name='rows')
Then you can use:
order = Order.objects.first()
for order_row in order.rows.all():
print(order_row)
For more information, please check the documentation.
I have the following models:
class Work_Music(models.Model):
key = models.CharField(max_length=10, null=True, blank=True)
tonality = models.CharField(max_length=20, null=True, blank=True)
class Catalogue(models.Model):
work_music = models.ForeignKey(Work_Music, verbose_name=_('work_music'), on_delete=models.PROTECT)
name = models.CharField(max_length=100, null=True, blank=True)
name_short = models.CharField(max_length=100, null=True, blank=True)
no = models.CharField(max_length=100, null=True, blank=True)
related_field() only works with the Foreign key is in Work_Music. Many catalogue/catalogue numbers can map to a piece of music (Work_Music). How can I construct a query set on Work_Music to pull all of the catalogues related to the piece of work?
Use catalogue_set.
Django's ORM automatically creates the field for you on the navigation model of the foreign key (Work_Music in this case). For "one-to-many" relationships, this is a queryset with the name of the model on which the foreign key exists appended with _set. For "one-to-one" relationships, this is just the name of the model on which the foreign key exists.
assuming a Work_Music instance called work_music_instance:
catalogues = work_music_instance.catalogue_set.all()
or
catalogues = work_music_instance.catalogue_set.filter(...) # any query set operation
First get an object whose catalogue you want.
workmusic = Work_Music.objects.all()[0]
then
workmusic.catalogue_set.all()
this will return all catalogue related to workmusic object.
I am trying to export all my database with a prefetch_related but I only get data from the main model.
My models:
class GvtCompoModel(models.Model):
gvtCompo= models.CharField(max_length=1000, blank=False, null=False)
...
class ActsIdsModel(models.Model):
year = models.IntegerField(max_length=4, blank=False, null=False)
...
class RespProposModel(models.Model):
respPropos=models.CharField(max_length=50, unique=True)
nationResp = models.ForeignKey('NationRespModel', blank=True, null=True, default=None)
nationalPartyResp = models.ForeignKey('NationalPartyRespModel', blank=True, null=True, default=None)
euGroupResp = models.ForeignKey('EUGroupRespModel', blank=True, null=True, default=None)
class ActsInfoModel(models.Model):
#id of the act
actId = models.OneToOneField(ActsIdsModel, primary_key=True)
respProposId1=models.ForeignKey('RespProposModel', related_name='respProposId1', blank=True, null=True, default=None)
respProposId2=models.ForeignKey('RespProposModel', related_name='respProposId2', blank=True, null=True, default=None)
respProposId3=models.ForeignKey('RespProposModel', related_name='respProposId3', blank=True, null=True, default=None)
gvtCompo= models.ManyToManyField(GvtCompoModel)
My view:
dumpDB=ActsInfoModel.objects.all().prefetch_related("actId", "respProposId1", "respProposId2", "respProposId3", "gvtCompo")
for act in dumpDB.values():
for field in act:
print "dumpDB field", field
When I display "field", I see the fields from ActsInfoModel ONLY, the starting model. Is it normal?
You haven't understood the arguments to prefetch_related. It's not a list of fields, but a list of models.
(Note that your field naming convention is also very misleading - respProposId1 and actId are not IDs, but actual instances of the models. Django has created an underlying field in each case by appending _id, so the db columns are respProposId1_id and actId_id. You should just call the fields resp_propos1 and resp_propos2 - also note that normal style is lower_case_with_underscore, not capWords.)
It is normal, that you are seeing fields from ActsInfoModel only. You can access related models via dot notation, like:
acts = ActsInfoModel.objects.all().prefetch_related("actId", "respProposId1", "respProposId2", "respProposId3", "gvtCompo")
for act in acts:
print act.respProposId1.respPropos
Related models are already prefetched, so it won't produce any additional queries. FYI, quote from docs:
Returns a QuerySet that will automatically retrieve, in a single
batch, related objects for each of the specified lookups.