Django Many to Many field dependent on another many to many field - python

I'm creating two many-to-many fields based on same model in a single model. I would like to show only those instances in second many-to-many field which are selected in first many to many field to further apply selection. Through which approach should i handle this behaviour.
class Params(models.Model):
name = models.CharField(max_length = 200)
comments = Model.TextField()
def __str__(self):
return self.name
class Selection(models.Model):
select_params = models.ManyToManyField(Params, blank=True, related_name = "selection_1")
edit_selected_params = models.ManyToManyField(Params, blank=True, related_name =
"selection_from_selec_params")
Thanks and regards

You can use SubQuery is think:
selected = Selection.objects.filter(
edit_selected_params__in=SubQuery(
Selection.objects.filter(select_params__isnull=False).values_list("select_params", flat=True)
)
)
You can see SubQuery docs

Related

DJANGO: How can I duplicate attribute from other class?

I want to duplicate an attribute from other class.
class PedidoCliente(Pedido):
total_pagado = models.DecimalField(blank=True, max_digits=10, decimal_places=2,default = 0,verbose_name="Pagado $") # default 0 para el error for += int
barril_encargado = models.DecimalField(blank=True, default=0, max_digits=10, decimal_places=2,verbose_name="Barr. entregados")
fecha_entrega = models.DateField(verbose_name="Fecha Entrega")
class DetallePedidoCliente(DetallePedido):
comments = models.CharField(max_length=300, verbose_name="Comentarios")
precio_venta = models.DecimalField(max_digits=16, decimal_places=2, default = 0)
pedido = models.ForeignKey(PedidoCliente,on_delete=models.CASCADE)
fecha_entrega = the same from PedidoCliente
I'm new at OPP so sorry if it's a silly question.
Thanks!
One should not look to mirror fields of another model. This simply leads to extra work. One needs to update this mirrored field each time it is updated in the other table, etc.
Also it is not very useful when we have already cemented the relationship between the two tables using a Foreign Key.
To access a related fields data is very easy in Django. Suppose we have an instance of DetallePedidoCliente named instance using this we can access the fecha_entrega of the related model by the foreign key as follows:
instance.pedido.fecha_entrega
If one just wants an easy way to refer to this field one may consider adding a property to the model:
class DetallePedidoCliente(DetallePedido):
comments = models.CharField(max_length=300, verbose_name="Comentarios")
precio_venta = models.DecimalField(max_digits=16, decimal_places=2, default = 0)
pedido = models.ForeignKey(PedidoCliente,on_delete=models.CASCADE)
#property
def fecha_entrega(self):
return self.pedido.fecha_entrega
Now we can simply access the field as:
instance.fecha_entrega

Reduce the headache on database when using ModelChoiceField

please I need your help how to reduce the database call when using ModelChoiceField as it requires a queryset and I have to use it three times separately with a model that is recursively foreign key on itself, the code is below:
ModelForm code in the init function
self.fields['category'] = forms.ModelChoiceField(queryset=queryset)
self.fields['super_category'] = forms.ModelChoiceField(queryset=)
self.fields['product_type'] = forms.ModelChoiceField(queryset=)
the model class:
class Category(ProjectBaseModel, AuditLogMixin):
parent_id = models.ForeignKey('self', related_name='children', blank=True, null=True, on_delete=models.CASCADE,verbose_name=_('Parent'))
what i tried to do is collect all ids of the desired categories in array and make only one filter queryset with them like the following:
category = auction.category
super_category = category.parent_id
product_type = super_category.parent_id
ids= [category.id,super_category.id,product_type.id]
queryset = Category.objects.filter(id__in=ids)
How to proceed with that solution

How do I check if two instances of a Django model are the same across a set of attributes and annotate a queryset accordingly?

My app has a model "OptimizationResult", where I store results from mathmatical optimization. The optimization distributes timeslots over projects. I need to indicate whether the current results is different from a recent result, based on a set of attributes (in particularly not the primary key)
The attribute optimization_run is a coutner for different runs
Project is a ForeignKey to the project.
By overwriting the __hash__ and __eq__ functions on the model I can compare the different instances by
OptimizationResults.objects.filter(proj = 1).filter(optimization_run =1).first() == OptimizationResults.objects.filter(proj = 1).filter(optimization_run = 2).first()
. But as I understand __eq__ and __hash__ are not available on the database.
How would I annotate the results accordingly? Something like
OptimizationResults.objects.filter(optimization_run = 2).annotate(same_as_before = Case(When(),default=False))
Edit
Added .first() to the code, to ensure that there is only one element.
class OptimizationResult(models.Model):
project = models.ForeignKey(project, on_delete=models.CASCADE)
request_weight = models.IntegerField()
periods_to_plan = models.IntegerField()
unscheduled_periods = models.IntegerField()
scheduled_periods = models.IntegerField()
start = models.DateField(null=True, blank=True, default=None)
end = models.DateField(null=True, blank=True, default=None)
pub_date = models.DateTimeField('Erstellungsdatum', auto_now_add=True, editable=False)
optimization_run= models.ForeignKey(OptimizationRun, on_delete=models.CASCADE)
I'd like to compore different entries on the basis of start and end.
Edit 2
My fruitless attempt with Subquery:
old = OptimizationResult.objects.filter(project=OuterRef('pk')).filter(optimization_run=19)
newest = OptimizationResult.objects.filter(project=OuterRef('pk')).filter(optimization_run=21)
Project.objects.annotate(changed = Subquery(newest.values('start')[:1])== Subquery(old.values('start')[:1]))
results in TypeError: QuerySet.annotate() received non-expression(s): False
We can use a subquery here, to make an annotation:
from django.db.models import Exists, OuterRef, Subquery, Q
to_exclude = {'pk', 'id', 'project', 'project_id', 'optimization_run', 'optimization_run_id'}
subquery = OptimizationResult.objects.filter(
project_id=OuterRef('project_id')
optimization_run=1,
**{f.name: OuterRef(f.name)
for f in OptimizationResult._meta.get_fields()
if f.name not in to_exclude
}
)
OptimizationResult.objects.filter(
optimization_run=2
).annotate(
are_same=Exist(subquery)
)
Here we will thus annotate all the OptimizationResults with an optimization_run=2, with an extra attribute .are_same that checks if there exists an OptimizationResult object for optimization_run=1 and for the same project_id, where all fields are the same, except the ones in the to_exclude set.

Django Form Automatically select first option if only one choice available

Is there an easy way to select the first option of a dropdown in a Django form, in cases where there is only one option available?
With easy I mean a solution that doesn't require defining an own widget, which would be quite repetitive to change in all our (model) forms.
Update because it seems like the initial question was unclear:
I want the initital option only to be selected if there is one option available. And the the way to do that is non-obvious to me, if the options are foreign key references to another model:
class Category(models.Model):
name = CharField(...)
class Post(models.Model):
category = ForeignKey(Category)
class PostForm(forms.ModelForm):
class Meta:
fields = '__all__'
[...]
Now I want the category field in the PostForm to be autoselected to the first category, if only one instance is present in the database and be -------- if there a two or more categories
What about using this :
Your_Dropdown = forms.TypedChoiceField(choices=your choises, initial='FIRST_OPTION')
As shown in documentation: Here
I don't think any explanation is required, have a look at following code
post_type_choices = (
('article', 'article'),
('tip', 'tip'),
('snippet', 'snippet'),
)
class Post(models.Model):
post_type = models.CharField(
max_length=10, choices=post_type_choices,default='article')
I did it in the get_form() like this:
def get_form(self, form_class=form_class):
form = super(WPWeekSubjectCreateView, self).get_form(form_class)
....
subjects = Subject.objects.filter(
schoolyear=schoolyear,
pk__in=subject_bearings,
lesson__teachers=teacher
).order_by('abbreviation').distinct()
form.fields['subject'].queryset = subjects
if subjects.count() == 1:
form.fields['subject'].initial = subjects.first()
return form

django-tables 2 M2M field not shown

I am trying to show a M2M field in a django-table2 as seen in Django-tables2: How to use accessor to bring in foreign columns? and Accessing related models with django-tables2
Using: foreigncolumn = tables.Column(accessor='foreignmodel.foreigncolumnname'), I only see a '--'...
# The models:
class Organism(models.Model):
species_name = models.CharField(max_length=200)
strain_name = models.CharField(max_length=200)
eukaryotic = models.BooleanField(default=True)
lipids = models.ManyToManyField('Lipid',blank=True)
class Lipid(models.Model):
lm_id = models.CharField(max_length=100)
common_name = models.CharField(max_length=100,blank=True)
category = models.CharField(max_length=100,blank=True)
#The tables
class OrganismTable(tables.Table):
name = tables.LinkColumn('catalog:organism-detail', text=lambda record: record.species_name, args=[A('pk')])
lp = tables.Column(accessor='Lipid.common_name')
class Meta:
model = Organism
sequence = ['name','lp']
exclude = ['id','species_name']
Any idea what I'm doing wrong?
This does not work so easily for ManyToManyFields because of the simple way Accessor works. You could display the repr of the related QuerySet via 'lipids.all' but that does not seem sufficient here. You can, however, add a property (or method) to your Organism model and use it in the accessor. This way, you can display any custom information related to the instance:
class Organism(models.Model):
# ...
#property
def lipid_names(self):
return ', '.join(l.common_name for l in self.lipids.all()) # or similar
class OrganismTable(tables.Table):
# ...
lp = tables.Column(accessor='lipid_names')
I would recommend then to add a prefetch_related('lipids') to the Organism QuerySet that you pass to the table for better performance.

Categories