how to update another field on admin django - django

models.py
Good night friends, I would like to know if there is a possibility that every time I register a new move, the django administrator checks what is a 'hydrographic region' and adds the value that is entering with the 'balance_box'.
class Movement(models.Model):
TYPE_MOVE = (
('1', 'Receita'),
('2', 'Despesa'),
)
regiao_hidrografica = models.ForeignKey(RegiaoHidrografica, verbose_name="Região Hidrografica", null=False)
origem = models.ForeignKey(Origem, verbose_name="Origem", null=False)
finalidade_recurso = models.ForeignKey(FinalidadeRecursos, verbose_name="Finalidade de Recursos", null=True)
descricao = models.TextField("Descrição", null=True)
valor = MoneyField(max_digits=10, decimal_places=2, default_currency='BRL')
data_refencia = MonthField("Data de Referencia", help_text="Informe mês e ano")
# data_refencia = models.DateField("Data de Referencia", null=True, blank=True, default=None)
tipo_movimento = models.CharField(max_length=1, default=1, choices=TYPE_MOVE)
def __str__(self):
return self.descricao
def update_total_valor(self):
total = 0
self.movimento_set:
total += mov.valor
self.saldo_caixa = total
self.save()
class RegiaoHidrografica(models.Model):
name = models.CharField("Nome", max_length=100, null=False)
sigla = models.CharField("Sigla", max_length=10, null=True)
taxa_inea = models.IntegerField(default=10, null=True)
taxa_trans = models.IntegerField(default=0, null=True)
saldo_caixa = MoneyField('Saldo em caixa estimado', max_digits=10, decimal_places=2, null=True, default=0, default_currency='BRL')
saldo_cc = MoneyField('Saldo em conta estimado', max_digits=10, decimal_places=2, null=True, default=0, default_currency='BRL')
def __str__(self):
return self.name
I tried something like this, create this method in the 'class MovimentoAdmin(admin.ModelAdmin)', but it did not work.
admin.py
def save_formset(self, request, form, formset, change):
instances = formset.save(commit=False)
for instance in instances:
instance.save()
formset.save_m2m()
instance.RegiaoHidrografica.update_total_valor()
Would anyone have a hint how I could do this?

Sounds to me like you need Django Signals.
You can register a listener on the post_save signal for your model Movement. The listener then would check for changes (it can also detect object creation with the parameter created) and react accordingly.
However, this would not only apply to Django Administrator but rather to all positions in your code where a Movement object got created. If you only create those objects via the admin site you are fine.
Otherwise, consider overwriting the Django ModelAdmin.save_model method:
Example in Django documentation. This method also provides you with the ability to detect object creation as well.
If you really want to use the save_formset method instead, check your code. update_total_valor is defined in and for class Movement and not RegiaoHidrografica according to your snippet, the method in admin.py is defined on Movement (which is fine, but then your access to RegiaoHidrografica looks wrong to me, since you are trying to access a class name instead of the model property).
I recommend to work with Django signals here, they provide a ton of comfort (but also have a trade-off: Added processing time when saving an object...

Related

Django viewflow running queries in a custom node

I am trying to adapt the Viewflow Dynamicsplit example
The objective is to split approvals of an Order based on OrderLines and to assign them to the appropriate approver. It seems that this should be possible as there seems to be a possibility described in this answer - Assign user to tasks automatically (Viewflow, Django)
The issue is that whenever I try to grab the current order pk in the DynamicSplitActivation - the queryset comes back empty. Not sure where I am going wrong. The queryset works fine if I set the pk manually, but as soon as I try to use a dynamic variable it stops working.
I have listed the flow and models etc. at the end of the post, however, I am guessing the issue is quite basic. Any help would be appreciated!
nodes.py
...
class DynamicSplitActivation(AbstractGateActivation):
def calculate_next(self):
self._order = self.flow_task._order_callback(self.process)
order_id = self._order.pk
# order_id = 28
order_lines = models.OrderLine.objects.filter(order_id=order_id)
project_lines = project_models.ProjectLine.objects.filter(orderline__in=order_lines)
users = User.objects.filter(projectline__in=project_lines).distinct()
self._approvers = users
...
class DynamicSplit(...):
...
def __init__(self, callback):
super(DynamicSplit, self).__init__()
self._order_callback = callback
self._ifnone_next_node = None
...
flows.py
...
approval_split = (
nodes.DynamicSplit(lambda act: act.order)
.IfNone(this.end)
.Next(this.split_approval_budget)
)
models.py
...
class ProjectLine(models.Model):
project = models.ForeignKey(Project, on_delete=models.CASCADE)
description = models.CharField(max_length=50)
budget_holder = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.SET_NULL, null=True, blank=True)
class Order(models.Model):
description = models.CharField(max_length=30)
class OrderLine(models.Model):
order = models.ForeignKey(Order, on_delete=models.CASCADE)
project_line = models.ForeignKey(project_models.ProjectLine, on_delete=models.SET_NULL, null=True, blank=False)
product = models.ForeignKey(catalogue_models.Product, on_delete=models.CASCADE)
quantity = models.PositiveIntegerField()
budgetholder_approved = models.BooleanField(null=True)
class OrderProccess(Process):
order = models.ForeignKey(Order, blank=True, null=True, on_delete=models.CASCADE)
...

How to use a ManyToMany field in django with a through model, displaying it and saving it?

I am doing a basic system in Django for a Spa that requires me to have an inventory, massages that use different quantities of product in the inventory, and then a service which will be a combination of multiple massages. So the user of the spa, which is the staff, will be able to create a service, select which massages make that service, and that will instantly trigger the subtraction of that product from the inventory. I used a many to many relation to relate the massages and the items, with a through model to save the amount used as well. My question is, what would be the best way to display this in a form so the staff can add new massages in a way where they can choose many items and their respective quantity that the massage will use? And how can i save all of this afterwards into the DB? I'm using PostgreSQL. This is how my models look right now:
class Producto(models.Model):
nombre = models.CharField(max_length=200, blank=False)
línea = models.CharField(max_length=200, blank=False)
proveedor = models.CharField(max_length=200, blank=False)
costo_mxn = models.DecimalField(blank=False, max_digits=10, decimal_places=2)
unidad_de_medición_choices = [
("g", "g"),
("mL", "mL"),
("oz", "oz"),
]
unidad_de_medición = models.CharField(max_length=20, choices=unidad_de_medición_choices,null=True, blank=True)
cantidad_actual = models.DecimalField(blank=False, max_digits=10, decimal_places=2)
cantidad_inicial = models.DecimalField(blank=False, max_digits=10, decimal_places=2)
cantidad_alerta = models.DecimalField(blank=False, max_digits=10, decimal_places=2)
fecha_de_registro = models.DateField(blank=True,null=True,default= datetime.today)
def __str__(self):
return self.nombre
class Masaje(models.Model):
nombre = models.CharField(max_length=200, blank=False)
productos = models.ManyToManyField(Producto, through='CantidadProducto',blank=True)
costo = models.DecimalField(blank=False, max_digits=10, decimal_places=2)
duracion = models.DurationField()
descripcion = models.TextField(
max_length=500, blank=True, null=True
)
class CantidadProducto(models.Model):
masaje = models.ForeignKey(Masaje,on_delete=models.CASCADE)
producto = models.ForeignKey(Producto,on_delete=models.CASCADE)
cantidad_usada = models.DecimalField(blank=False, max_digits=10, decimal_places=2)
Now I've been using simple forms to display other parts of the system that I've done that aren't as complex, for example the masseuse, like this:
class MasajistaForm(ModelForm):
class Meta:
model = Masajista
fields = (
'nombre',
'telefono_celular',
'fecha_de_nacimiento',
)
widgets = {
'nombre': forms.TextInput(attrs={'class':''}),
'telefono_celular': forms.TextInput(attrs={'class':''}),
'fecha_de_nacimiento': forms.SelectDateWidget(years=range(1900, 2023),months = MONTHS,attrs={'class':''},empty_label=("Año", "Mes", "Dia"))
}
With a result like
this
Now, i know it doesn't look great but that's not the problem right now, I would like it so the staff can see a form like that where you could maybe hit a plus button or something like that where a new select box would appear with a selection of the already registered items, and an input box that could be filled by hand and then saved. What would be the way to go here?

Django - How to create a TableView out of many models that inherit same abstract class?

I'm trying to create a TableView that displays all objects in my project that inherit from the same abstract class. I know I may have needed to make the original class not abstract, but the project is already running and I'd rather not change the models now.
The abstract class is this:
class WarehouseBase(models.Model):
region = models.ForeignKey(Region, on_delete=models.PROTECT, null=True, blank=False, verbose_name='Región')
name = models.CharField(max_length=50, verbose_name='Nombre', unique=True)
class Meta:
abstract = True
And the classes that inherit from it are:
class SaleWarehouse(WarehouseBase):
TYPES = (
(0, 'Autotanque'),
(1, 'Estación de carburación')
)
type = models.IntegerField(choices=TYPES, null=False, blank=False, verbose_name='Tipo')
# price = models.ForeignKey(SpecificPrice, on_delete=models.SET_NULL, null=True, blank=True, related_name='warehouse')
lat = models.DecimalField(max_digits=9, decimal_places=6, null=True)
lng = models.DecimalField(max_digits=9, decimal_places=6, null=True)
price = models.FloatField(verbose_name='Precio', validators=[MinValueValidator(0.0), MaxValueValidator(1000.0)], null=True, blank=True)
price_date = models.DateField(verbose_name='Fecha de precio', null=True, blank=True, auto_now_add=True)
def __str__(self):
return '{} - {}'.format(str(self.pk), self.name)
class GeneralWarehouse(WarehouseBase):
#property
def total_capacity(self):
capacity = 0.0
for tank in self.tanks:
capacity += tank.max_capacity
return capacity
def __str__(self):
return "Almacén general '{}'".format(self.name)
The new requirement for a view that enlists all warehouses was just added, but when the project was made this was not needed. I've been searching and I've found ways to change the database models so that I can make a queryset of WarehouseBase objects, but it would require many changes in the database that would be very dangerous now that several functionalities depend on those models.
Is there a way to just make the TableView display all SaleWarehouse and GeneralWarehouse objects, without changing the models?
you can create a list of objects or dictionary and add objects from both models , SaleWarehouse and GeneralWarehouse. This way you can combine data from both models in a single list without any changes to the database.

Django cannot access model in admin site

I was trying to adjust a DateField in one of my models to also show the time (DateTimeField). I ended up also making timezone adjustments. After all I decided to not use the time and deleted the additional code and set the field back to DateField. Migrations are made and migrated. Now when trying to access an object from the model either via the page or admin page I receive the error:
invalid literal for int() with base 10: b'24 22:00:00'
So after trying a few things I just wanted to delete the objects in the model using the admin page. This also resulted in the above error.
It seems every page relying on an object from that model throws the error.
Is there a way to force delete objects?
Can you recommend any other clean up methods?
The model is defined as:
class PieceInstance(models.Model):
id = models.UUIDField(primary_key=True, default=uuid.uuid4, help_text='Unique ID for this particular Piece across whole system')
piece = models.ForeignKey('Piece', on_delete=models.SET_NULL, null=True)
version = models.CharField(max_length=200)
date_claimed = models.DateField(null=True, blank=True)
claimant = models.ForeignKey(User, on_delete=models.SET_NULL, null=True, blank=True)
date_sent_to_claimant = models.DateField(null=True, blank=True)
PIECE_STATUS = (
('n', 'Not Claimable'),
('a', 'Available'),
('r', 'Reserved'),
('c', 'Claimed'),
)
status = models.CharField(
max_length=1,
choices=PIECE_STATUS,
blank=True,
default='a',
help_text='Piece Availability',
)
#property
def claimed_overdue(self):
days_till_claimed_overdue = 7
if self.date_claimed and date.today() > self.date_claimed + timedelta(days=days_till_claimed_overdue):
return True
return False
class Meta:
ordering = ['date_claimed']
permissions = (('can_mark_sent_to_claimant', 'Set Piece Instance as sent to claimant'),)
def __str__(self):
return f'{self.id} ({self.piece.title})'
Since my project is not big I decided to drop the whole database and set it up again from scratch.
I used the accepted answer of this question
Note that you also have to set up all users again (including the superuser)

Django Assign M2M after Saving

I'm working on a project in Django and I have the following problem:
I have these two classes, Team and Project. When I create one project I want to automatically assign users from the team what was selected when I created the Project to the new project.
I override Project's save method and after the project was created assign users to the project(I did after saving because, before gave me an error). I tried of several ways but none of them works.
Tried by:
self.user.add(*self.team.users.all())
self.save()
And this doesn't work.
Tried iterating:
for uTeam in self.team.users.all():
self.users.add(uTeam)
and doesn't work either.
The only way that work for me is this, but only in the Django Shell:
P = Project.objects.get(pk=1)
T = Team.objects.get(pk=1)
P.user.add(*T.user.all())
P.save()
This is the solution that I have below but doesn't work in Django(gives an infinite loop)
class Team(models.Model):
name = models.CharField(max_length=200,
help_text=_('name of the team'))
user = models.ManyToManyField(settings.AUTH_USER_MODEL,
related_name="members_of_team",
help_text=_('users of the team'),
null=True
)
and more....
class Project(models.Model):
id = models.AutoField(primary_key=True, null=False)
name = models.CharField(max_length=200,
help_text=_('name of project'),
)
team = models.ForeignKey(Team,`enter code here`
on_delete=models.PROTECT,
help_text=_('team of project'))
created_by = models.ForeignKey(settings.AUTH_USER_MODEL,
on_delete=models.PROTECT,
related_name='creator_project',
blank=True,
null=False,
help_text=_('project created by'))
customer = models.ForeignKey(Customer,
on_delete=models.PROTECT,
help_text=_('customer'))
user = models.ManyToManyField(settings.AUTH_USER_MODEL,
related_name='users_team',
blank=True,
null=False,
help_text=_('users of this project'))
def save(self, *args, **kwargs):
if self.checkIntegrity():
super(Project, self).save(*args, **kwargs)
if self.user.all().count() < self.team.user.all().count():
T = Team.objects.get(pk=self.team.id)
P = Project.objects.get(pk=self.id)
P.user.add(*T.user.all())
P.save()
Thank you for your help
I got it, I read that m2m fields are filled after save() and post_save() and there is a signal that trigger when a m2m field is changed so I write the following:
#receiver(m2m_changed, sender=Project.user.through)
def m2mChange(sender, **kwargs):
instance = kwargs['instance']
T = Team.objects.get(pk=instance.team.id)
if kwargs['pk_set'] is None:
instance.user.add(*T.user.all())
And now it works fine.
Thank you for all.