I'm trying to update field in my models with the newly calculated value from my view and when I try to update my field using total.objects.update(total=total) this is what i get 'decimal.Decimal' object has no attribute 'objects'.
I also have some other questions, I'm currently calculating the total field from initial values inputted when the item is created, using the save() method. is this a good idea ? or is there a better way of doing this? the reason I'm currently doing this is because i display the a list of items with their initial values.
Over all I'm trying to make a tools inventory system. I also have some other concerns.
How can I use this view on multiple items types? the model items is an abstract model that contains all common fields,and every tool type inherits this model and will be using the same operations, calculate the new cantidad_existente and update the total fields. Is there a better way?
my views.py
def calcular_nueva_cantidad(ce, up):
total = ce + up
return total
class updateForm(forms.Form):
update = forms.IntegerField()
def actualizar_cantidad(request, pk):
# trae de la base de datos el valor de la cantidad existente
cantidad_existente = Cortadores.objects.filter(pk=pk).values('cantidad_existente')
c = cantidad_existente.values_list('cantidad_existente', flat=True)
ce= c[0]
# trae de la base de datos el valor de precio_unitario
precio_unitario = Cortadores.objects.filter(pk=pk).values('precio_unitario')
p = precio_unitario.values_list('precio_unitario', flat=True)
pu =p[0]
# trae de la base de datos el valor de la total
total = Cortadores.objects.filter(pk=pk).values('total')
print(F'el precio unitario es {total} ----------------------------------------------------')
if request.method =='POST':
form = updateForm(request.POST)
if form.is_valid():
up = form.cleaned_data['update']
nce = calcular_nueva_cantidad(up, ce)
total = nce * pu
print(F' el nuevo total es {total} -----------------------')
# nce.save()
cantidad_existente.update(cantidad_existente=nce)
total.objects.update(total=total)
return render(request, 'inventario/cortadores.html', {'nce':nce})
else:
# Redirect to fail page after POST
return HttpResponse('')
else:
form = updateForm()
return render(request, 'inventario/update-cortador.html', {'form':form, 'cantidad_existente':cantidad_existente })
my models.py
class Item(models.Model):
description = models.CharField(max_length=30,)
numero_parte = models.CharField(max_length=30)
proveedor = models.ForeignKey(Proveedor, on_delete=models.CASCADE)
cantidad_existente = models.PositiveIntegerField()
update = models.PositiveIntegerField(blank=True, default=0)
cantidad_minima = models.PositiveIntegerField()
precio_unitario = models.DecimalField(max_digits=5, decimal_places=2)
total = models.FloatField(blank=True)
asignado_a = models.ForeignKey(Empleados, on_delete=models.CASCADE, blank=True, null=True)
anaquel = models.CharField(max_length=2, choices=ANAQUEL, blank=True, null=True)
posicion_en_x = models.CharField(max_length=2, blank=True, null=True)
posicion_en_y = models.CharField(max_length=2, blank=True, null=True)
activo = models.BooleanField()
class Meta:
abstract = True
def save(self,*args,**kwargs):
self.total = self.cantidad_existente * self.precio_unitario
super().save(*args,**kwargs)
class Cortadores(Item):
tipo = models.ForeignKey(Tipos_Cortadores,on_delete=models.CASCADE)
material = models.ForeignKey(Materiales, on_delete=models.CASCADE)
filos = models.CharField(max_length=5, choices=GABILANES)
diametro = models.ForeignKey(Diametros, on_delete=models.CASCADE)
longitud = models.ForeignKey(Longitud, on_delete=models.CASCADE)
desbaste = models.CharField(max_length=1, choices=DESBASTE)
class Meta:
verbose_name_plural = "Cortadores"
def get_absolute_url(self):
return reverse('inventario:cortadores-list', kwargs={'id': self.id})
def __str__(self):
return '%s %s %s %s %s %s' % ( str(self.tipo), str(self.material), str(self.filos), str(self.diametro),
self.longitud, self.desbaste
)
The error is that you have two variables called total. Just rename one of them.
total = Cortadores.objects.filter(pk=pk).values('total')
...
new_value = nce * pu
total.objects.update(total=new_value)
There is a error, you changing you queryset to flaot value, and then trying to use queryset functions on it, so you should use other variable in total and not your own queryset
total = Cortadores.objects.filter(pk=pk).values('total')
total = nce * pu // This line replace your queryset to float
total.objects.update(total=total)
You should use something like that
qs_total = Cortadores.objects.filter(pk=pk).values('total')
total = calcular_nuevo_total(nce, pu)
for value in qs_total:
value.total=total
value.save()
To use it as generic like you want use pass the class reference as parameter and use it to call your query set
def something(__class__):
class.objects.all()
EDIT: Making a generic method to use with any class
from .models import Cortadores, OtherModelExample
def generic_update_noreturn(__class__, pk, total)
qs= __class__.objects.filter(pk=pk).values('total')
for value in qs:
value.total=total
value.save()
return qs
def generic_update_noreturn(__class__, pk, total)
__class__.objects.filter(pk=pk).values('total')update(total=total)
def actualizar_cantidad(request, pk):
...
total = calcular_nuevo_total(nce, pu)
updated_cortadores=generic_update(Cortadores, pk, total)
updated_otherexample=generic_update(OtherModelExample, total, pu)
generic_update_noreturn(Cortadores, pk, total)
Related
How can I pass the foreign key values from my model to my serialised json object?
Now I have this three models,
class Fleet(models.Model):
fleet_id = models.IntegerField('Id flota', primary_key=True, unique=True)
fleet_name = models.CharField('Nombre flota', max_length=20, unique=True)
def __str__(self):
return self.fleet_name + ' ' + str(self.fleet_id)
class Device(models.Model):
dev_eui = models.CharField(max_length=16, primary_key=True, unique=True)
producer = models.CharField(max_length=20)
model = models.CharField(max_length=20)
dev_name = models.CharField(max_length=20, unique=True)
fleet_id = models.ForeignKey(Fleet, on_delete=models.CASCADE)
def __str__(self):
return self.dev_eui
class DevData(models.Model):
data_uuid = models.UUIDField(primary_key=True, default=uuid.uuid1, editable=False)
frequency = models.IntegerField()
data_1 = models.FloatField()
data_2 = models.FloatField(null=True, blank=True)
dev_eui = models.ForeignKey(Device, on_delete=models.CASCADE) #hay que saber porque añade _id
def __str__(self):
return self.dev_eui
And what I'm doing is call my view function in my JS code to obtain some data like this.
def getData(request):
ctx = {}
if request.method == 'POST':
select = int(request.POST['Select'])
data = DevData.objects.order_by('dev_eui','-data_timestamp').distinct('dev_eui')
nodes = Device.objects.all()
fleets = Fleet.objects.all()
data = loads(serializers.serialize('json', data))
nodes = loads(serializers.serialize('json', nodes))
fleets = loads(serializers.serialize('json', fleets))
ctx = {'Data':data, 'Nodes':nodes, 'Fleets':fleets}
return JsonResponse(ctx)
And inside my js file I filter it with some if else conditionals.
This works well, but I'm sure I can do it directly in my view but I don't know how. How can I obtain just one JSON object with the three models information combined?
Thank you very much!!
You can write a custom serializer like this:
from django.core.serializers.json import Serializer
class CustomSerializer(Serializer):
def end_object(self, obj):
for field in self.selected_fields:
if field == 'pk':
continue
elif field in self._current.keys():
continue
else:
try:
if '__' in field:
fields = field.split('__')
value = obj
for f in fields:
value = getattr(value, f)
if value != obj and isinstance(value, JSON_ALLOWED_OBJECTS) or value == None:
self._current[field] = value
except AttributeError:
pass
super(CustomSerializer, self).end_object(obj)
Then use it like this
serializers = CustomSerializer()
queryset = DevData.objects.all()
data = serializers.serialize(queryset, fields=('data_uuid', 'dev_eui__dev_eui', 'dev_eui__fleet_id__fleet_name'))
I have wrote an article regarding serializing nested data here. You can check that out as well.
I'm developing a django app to keep track of orders and products in my laboratory. I have an Order model that I create instances from with a form that fills some of its fields (but not all) and creates an object.
I've also created an UpdateForm to update the blank fields once the order arrives to the lab. This update form has just one field (storage location), but I want this form to automatically set the status of the order to "received" and populate the "received_by" field with the logged user and "received_date" with the dateTime when the form is sent..
While writing this I just thought I could create a different model for Receive and relate it to the Order model via OnetoOne, would that be a proper solution?
How my code looks like:
#models.py-------------------------------------------------------------
class Pedido(models.Model):
nombre = models.CharField(max_length=40, help_text=_('Nombre del producto.'))
referencia = models.CharField(max_length=20, help_text=_('Referencia del fabricante.'))
cpm = models.CharField(max_length=20, default ='A la espera.',help_text=_('Código del CPM asignado a este pedido.'), null = True, blank = True, verbose_name = _('CPM'))
fecha = models.DateTimeField(auto_now_add=True)
unidades = models.IntegerField(default = 1)
usuario = models.ForeignKey(User, on_delete=models.CASCADE, blank = True)
autogestion = models.BooleanField(default = False, verbose_name='Autogestión', help_text = _("Marca esta casilla si vas a procesar tu mismo el pedido."))
usuario_recepcion = models.ForeignKey(User, on_delete=models.CASCADE, null=True, blank=True, related_name='recepcion')
fecha_recepcion = models.DateTimeField(blank=True, null=True)
ESTADO_PEDIDO = (
('n', _('Pendiente')),
('p', _('Proforma solicitada')),
('c', _('CPM solicitado')),
('v', _('Para validar')),
('r', _('Recibido'))
)
estado = models.CharField(
max_length=1,
choices=ESTADO_PEDIDO,
blank=False,
default='n',
help_text=_('Estado del pedido'),
)
fabricante = models.ForeignKey('Fabricante', null = True, on_delete=models.SET_NULL)
centro_gasto = models.ForeignKey('CentroGasto', null = True, on_delete=models.SET_NULL, verbose_name = _('Centro de Gasto'))
almacen = models.ForeignKey('Almacen', null = True, on_delete=models.SET_NULL, blank = True)
direccion = models.ForeignKey('Direccion', default = 'CIBM', null = True, on_delete=models.SET_NULL, verbose_name = _('Dirección de entrega'))
codigo = models.CharField(max_length=20, blank=True, default=keygen())
#views.py----------------------------------------------------------
class PedidoListView(LoginRequiredMixin, generic.ListView):
model = Pedido
ordering = ['-fecha']
class PedidoDetailView(LoginRequiredMixin, generic.DetailView):
model = Pedido
#login_required
def Guia(request):
return render(request, 'guia.html')
#login_required
def add_pedido(request):
if request.method == "POST":
form = PedidoForm(request.POST)
if form.is_valid():
model_instance = form.save(commit=False)
model_instance.usuario = request.user
model_instance.save()
return redirect('/')
else:
form = PedidoForm()
return render(request, "nuevo_pedido.html", {'form': form})
class RecepcionUpdate(LoginRequiredMixin, UpdateView):
model = Pedido
fields = ['almacen']
template_name_suffix = '_recepcionar'
#forms.py-----------------------------------------------------------------
class PedidoForm(ModelForm):
def clean_usuario(self):
if not self.cleaned_data['usuario']:
return User()
return self.cleaned_data['user']
class Meta:
model = Pedido
exclude = ['codigo', 'fecha', 'cpm', 'almacen', 'estado', 'usuario']
If you are trying to change predefined class in Django, it's always possible to overwrite it. For example, you could extend the form_valid method:
class RecepcionUpdate(LoginRequiredMixin, generic.UpdateView):
model = Pedido
fields = ['almacen']
template_name_suffix = '_recepcionar'
def form_valid(self, form):
instance = form.save(commit=False)
instance.user = self.request.user
super(RecepcionUpdate, self).save(form)
Note: I have not tested this, it is probable that instead of calling super().save(form) you should return super().form_valid(form). Anyways, I'm sure that with this example you'll be able to find plenty of code snippets matching your Django version.
Guys I want to create a tools inventory app.
I have this method that will do the exact same thing on all tools types. What I want to know is how can I use this method dynamically selecting what models to use (maybe how to pass a model class as an argument).
It's currently working only for one type of tool. My models.py has an abstract model that has all common fields for all tools and then various models that inherit it for tool specific fields (e.i. End mills, Drill-bits, pliers, screwdrivers, etc all inherit common filed from my abstract model).
def calcular_nueva_cantidad(ce, up, get_link):
if get_link == 'incremento':
total = ce + up
else:
total = -(ce - up)
return total
def calcular_nuevo_total(nce, pu):
total = nce * pu
return total
# crea el formulario para la actualizacion de cantidad existente
class updateForm(forms.Form):
update = forms.IntegerField()
def actualizar_cantidad(request, pk, model ):
# trae de la base de datos el valor de la cantidad_existente
cantidad_existente = model.objects.filter(pk=pk).values('cantidad_existente')
c = cantidad_existente.values_list('cantidad_existente', flat=True)
ce = c[0]
# trae de la base de datos el valor de la precio_unitario
precio_unitario = model.objects.filter(pk=pk).values('precio_unitario')
p = precio_unitario.values_list('precio_unitario', flat=True)
pu = p[0]
# trae de la base de datos el valor de la total
qs_total = model.objects.filter(pk=pk).values('total')
if request.method =='POST':
form = updateForm(request.POST)
if form.is_valid():
# Obtiene el name de urls para el link segun sea el caso
get_link = resolve(request.path_info).url_name
get_linkwargs = resolve(request.path_info).kwargs
print(F'========>{get_link, get_linkwargs }<=========')
up = form.cleaned_data['update']
# Calcula el nuevo valor de cantidad existente
nce = calcular_nueva_cantidad(up, ce, get_link)
# Actualiza la nueva cantidad existente
cantidad_existente.update(cantidad_existente=nce)
# Calcula el nuevo valor de cantidad existente
s_total = calcular_nuevo_total(nce, pu)
# Actualiza la nueva cantidad existente
qs_total.update(total=s_total)
# Obteiene item id del tipo de cortador asi puede regresar a la pantalla del listado
pp = model.objects.filter(pk=pk).values('tipo')
ppp = pp.values_list('tipo', flat=True)
pk = ppp[0]
return HttpResponseRedirect(reverse('inventario:cortadores-list', args=(pk, )))
else:
# Redirect to fail page after POST
return HttpResponse('')
else:
form = updateForm()
return render(request, 'inventario/update.html', {'form':form})
This is my abstract class in my models.py
class Item(models.Model):
description = models.CharField(max_length=30,)
numero_parte = models.CharField(max_length=30)
proveedor = models.ForeignKey(Proveedor, on_delete=models.CASCADE)
cantidad_existente = models.PositiveIntegerField()
update = models.PositiveIntegerField(blank=True, default=0)
cantidad_minima = models.PositiveIntegerField()
precio_unitario = models.DecimalField(max_digits=7, decimal_places=2)
total = models.DecimalField(max_digits=7, decimal_places=2, blank=True)
asignado_a = models.ForeignKey(Empleados, on_delete=models.CASCADE, blank=True, null=True)
anaquel = models.CharField(max_length=2, choices=ANAQUEL, blank=True, null=True)
posicion_en_x = models.CharField(max_length=2, blank=True, null=True)
posicion_en_y = models.CharField(max_length=2, blank=True, null=True)
activo = models.BooleanField()
class Meta:
abstract = True
def save(self,*args,**kwargs):
self.total = self.cantidad_existente * self.precio_unitario
super().save(*args,**kwargs)
These two classes inherit from Item
class Cortadores(Item):
tipo = models.ForeignKey(Tipos_Cortadores,on_delete=models.CASCADE)
material = models.ForeignKey(Materiales, on_delete=models.CASCADE)
filos = models.CharField(max_length=5, choices=GABILANES)
diametro = models.ForeignKey(Diametros, on_delete=models.CASCADE)
longitud = models.ForeignKey(Longitud, on_delete=models.CASCADE)
desbaste = models.CharField(max_length=1, choices=DESBASTE)
class Meta:
verbose_name_plural = "Cortadores"
def get_absolute_url(self):
return reverse('inventario:cortadores-list', kwargs={'id': self.tipo.id})
def __str__(self):
return '%s %s %s %s %s %s' % ( str(self.tipo), str(self.material), str(self.filos), str(self.diametro),
self.longitud, self.desbaste
)
class Tornillos(Item):
tipo = models.CharField(max_length=10, choices=TIPO_TORNILLO)
paso = models.ForeignKey(Paso_Tornillo, on_delete=models.CASCADE)
material = models.ForeignKey(Materiales, on_delete=models.CASCADE)
longitud = models.ForeignKey(Longitud, on_delete=models.CASCADE)
class Meta:
verbose_name_plural = "Tornillos"
def get_absolute_url(self):
return reverse('inventario:lista-herramientas-mecanicas')#, kwargs={'pk': self.pk})
def __str__(self):
return '%s %s %s %s' % (str(self.tipo), str(self.paso), str(self.material), str(self.longitud))
I made a class for every tool type that I own. I only included these two classes for simplicity and not fill the post with a lot of code.
If you still can change the design of your tables, you could use multi-table-inheritance instead of the abstract-base-class you are using now.
That would mean that you will have one model Item (which will be an actual database table) and then other models that inherit from this model (their database tables will only hold the new fields, but not repeat any fields).
For that change you only need to remove abstract = True from Item.Meta; you should not need to change other parts form your models. Of course, you will have to drop your tables and run migrations again (will destroy your current data).
As I said, this is only an option if you can still change your database tables significantly.
With this setup, you can query your Item model directly for the common fields. There are some subtleties you have to be careful about, but read the docs I linked to see if it solves your issue.
I'm trying to a save a foreign key inside an object into my db using a form, but i get the error : 'Syntax isn't valid for integer', I discovered that postgreSQL save the foreign key as an id, how can i save it then?
Here it is my code.
Models.py :
class treballador(models.Model):
nom = models.CharField(max_length=150, null=False, unique=True)
cognom = models.CharField(max_length=150, null=False)
tipusDocID = models.CharField(max_length=3, choices=TIPUSDOC, null=False)
docId = models.CharField(max_length=9, null=False)
tlf_regex = RegexValidator(regex=r'^\d{9,9}$',message="Phone number must be entered in the format: '+999999999'. Up to 9 digits allowed.")
tlf = models.CharField(validators=[tlf_regex], blank=True, max_length=9) # validators should be a list
correu = models.EmailField(max_length=254)
ciutat = models.CharField(max_length=150)
dataDAlta = models.DateTimeField(auto_now_add=True)
def __unicode__(self):
return unicode(self.nom) or unicode(self.id)
class despesa(models.Model):
nomTreballador = models.ForeignKey(treballador, to_field='nom')
tipusDeGast = models.CharField(max_length=3, choices=GASTOS)
quantia = models.DecimalField(max_digits=5, decimal_places=2)
data = models.DateTimeField()
forms.py:
class desModelForm(forms.ModelForm):
data = forms.DateField(widget=DateInput(format='%d/%m/%Y'), label="Data de la despesa", input_formats=['%d/%m/%Y'])
class Meta:
model= despesa
fields= ["nomTreballador","tipusDeGast","quantia","data"]
def clean_despesa(self):
despeses = self.cleaned_data.get("tipusDeGast")
return despeses
def clean_date(self):
date = self.cleaned_data.get("data")
return date
def clean_quantia(self):
quantia = self.cleaned_data.get("quantia")
return quantia
def clean_nom(self):
nomTreballador = self.cleaned_data.get("nomTreballador")
return nomTreballador
def __init__(self, *args, **kwargs):
super(desModelForm, self).__init__(*args, **kwargs)
self.fields["nomTreballador"].queryset=treballador.objects.all().distinct()
views.py:
def home(request):
form = desModelForm(request.POST or None)
context = {
"gast_form": form
}
if form.is_valid():
desp = form.save(commit=False)
desp.save()
return render(request, "imputacioDespeses.html", context)
Your foreign key field is the problem.
Remove to_field and Django will automatically map it to ID
nomTreballador = models.ForeignKey(treballador)
Remove to_field='nom' from the nomTreballador ForeignKey field and it will insert the Treballador's primary key (an integer) instead of nom (which is a string).
first im so sorry with my english, im new with Django, im from php + codeigniter.
I have a problem with a related_name, the tables are fine, but the problem is that in the Select (DropDown) the data display is "bad", in this way: Tarifas_object:
Html code:
<option value="1">Tarifas object</option>
how ill display the correct data?
my model:
class Tarifas(models.Model):
recarga = models.CharField(max_length=7, help_text='Codigo de la tarifa')
precio = models.DecimalField(max_digits=7, decimal_places=2)
diligencias = models.PositiveIntegerField(max_length=3)
def __inicode__(self):
return self.precio
class Meta:
verbose_name_plural="Tarifas"
class Recarga(models.Model):
socio = models.ForeignKey(User)
fecha = models.DateField(auto_now_add=True)
#valor = models.DecimalField(max_digits=6, decimal_places=2,verbose_name='Valor de la recarga', help_text= "Introduzca valores numericos ej.: 150.00")
valor = models.ForeignKey(Tarifas, related_name='recarga_valor')
diligencias = models.IntegerField(max_length=3, verbose_name='Cantidad de diligencias recargadas')
tiponcf = models.IntegerField(max_length=1,choices=TIPO_NCF, verbose_name='Tipo de comprobante fiscal')
ncf = models.CharField(max_length=19,verbose_name='Numero de comprobante fiscal')
cajero = models.CharField(max_length=20)
tipotarj = models.CharField(choices=TIPOS_TARJETAS, max_length=20, verbose_name='Tipo de tarjeta')
numtarj = models.IntegerField(max_length=16, verbose_name='Numero de tarjeta')
seguridad = models.IntegerField(max_length=3)
forma_pago = models.CharField(max_length=10, verbose_name='Forma de pago')
banco = models.CharField(max_length=20)
numerock = models.IntegerField(max_length=8, verbose_name='Numero de cheque')
def __unicode__(self):
return u'%s %s %s %s' % (self.socio,self.diligencias, self.fecha)
class Meta:
ordering = ['socio']
Thanks guys.
If that's the straight copy and paste from your model, you've misspelled unicode on the Tarifas model.