I'm writing an app that has an HTML page which must be capable of saving data into 2 models. I've created two separate forms and referenced them in the view, however the information is not saving into the DB.
Here are the views.py
def nuevoingreso(request):
if request.method == "POST":
formingreso = NuevoIngreso(request.POST)
formprodingreso = NuevoProdIngreso(request.POST)
if formingreso.is_valid():
ingreso = formingreso.save(commit=False)
ingreso.idUser = request.user
ingreso.Condominio = get_object_or_404(Condominios, idCondominio=request.session["idCondominio"])
ingreso.save()
ingresoprod = formprodingreso.save()
for i in range(5):
if ProductosIngresos.SubtotalP != "" and ProductosIngresos.IvaP != "" and ProductosIngresos.TotalP != "":
ingresoprod.ProductosIngresos(Concepto=request.POST.get("Concepto"+str(i), ""), SubtotalP=request.POST.get("SubtotalP"+str(i), ""), IvaP=request.POST.get("IvaP"+str(i), ""), TotalP=request.POST.get("TotalP"+str(i), ""))
ingresoprod.save()
return HttpResponseRedirect("/propiedades/")
else:
return render(request, "immovelc/nuevoingreso.html",
{"formingreso": formingreso, "formprodingreso": formprodingreso})
propiedadesing = PropiedadesCond.objects.all()
context = ({"propiedadesing": propiedadesing})
return render(request, "immovelc/nuevoingreso.html", context)
forms.py
class NuevoIngreso(ModelForm):
class Meta:
model = Ingresos
fields = ["Numero", "Persona", "Fecha", "Observaciones", "Cobrado", "Subtotal", "Iva", "Total"]
def clean(self):
Numero = self.cleaned_data["Numero"]
Persona = self.cleaned_data["Persona"]
Fecha = self.cleaned_data["Fecha"]
if not Numero:
raise forms.ValidationError("El campo de numero es obligatorio")
if not Persona:
raise forms.ValidationError("El campo de cliente es obligatorio")
if not Fecha:
raise forms.ValidationError("El campo de fecha es obligatorio")
class NuevoProdIngreso(ModelForm):
class Meta:
model = ProductosIngresos
fields = ["Concepto", "SubtotalP", "IvaP", "TotalP"]
models.py
class Ingresos(models.Model):
idIngreso = models.AutoField(primary_key=True, null=False, max_length=15)
idCondominio = models.ForeignKey(Condominios)
idUser = models.ForeignKey(User)
Numero = models.CharField(max_length=100)
Persona = models.CharField(max_length=250, default="Ninguno")
Cobrado = models.CharField(max_length=100, default=0)
Observaciones = models.TextField(default="Ninguna")
Fecha = models.DateField()
Subtotal = models.CharField(max_length=100)
Iva = models.CharField(max_length=100)
Total = models.CharField(max_length=100)
def __unicode__(self):
return unicode(self.idIngreso)
class ProductosIngresos(models.Model):
idProductoIngreso = models.AutoField(primary_key=True, null=False, max_length=15)
idIngreso = models.ForeignKey(Ingresos)
Concepto = models.CharField(max_length=500)
SubtotalP = models.CharField(max_length=100)
IvaP = models.CharField(max_length=100)
TotalP = models.CharField(max_length=100)
def __unicode__(self):
return unicode(self.idProductoIngreso)
Thanks!
No offence, but this code is far from being correct.
Besides you've got many errors that you might want to remove.
Errors:
formprodingreso.is_valid() is never called
inside for i in range(5) you use a class as if it was an instance (ProductosIngresos.SubtotalP)
clean method in form has to be outside the Meta block
I believe what you want inside the loop is:
producto_ingreso = ProductosIngresos()
producto_ingreso.idIngreso = ingreso # better change to producto_ingreso.ingreso
producto_ingreso.Concepto=request.POST.get("Concepto"+str(i), "") # producto_ingreso.concepto
producto_ingreso.SubtotalP=request.POST.get("SubtotalP"+str(i), "") # producto_ingreso.subtotal_p
producto_ingreso.IvaP=request.POST.get("IvaP"+str(i), "")
producto_ingreso.TotalP=request.POST.get("TotalP"+str(i), ""))
producto_ingreso.save()
To make it cleaner, you can make this king of logic overridding the save() method of ModelForm. Or use inline formsets.
Confusion:
Model FKs are objects in Django, not integers. Better name them like condominio instead of idCondominio
Decimal columns (subtotal, iva, total) should be declared as deciaml i.e. models.DecimalField(max_digits=10, decimal_places=2)
clean method is intended for cross field validation (more than one field). Only one field should be validated by clean_numero f.e.
Over complication:
models have ID/PK by default, no need to explicit them (referenced as self.id or self.pk)
model unicode function is not giving any info
clean and ValidationError are superflous: modelform checks if attributes are requiered automatically
Convention errors:
attributes are always written_in_lowercase (SubtotalP -> subtotal_p)
I would seriously try to fix all of those if you dont want the developers maintaining your code hate you and make some voodoo on you.
Related
I would like to know how to get data when I am using a foreign key. I mean, I have a many-to-one relation, but when I get data I don’t receive the response how I would like it.
class AsigManager(models.Manager):
def get_by_natural_key(self, Nom_Asig, horario):
return self.get(Nom_Asig=Nom_Asig, horario=horario)
class ProfManager(models.Manager):
def get_by_natural_key(self, Nombre, profesion):
return self.get(Nombre=Nombre, profesion=profesion)
class Asignatura(models.Model):
Nom_Asig = models.CharField(max_length=200)
horario = models.CharField(max_length=200)
objects = AsigManager()
class Meta:
unique_together = [['Nom_Asig', 'horario']]
class Profesor(models.Model):
asignatura = models.ForeignKey(Asignatura, on_delete=models.CASCADE)
Nombre = models.CharField(max_length=200)
profesion = models.CharField(max_length=200)
objects = AsigManager()
class Meta:
unique_together = [['Nombre', 'profesion']]
class ProfesorView(View):
def get(self, request):
profe = list(Profesor.objects.values())
if len(profe)>0:
datos = {'message':'Succes','Profesores: ':profe}
else:
datos = {'message':'Profesor Not Found...'}
return JsonResponse(datos)
But I would like to get the Asignatura data when I get the Professor data, such as an object or a list inside the Professor request.
I'm trying to build a webapp where the same task is given to all users, and when the users complete the task they can mark it as completed, to do so I added a 'status' bool that is set to true when the 'task' is not complete, and with a button the user can set it to false, the problem is that when I use a many-to-many field, if one user changes the 'status', it changes for everyone.
I also tried using a Foreignkey but when I use a Foreignkey I have to create a task for every user.
What I want is to create a task, assign it to all users, and then all the users can interact with the task without affecting what other users see.
These are the models that I created(it's in spanish):
class Usuario(AbstractUser):
pass
class Tps(models.Model):
users = models.ForeignKey(Usuario, on_delete=CASCADE)
titulo = models.CharField(max_length=100)
TECNOLOGIA_DE_LA_FABRICACION = 'TDF'
MANTENIMIENTO_Y_REPARACION_DE_EQUIPOS = 'MYRDE'
MAQUINAS_ELECTRICAS_Y_ENSAYOS = 'MEYE'
SEGURIDAD_E_HIGIENE_INDUSTRIAL = 'SEHI'
LABORATORIO_DE_ENSAYOS_INDUSTRIALES = 'LDEI'
INSTALACIONES_INDUSTRIALES = 'II'
RELACIONES_HUMANAS = 'RH'
TALLER_DE_ELECTROMECANICA = 'TE'
ORGANIZACION_INDUSTRIAL = 'OI'
INSTALACIONES_ELECTRICAS = 'IE'
EDUCACION_FISICA = 'EF'
EQUIPOS_Y_APARATOS_DE_MANIOBRA_Y_TRANSPORTE = 'EYADMYT'
MATERIAS_CHOICES = [
(TECNOLOGIA_DE_LA_FABRICACION, 'Tecnologia de la fabricación'),
(MANTENIMIENTO_Y_REPARACION_DE_EQUIPOS, 'Mantenimiento y R de equipos'),
(MAQUINAS_ELECTRICAS_Y_ENSAYOS, 'Máquinas eléctricas y ensayos'),
(SEGURIDAD_E_HIGIENE_INDUSTRIAL, 'Seguridad e higiene industrial'),
(LABORATORIO_DE_ENSAYOS_INDUSTRIALES,
'Laboratorio de ensayos industriales'),
(INSTALACIONES_INDUSTRIALES, 'Instalaciones industriales'),
(RELACIONES_HUMANAS, 'Relaciones humanas'),
(TALLER_DE_ELECTROMECANICA, 'Taller de electromecánica'),
(ORGANIZACION_INDUSTRIAL, 'Organización industrial'),
(INSTALACIONES_ELECTRICAS, 'Instalaciones eléctricas'),
(EDUCACION_FISICA, 'Educacion fisica'),
(EQUIPOS_Y_APARATOS_DE_MANIOBRA_Y_TRANSPORTE,
'Equipos y aparatos de maniobra y transporte')
]
materia = models.CharField(
max_length=8, choices=MATERIAS_CHOICES, default=None)
fecha_actual = models.DateField(default=timezone.now)
fecha_entrega = models.DateField(auto_now=False, auto_now_add=False)
material = models.URLField()
consignas = models.URLField()
status = models.BooleanField(default=True)
def __str__(self):
return self.titulo
I think you should use an intermediate table and make the relationship with the through attribute, so you could make a table like this:
class Tps(models.Model):
users = models.ForeignKey(Usuario, on_delete=CASCADE, through='TaskDone')
class TaskDone(models.Model):
user = models.ForeignKey(Usuario, on_delete=models.CASCADE)
tps = models.ForeignKey(Tps, on_delete=models.CASCADE)
status = models.BooleanField(default=True)
I'm working on this big project with Django and I have to update the database. I have to add another table which will replace another later.
So I want to add in a model the possibility to have a field where I can have either the old model OR the new one.
Here is the code of the old model:
class Harvests(models.Model):
ident_culture = models.IntegerField(primary_key=True)
intitule_culture = models.CharField(max_length=50, blank=True)
nom_fertiweb = models.CharField(max_length=50, blank=True, null = True)
affichage_quintaux_tonne = models.CharField(max_length=1,
choices=RENDEMENT_CHOICES, default = 'T')
type_culture = models.ForeignKey("TypeCulture", null=True)
slug = models.SlugField(null=True, blank=True)
image = models.ImageField(upload_to = 'images_doc_culture/',
null=True, blank = True)
affichage = models.BooleanField(default = True)
class Meta:
verbose_name = "Liste - Culture"
verbose_name_plural = "Liste - Cultures"
ordering = ['intitule_culture']
def __str__(self):
return self.intitule_culture
def label(self):
return self.intitule_culture or ''
#classmethod
def get_choices(cls):
choices = [('', corp.EMPTY_CHOICE_LBL)]
c_category_lbl, c_category = '', []
for item in cls.objects.all():
choices.append((item.pk, item.intitule_culture))
return choices
And there is the code od the new one I created:
class Crops(models.Model):
intitule_culture = models.CharField(max_length=75, blank=True)
affichage_quintaux_tonne = models.CharField(max_length=2,
choices=RENDEMENT_CHOICES, default = 'T')
type_culture = models.ForeignKey("TypeCulture", null=True)
ident_culture = models.IntegerField(primary_key=True)
affichage = models.BooleanField(default = True)
id_marle = models.IntegerField(null=True)
class Meta:
verbose_name = "Liste - Culture 2019"
verbose_name_plural = "Liste - Cultures 2019"
ordering = ['intitule_culture']
def __str__(self):
return self.intitule_culture
def label(self):
return self.intitule_culture or ''
#classmethod
def get_choices(cls):
choices = [('', corp.EMPTY_CHOICE_LBL)]
c_category_lbl, c_category = '', []
for item in cls.objects.all():
choices.append((item.pk, item.intitule_culture))
return choices
I want to accept both models in the field culture in this model:
class CompanyHarvest(models.Model):
company = models.ForeignKey('corp.Company', verbose_name='Exploitation',
related_name ='cultures')
culture = models.ForeignKey(Harvests, verbose_name ='Culture')
precision = models.CharField(max_length=255, blank=True)
saison_culture = models.CharField(max_length=1, choices=SAISON_CHOICES,
default = 'P')
class Meta:
verbose_name = "Expl. - Culture"
verbose_name_plural = "Expl. - Cultures"
unique_together = ('company', 'culture', 'precision', 'saison_culture')
def __str__(self):
return str(self.culture) + ' ' + self.precision + \
' ' + str(self.get_saison_culture_display() )
#property
def slug(self):
return "_".join([slugify(str(self.culture or '')),
slugify(str(self.precision or ''))]
)
I'm new to Django, can anyone help me with this please ? (^-^)
This is not possible - at least not this way. And this is not a Django limitation but a SQL one, a foreign key cannot reference either one table or another.
A possible and simple obvious solution here would be to have two foreign keys in CompanyHarvest - one for each of the old and new model -, each with blank=True et default=None, but it can quickly make a mess of all the client code (all code using CompanyHarvest).
Much better solutions would be to either only keep the existing model (adding any new field/feature to it and eventually hiding obsolete ones) or migrate all old model records to the new model (this can be combined with the naive "two foreign keys" solution so you can keep the old table and records as archives if necessary).
Also - totally unrelated but -, this:
#classmethod
def get_choices(cls):
choices = [('', corp.EMPTY_CHOICE_LBL)]
c_category_lbl, c_category = '', []
for item in cls.objects.all():
choices.append((item.pk, item.intitule_culture))
return choices
1/ should be defined on the manager (cf https://docs.djangoproject.com/en/2.1/topics/db/managers/#adding-extra-manager-methods)
2/ should be written using .values() queryset (which will save on both the db query and building full-blown instances for no good reason):
for item in cls.objects.values("pk", "intitule_culture"):
choices.append(item)
3/ and could very possibly (i'd have to see how it's used) replaced by a ModelChoiceField in the calling code.
Oh and yes: if you allow blanks for text fields, you very probably want to force the empty string as default so you don't two possible (and incompatible) cases (sql NULL and the empty string) when no value is given.
I am trying to save a nested relationship in Django REST Framework following the Django REST Framework guide but I couldn't do that.
I have a class "Asiento" which is a foregin key for another class "Apunte". When I get every "Asiento" Django REST Framework returns them and all of their "Apunte" objects. This works, but when I try to create/update an "Asiento" with writable nested serializers I get that AsientoSerializer(data=data).is_valid() == False.
My models:
class Apunte(TxerpadBase):
debe = models.DecimalField(null=True, blank=True, max_digits=18, decimal_places=6)
haber = models.DecimalField(null=True, blank=True, max_digits=18, decimal_places=6)
cuenta = models.ForeignKey(Cuenta, related_name='mayor', on_delete=models.PROTECT)
partner = models.ForeignKey(Partner, null=True, blank=True, on_delete=models.PROTECT)
asiento = models.ForeignKey(Asiento, related_name='apuntes')
fecha = models.DateField()
recc = models.BooleanField(blank=True, default=False)
conciliacion = models.ForeignKey('Conciliacion', null=True, blank=True, on_delete=models.SET_NULL)
estado = FSMField(default='borrador')
class Asiento(TxerpadBase):
numero = models.PositiveIntegerField(null=True, blank=True)
fecha = models.DateField(blank=True, default=datetime.datetime.now)
libro = models.ForeignKey('Libro', on_delete=models.PROTECT)
periodo = models.ForeignKey(Periodo, on_delete=models.PROTECT)
estado = FSMField(default='borrador')
My serializers:
class ApunteSerializer(serializers.ModelSerializer):
fecha = serializers.DateField(
format='%d-%m-%Y', input_formats=('%d-%m-%Y',),
error_messages={'invalid': 'La fecha del apunte no esta en el formato correcto.'}
)
class Meta:
model = Apunte
class AsientoSerializer(serializers.ModelSerializer):
fecha = serializers.DateField(
format='%d-%m-%Y', input_formats=('%d-%m-%Y',),
error_messages={'invalid': 'La fecha del asiento no esta en el formato correcto.'}
)
apuntes = ApunteSerializer(many=True)
class Meta:
model = Asiento
def create(self, data):
apuntes_data = data['apuntes']
asiento_data = data
asiento_data['fecha'] = datetime.datetime.strptime(asiento_data['fecha'], '%d-%m-%Y').date()
del asiento_data['apuntes']
asiento = Asiento.objects.create(**asiento_data)
for apunte in apuntes_data:
apunte['fecha'] = datetime.datetime.strptime(apunte['fecha'], '%d-%m-%Y').date()
Apunte.objects.create(asiento=asiento, **apunte)
My viewset:
class AsientoViewSet(viewsets.ModelViewSet):
queryset = Asiento.objects.all()
serializer_class = AsientoSerializer
def create(self, validated_data):
# JSON dictionary is inside validated_data.data
serializer = AsientoSerializer(data=validated_data.data)
if serializer.is_valid():
return Response(serializer.data)
else:
raise AttributeError('Error al validar')
This is JSON that I send with my request:
{
u'name': u'prueba 3000',
u'periodo': 13,
u'fecha': u'18-02-2016',
u'numero': None,
u'estado': u'borrador',
u'libro': 1,
u'apuntes': [
{
u'name': u'a',
u'recc': False,
u'debe': u'1',
u'haber': u'0.00',
u'cuenta': u'5',
u'partner': 8, u'fecha':
u'18-02-2016',
u'conciliacion': u''
}
]
}
If I debug the code only "create" method which executes is viewset's method, but it doesn't run "create" method from serializer.
With this code I can't save an "Asiento" neither an "Apunte". What am I doing wrong? Thank you for any answere!
I am using python 2.7 (I can't update it for external reasons) and Django REST Framework 3.3.2.
First thing you should do in case of invalid serialization is to look at the returned message (serializer.data). It'll help you understand what's going wrong.
My blind guess here is that you're missing the queryset argument relating to the nested serializer. If not set, DRF will consider those fields as read only.
Edit: After the OP edition, the issue comes from the viewset.
You need to call serializer.save() if the serializer is valid.
Have a look at how the CreateMixin does it.
Ok, I found that my problem was that "asiento" attribute in "Apunte" object can't be null and I wasn't sending it. Now, I have changed "asiento" attribute in "Apunte" object and serializer finally works, and it is no needed "create" method on ViewSet.
Thanks to everyone for your answeres.
Not sure if thats the solution. But the create method of a serializer has to return the created object.
Try adding return to your last line
I have the next code:
Models:
class Producto(models.Model):
def __unicode__(self):
return(self.nombre)
nombre = models.CharField(max_length=50)
descripcion = models.TextField(max_length=140)
color = models.CharField(max_length=15)
talla = models.CharField(max_length=10)
precio = models.IntegerField()
cantidad = models.IntegerField()
create_date = models.DateTimeField("Fecha de Creacion",auto_now=True)
def precio_display(self):
return "Gs. "+ format(self.precio, "8,d")
precio_display.short_description = 'Precio'
class Venta(models.Model):
def __unicode__(self):
return "id: {0}, {1:%H:%M - %d/%m/%Y}".format(self.id, self.fecha)
fecha = models.DateTimeField(auto_now=True)
# Relacion muchos a muchos por medio de la tabla Detalle
productos = models.ManyToManyField('Producto', through="Detalle", related_name="productos")
total = models.IntegerField()
credencial = models.CharField(max_length=200)
class Detalle(models.Model):
producto = models.ForeignKey(Producto)
venta = models.ForeignKey(Venta)
cant = models.IntegerField()**`strong text`**
precioVenta = models.IntegerField()
def __unicode__(self):
return "Se vendio {0} de {1} en la venta {2}".format(self.cantidad,self.producto, self.venta.id)
Serializers:
class ProductoModelSerializer(ModelSerializer):
class Meta:
model = Producto
fields = ("id", "nombre", "descripcion", "color", "talla",
"precio", "cantidad")
class DetalleSerializer(HyperlinkedModelSerializer):
id = ReadOnlyField(source='producto.id')
nombre = ReadOnlyField(source='producto.nombre')
class Meta:
model = Detalle
fields = ('id', 'nombre', 'cant', 'precioVenta')
class VentaModelSerializer(ModelSerializer):
productos = DetalleSerializer(source='detalle_set', many=True)
class Meta:
model = Venta
fields = ("id", "productos", "total", "credencial")
and when i use Post method i get the next error:
TypeError at /stock/rest/ventas/
'Detalle' instance expected, got OrderedDict([(u'cant', 25), (u'precioVenta', 25000)])
Request Method: POST
Request URL: http://127.0.0.1:8000/stock/rest/ventas/
Django Version: 1.7.5
Exception Type: TypeError
Exception Value:
'Detalle' instance expected, got OrderedDict([(u'cant', 25), (u'precioVenta', 25000)])
i dont know why. The get method work perfectly when i use this with a web forntend done with angular.js. But the POST, PATCH and PUT method get me the same error.
PD: Sorry for my bad english.
The documentation says:
If you're supporting writable nested representations you'll need to write .create() or .update() methods that handle saving multiple objects.
http://www.django-rest-framework.org/api-guide/serializers/
Thus you should write your own create method for POST in this case.