I'm working on a multilingual application where I need to implement a search engine, I opted for haystack.
This is the model I want to index
class Post(TranslatableModel):
category = models.ForeignKey(
Category,
related_name='posts',
verbose_name=_(u'Categoría')
)
slug = AutoSlugField(
populate_from='title'
)
featured_picture = ThumbnailerImageField(
upload_to='blog/posts/featured-pictures',
verbose_name=_(u'Imagen destacada'),
help_text=_(u'Tamaño: 850 x 423px. Será recordada si no.')
)
box_bg = models.CharField(
max_length=20,
verbose_name=_(u'Color de fondo de la caja'),
choices=SERVICE_BOX_COLORS,
# Could be an image
null=True, blank=True
)
box_image_bg = ThumbnailerImageField(
upload_to='blog/posts/background-images',
verbose_name=_(u'Imagen de fondo de la caja'),
null=True, blank=True,
help_text=_(u'Tamaño: 500 x 500px. Será recordada si no.')
)
translations = TranslatedFields(
title=models.CharField(
max_length=100,
verbose_name=_(u'Título')
),
content=RichTextField(
verbose_name=_(u'Contenido')
),
meta_description=models.TextField(
verbose_name=_(u'Meta description (SEO)'),
help_text=_(u'Máximo 160 caracteres.'),
max_length=160
)
)
I don't know in haystack how to deal with hvad translation fields
I will describe what I did when faced a similar problem.
In your index definition, specify a field for the current language. Django-hvad always returns a 'language_code' field if you do a query, so for example:
class PostIndex(indexes.SearchIndex, indexes.Indexable):
# your field definitions here
lan = indexes.CharField(model_attr='language_code')
# rest of your configuration here
def index_queryset(self, using=None):
return self.get_model().objects.language('all').all()
def read_queryset(self, using=None):
return self.get_model().objects.language()
This way when Haystack indexes the Posts, it will get every language version separately and store it along with a language code.
You will have to modify your search form to include the lan field as a filter:
class PostSearchForm(SearchForm):
lan = forms.CharField(required=False)
def search(self):
sqs = super(PostSearchForm, self).search()
if not self.is_valid():
return self.no_query_found()
if self.cleaned_data.get('lan'):
sqs = sqs.filter(lan=self.cleaned_data['lan'])
return sqs
It can be a hidden input field, with the value taken from request.LANGUAGE_CODE.
Related
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 am working on a Django form that let's you order customs pizzas. When building the form to "Select Size" for instance, I want to pull from a database that has my menu item's available sizes in it, so that if the menu changes, the form will automatically know what sizes are available.
Right now I am having an issue with how the query set is returned as it shows up.
How should I alter the code such that
queryset=query_list.values_list('size').distinct()
shows up in the drop down as: Small, Medium
and not: (Small,), (Medium,)
Or is there maybe a way to pull directly from the SIZE_CHOICES tuple in the class?
Thank you!
Models.py:
class Pizza(MenuItem):
STYLE_CHOICES = (
('Regular', 'Regular'),
('Sicilian', 'Sicilian'),
)
SIZE_CHOICES = (
('Small', 'Small'),
('Large', 'Large'),
)
style = models.CharField(max_length=16, blank=False, choices=STYLE_CHOICES)
size = models.CharField(max_length=16, blank=False, choices=SIZE_CHOICES)
num_toppings = models.IntegerField()
toppings = models.ManyToManyField(Topping, blank=True)
is_special = models.BooleanField(default=False)
def toppings_list(self):
return "\n".join([p.name for p in self.toppings.all()])
def __str__(self):
return f"{self.style} {self.size}"
forms.py
class PizzaForm(forms.Form):
query_list = Pizza.objects.all()
style = forms.ModelChoiceField(
widget=forms.Select,
queryset=query_list,
empty_label="Select Size"
)
size_choices = forms.ModelChoiceField(
widget=forms.Select,
queryset=query_list.values_list('size').distinct(),
empty_label="Select Size"
)
topping_choices = forms.ModelMultipleChoiceField(
widget=forms.CheckboxSelectMultiple,
queryset=Topping.objects.all(),
required=False
)
This is not a ModelChoiceField [Django-doc], since you do not select a model object, but a value. You thus can use a ChoiceField [Django-doc], and import the choices from the model:
class PizzaForm(forms.Form):
style = forms.ChoiceField(
widget=forms.Select,
choices=Pizza.STYLE_CHOICES,
empty_label="Select Size"
)
size_choices = forms.ChoiceField(
widget=forms.Select,
choices=Pizza.SIZE_CHOICES,
empty_label="Select Size"
)
topping_choices = forms.ModelMultipleChoiceField(
widget=forms.CheckboxSelectMultiple,
queryset=Topping.objects.all(),
required=False
)
That being said, you might want to look into a ModelForm [Django-doc]. This can automatically construct a form based on a model, and furthermore remove a lot of boilerplate code to save/update a Pizza object in the database.
Anyone looking to create a choice field for a non-ModelForm where the choices come dynamically from a queryset but are not model instances, you can pass a callable to the choices parameter on a ChoiceField
def _make_choices():
return [(c, c) for c in queryset.values_list('field', flat=True)]
choice_field = forms.ChoiceField(choices=_make_choices)
A Willem said, a ModelForm is the way to go for this problem.
I have a quite peculiar issue, regarding creating a formset out of a certain form. The thing is, that the form has to has an undisclosed number of fields, so I want to pass a variable to that form, which will take a proper model from database, and create proper fields within form's init method.
StrangeForm(forms.Form):
def __init__(self, id, *args, **kwargs):
super(StrangeForm, self).__init__(*args, **kwargs)
# get the form's base entry
self.certain_entry = Certain_Entry.objects.get(id=id)
# create a hidden input to keep the id
self.fields["id"] = forms.HiddenInput()
self.fields["id"].initial = id
# initiate text field
self.fields["text_field"] = forms.CharField(widget=forms.TextInput(attrs={'style': 'width:95%', }),
required=False)
self.fields["text_field"].initial = self.certain_entry.text
# create and initiate fields for undisclosed number of subentries
subordinates = Certain_Entry_Subordinates.objects.filter(foreign_key=self.certain_entry)
for each in subordinates:
the_name = "%d_%s_%s" % (each.further.id, each.further.name)
self.fields[the_name] = forms.ChoiceField(choices=(("Ok", "Ok"), ("Not Ok", "Not Ok"), ("Maybe" "Maybe"),
required=False)
self.fields[the_name].initial = each.option
The models are as follows:
class Certain_Entry(models.Model):
text = models.TextField(max_length=128, null=True, blank=True)
class Certain_Entry_Subordinates(models.Model):
certain_entry = models.ForeignKey(Certain_Entry, null=False, blank=False)
option = models.TextField(max_length=8, null=True, blank=True)
further = models.ForeignKey(Further, null=False, blank=False)
class Further(models.Model):
name = models.TextField(max_length=32, null=True, blank=True)
So as you see, I need to pass this ID into the form. When it's a single form, it's all OK, but I can't find any information as to how create a formset with forms that require a variable. Any ideas?
PS: As to WHY... Don't ask, I just need to do it that way, trust me. I'm an engineer.
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'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.