Serialize QuerySet to JSON with FK DJANGO - python

I want to send a JSON of a model of an intersection table so I only have foreign keys saved, I tried to make a list and then convert it to JSON but I only receive the ids and I need the content, I also tried in the back as a temporary solution to make a dictionary with the Queryset but the '<>' makes it mark an error in the JS, does anyone know a way to have the data of my foreign keys and make them a JSON?
models:
class Periodos(models.Model):
anyo = models.IntegerField(default=2022)
periodo = models.CharField(max_length=10)
fecha_inicio = models.DateField(blank=True, null=True)
fecha_fin = models.DateField(blank=True, null=True)
class Meta:
app_label = 'modelos'
verbose_name = u'periodo'
verbose_name_plural = u'Periodos'
ordering = ('id',)
def __str__(self):
return u'%s - %s' % (self.anyo,self.periodo)
class Programas(models.Model):
programa = models.CharField(max_length=255,blank=True, null=True)
activo = models.BooleanField(default=True)
class Meta:
app_label = 'modelos'
verbose_name = u'Programas'
verbose_name_plural = u'Programas'
def __str__(self) -> str:
return self.programa
class Programa_periodo(models.Model):
periodo = models.ForeignKey(Periodos, related_name='Programa_periodo_periodo',on_delete=models.CASCADE)
programa = models.ForeignKey(Programas, related_name='Programa_periodo_Programa',on_delete=models.CASCADE)
class Meta:
app_label = 'modelos'
verbose_name = u'Programa Periodo'
verbose_name_plural = u'Programa Periodo'
def __str__(self) -> str:
return self.programa.programa
py where i send data
def iniciativa(request):
if request.user.is_authenticated:
context = {}
context['marcas'] = json.dumps(list(Marcas.objects.values()))
context['eo'] = get_estructura_org()
#This is where I call the data
programa = Programa_periodo.objects.all()
#These two only return the ids
# context['programa_periodos'] = json.dumps(list(Programa_periodo.objects.values()))
#context['programa_periodos'] = serializers.serialize("json", Programa_periodo.objects.all())
#One of my try but fail for the '<>'
programa_periodo = {}
for pg in programa:
programa_periodo[pg.periodo] = pg.programa
context['programa_periodos'] = programa_periodo
return render(request, 'agregar_iniciativa.html', context)
else:
return HttpResponseBadRequest('Favor de ingresar sesiĆ³n en el sistema.', format(request.method), status=401)

I am not sure that I get the question right, but if you need a special field value from foreign key you can use smth like:
Programa_periodo.objects.values("id", "periodo__periodo", "programa__programa")
With double underscore. Try it in the shell first. Check the docs here https://docs.djangoproject.com/en/4.0/ref/models/querysets/#values

Related

Django write a get_form() function

I have an app that creates modelForms dynamically based on models. These forms must be dynamically loaded on the template.
I need to write a function in my view that gets all the forms from forms.py or gets a specific form by it's name. Something similar to get_models(appName) and get_model(AppName, modelName) but for forms instead of models.
How can I write it and where should I write it?
in Registery or in forms or somewhere else?
Here is my code:
Models.py
class PrimaryInfo(models.Model):
Name = models.CharField(max_length=200, blank=False, null=True) #required. Must be filled by user
Surname = models.CharField(max_length=200, blank=False, null=True)
DateOfBirth = models.DateField('date of birth', blank=False, null=True)
<Some Other fields>
...
def calculateAge(self):
if not self.DateOfBirth is None:
thisYear = timezone.now().date().year
return thisYear - self.DateOfBirth.year
pass
<some other functions>
...
#Here come all the related tables
class Jobs(models.Model):
Rel = models.ForeignKey(PrimaryInfo, on_delete=models.CASCADE)
Job = models.CharField(max_length=200)
Age = models.IntegerField(default=0)
Country = models.CharField(max_length=200)
def __str__(self):
return self.Job
<some other related models>
....
My View:
def detail(request, personId):
appName = urls.app_name
tablesPrefix = appName + '_'
person = PrimaryInfo.objects.get(pk = personId)
peopledbModels = apps.get_models(appName)
fieldsList = []
relatedModels = []
relationshipsDic = {}
formsFileName = "write.py"
parentModelForms = []
# identify which models are parent and which ones are relationships. makes a dictionary (Of string, list) for the results.
for m in peopledbModels:
if m._meta.db_table.startswith(appName):
fields = m._meta.get_fields()
for fld in fields:
if fld.is_relation:
if fld.many_to_one or fld.many_to_many or fld.one_to_one:
pass
else:
relatedModels.append(fld.name)
relationshipsDic["{}".format(m._meta.label).replace("{}.".format(appName),"")] = relatedModels
#Write the modelForm from parent model into forms.py
for pmdl in relationshipsDic.keys():
parentModelName = pmdl
modelFormExist = False
with open("{}{}/{}".format(djangoSettings.MEDIA_ROOT, appName, formsFileName)) as file:
if "class {}Form(forms.ModelForm):".format(parentModelName) in file.read():
file.close()
modelFormExist = True
if modelFormExist == False:
with open("{}{}/{}".format(djangoSettings.MEDIA_ROOT, appName, formsFileName), "a+") as file:
file.write("\n\nclass {0}Form(forms.ModelForm):\n\tclass Meta:\n\t\tmodel = {0}\n\t\tfields = '__all__'".format(parentModelName))
file.close()
parentModel = apps.get_model(appName, pmdl)
instance = get_object_or_404(parentModel, pk=personId)
parentModelForm = "{}Form".format(pmdl) #this is where I need to get the form object with a variable name from forms.py
parentModelForm = parentModelForm(instance = instance) #this is not working (string object is not callable)
parentModelForms.append(parentModelForm)
<then pass this list of models to the template>
...
My forms (automatically populated from my view):
class PrimaryInfoForm(forms.ModelForm):
class Meta:
model = PrimaryInfo
fields = '__all__'
class JobsForm(forms.ModelForm):
class Meta:
model = Jobs
fields = '__all__'

Writing a view to allow user to add related data for a customer, like comments for example; on a single page

I have working models, forms, views and urls for a django CRUD app managing customer functions for a business. I just cant seem to figure out how to write a view to allow a user to add comments, or other data related to the customer and stored in other models using a single view and template.
So for example; for customer a, all the comments for customer a with the option to add, amend etc.. and the same for the other related models.
I understand how to do it for one I will be able to make quick progress. (old school programmer here)
Here is what I am working with - keeping it simple.
MODELS
class Emergency(models.Model):
# Fields
name = CharField(null = False, blank = False, max_length=60)
address = TextField(blank=True, null=True, help_text='Street and town', verbose_name='Address')
telephone = CharField(blank=False, null=False, unique= True, max_length=20)
relationship = CharField(choices=(('P', 'Parent'),('S', 'Son'),('D', 'Daughter'),('R', 'Relative'),('L', 'Partner')),max_length = 1,default='R')
class Meta:
ordering = ('-pk',)
def __unicode__(self):
return u'%s' % self.pk
def get_absolute_url(self):
return reverse('conform_emergency_detail', args=(self.pk,))
def get_update_url(self):
return reverse('conform_emergency_update', args=(self.pk,))
class Client(models.Model):
# Fields
surname = CharField(null = False, blank = False, max_length=30)
name = CharField(null = False, blank = False, max_length=60)
# Relationship Fields
emergencycontact = models.ForeignKey(Emergency, on_delete=models.CASCADE, name = 'Emergency Contact')
class Meta:
ordering = ('-pk',)
def __unicode__(self):
return u'%s' % self.pk
def get_absolute_url(self):
return reverse('conform_client_detail', args=(self.pk,))
def get_update_url(self):
return reverse('conform_client_update', args=(self.pk,))
class Clientnotes(models.Model):
# Fields
slug = AutoSlugField(populate_from='name', blank=True)
created = DateTimeField(auto_now_add=True, editable=False)
last_updated = DateTimeField(auto_now=True, editable=False)
note = CharField(blank=False, null=False, max_length= 300 )
# Relationship Fields
modified_by = models.ForeignKey(User, related_name='clientnotes_modified_by', on_delete=models.CASCADE, name= 'Changed by')
clientnotes = models.ManyToManyField(Client, name = 'Clients notes')
class Meta:
ordering = ('-created',)
def __unicode__(self):
return u'%s' % self.slug
def get_absolute_url(self):
return reverse('conform_clientnotes_detail', args=(self.slug,))
def get_update_url(self):
return reverse('conform_clientnotes_update', args=(self.slug,))
FORMS
class ClientForm(forms.ModelForm):
class Meta:
model = Client
fields = ['surname', 'name']
class ClientnotesForm(forms.ModelForm):
class Meta:
model = Clientnotes
readonly_fields = ['slug', 'modified_by']
fields = ['note']
VIEWS
class ClientListView(ListView):
model = Client
class ClientCreateView(CreateView):
model = Client
form_class = ClientForm
class ClientDetailView(DetailView):
model = Client
class ClientUpdateView(UpdateView):
model = Client
form_class = ClientForm
TEMPLATE NAMES
client_detail.html
client_form.html
client_list.html
I have simple views, forms and templates to list, view detail and add and it all works well - with the exception of related models because i am not able to add both models at the same time. I need a simple clear simpletons guide with what i have provided so it clicks into place.

Django: 'ModelForm' object has no attribute

I'm working with Django Forms in order to create a new object, but I'm having problems with it. It all renders OK, but when I submit the Form, an error is raised:
"AttributeError at /rutinas/nueva_rutina
'DiaForm' object has no attribute 'ejercicios'"
I've tried many possible solutions I read here, but they didn't work. I think the problem is with the M2M relationship, but it can also be for processing two forms at a time. Here are my files
models.py
class Ejercicio(models.Model):
id = models.AutoField(primary_key=True)
nombre = models.CharField(max_length=30, default='')
descripcion = models.TextField(default='')
gif = models.ImageField(default='')
def __str__(self):
return self.nombre
class Rutina(models.Model):
id = models.AutoField(primary_key=True)
nombre = models.CharField(max_length=30, default='')
def __str__(self):
return self.nombre
class Dia(models.Model):
ejercicios = models.ManyToManyField(Ejercicio)
rutina = models.ForeignKey(Rutina, on_delete=models.CASCADE)
forms.py
class RutinaForm(forms.ModelForm):
class Meta:
model = Rutina
fields = '__all__'
labels = {
'nombre': _('Nombre')
}
class DiaForm(forms.ModelForm):
ejercicios = forms.ModelMultipleChoiceField(queryset=Ejercicio.objects.all())
class Meta:
model = Dia
fields = ['ejercicios']
labels = {
'ejercicios': _('Ejercicios')
}
views.py
def nueva_rutina_view(request):
if request.method == "POST":
form = RutinaForm(request.POST)
dia_form_1 = DiaForm(request.POST)
dia_form_2 = DiaForm(request.POST)
dia_form_3 = DiaForm(request.POST)
if form.is_valid() and dia_form_1.is_valid() and dia_form_2.is_valid() and dia_form_3.is_valid():
rutina = form.save(commit=False)
dia1 = dia_form_1.save(commit=False)
dia2 = dia_form_2.save(commit=False)
dia3 = dia_form_3.save(commit=False)
rutina.save()
dia1.rutina = rutina
dia2.rutina = rutina
dia3.rutina = rutina
dia1.ejercicios = dia_form_1.ejercicios
dia2.ejercicios = dia_form_2.ejercicios
dia3.ejercicios = dia_form_3.ejercicios
dia1.save()
dia2.save()
dia3.save()
return redirect(historial_rutinas_view)
else:
form = RutinaForm()
dia_form_1 = DiaForm()
dia_form_2 = DiaForm()
dia_form_3 = DiaForm()
return render(request, 'rutinas/nueva-rutina.html', {'form': form, 'dia_form_1': dia_form_1, 'dia_form_2': dia_form_2, 'dia_form_3': dia_form_3})

Django order_by not working properly

I'm trying to get all the conversations ordered by it last message, but when I use the order_by clausule, the conversations are repeated.
Query without order_by:
conversaciones = Conversacion.objects.filter(usuarios=request.user)
Result (Grouped by Conversations but not ordered by the most recent last message first):
Query with order_by:
conversaciones = Conversacion.objects.filter(usuarios=request.user).order_by('-mensaje__fechaEnvio')
Result:
My models.py:
class Mensaje(models.Model):
remitente = models.ForeignKey('Usuario', on_delete=models.CASCADE, related_name='remitente')
destinatario = models.ForeignKey('Usuario', on_delete=models.CASCADE, related_name='destinatario')
cuerpo = models.TextField(validators=[MaxLengthValidator(750)])
leido = models.BooleanField(default=False)
fechaEnvio = models.DateTimeField(auto_now_add=True)
conversacion = models.ForeignKey('Conversacion', on_delete=models.CASCADE)
class Meta:
ordering = ['-fechaEnvio']
def __str__(self):
return str(self.remitente) + ' -> ' + str(self.destinatario)
class Conversacion(models.Model):
usuarios = models.ManyToManyField('Usuario', related_name='usuarios')
agresion = models.ForeignKey('Agresion', on_delete=models.CASCADE)
#property
def ultimoMensaje(self):
return self.mensaje_set.latest('fechaEnvio')
I found a solution:
conversaciones = Conversacion.objects.filter(usuarios=request.user).annotate(max_fecha=Max('mensaje__fechaEnvio')).order_by('-max_fecha')
I'm using MySQL so I can't use distinct with params.
As #jota suggested, I can add something in your model Mesanje. Make ordering a tuple and don't forget to add a comma and don't forget to make migrations again.
class Mesanje(models.Model):
........
class Meta:
ordering = ('-fechaEnvio',)

ManytoMany relationship serializer

I've encountered a huge problem with a single Many to many relationship, Im trying to send the id's of the users to the group serializer in order for me to save them and create the group however the id is never recorded and grupos is created with nothing but saves nombre and creates the object.
Models.py
class Usuarios(models.Model):
class Meta:
db_table = "Usuarios"
idUsuario = models.AutoField(primary_key=True)
tipoUsuario = models.BooleanField(blank=False)
nombre = models.CharField(max_length=100,blank=False)
idUser = models.IntegerField(blank=False)
idEscuela = models.ForeignKey(Escuelas, on_delete=models.CASCADE)
class Grupos(models.Model):
class Meta:
db_table = "Grupos"
idGrupo = models.AutoField(primary_key=True)
nombre = models.CharField(max_length=30,blank=False,unique=True)
idUsuario = models.ManyToManyField(Usuarios)
class idUsuarioSerializer(serializers.Serializer):
#idUsuario = serializers.IntegerField(required=True)
class Meta:
model = Usuarios
fields = ('idUsuario',)
class GrupoSerializer(serializers.Serializer):
nombre = serializers.CharField(required=True)
idUsuario = idUsuarioSerializer(many=True)
class Meta:
model = Grupos
fields = ('nombre','idUsuario')
def create(self, validated_data):
idUsuarios_data = validated_data.pop('idUsuario')
grupo = Grupos.objects.create(**validated_data)
for idUsuario_data in idUsuarios_data:
#print(**idUsuario_data)
#Usuarios.objects.create(grupo=grupo,**idUsuario_data)
grupo.idUsuario.add(**idUsuario_data)
grupo.save()
return grupo
However this saves nothing on idUsuario field and also if I do it like the documentation it gives me an error "group is not a valid keyword" or even if I use "idGrupo" it says the same, I already check other answers looks like it's not possible, already tried add method too.
I send the following json
{
"nombre": "4B",
"idUsuario":[{"id":1},{"id":2}]
}
Try something like this,
for idUsuario_data in idUsuarios_data:
grupo.idUsuario.add(idUsuario_data['id'])
grupo.save()

Categories

Resources