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__'
Related
I am using django-import-export to import an excel to my model, what I do is that I create a form with some inputs from where it loads the file, then in form_valid() I process the file to load it to the database, the model has two foreign keys 'id_order' and 'gestion'; 'id_orden' comes in the excel and 'gestion' I get it with gestion= Gestion.objects.get(idgestion=obj.pk) which is the id of the form that I am saving, but what I want to know is how I can pass 'gestion' to ModelResource and then save it to the database
view.py
class GestionView(CreateView):
model = Gestion
form_class = GestionForm
template_name = 'asignacion/gestion.html'
success_url = reverse_lazy('asignacion_url:gestion')
def form_valid(self, form):
isvalid = super().form_valid(form)
obj = form.save()
gestion= Gestion.objects.get(idgestion=obj.pk)
file = self.request.FILES['file']
item_gestion =ItemResourceResource()
dataset = Dataset()
imported_data = dataset.load(file.read(), format='xls')
result = item_gestion.import_data(dataset, dry_run=True)
if not result.has_errors():
item_gestion.import_data(dataset, dry_run=False)
model.py
class ItemGestion(models.Model):
idgestion = models.AutoField(primary_key=True)
numero_imagenes = models.CharField(max_length=45, blank=True, null=True)
id_orden = models.ForeignKey('Asignacion', models.DO_NOTHING)
aviso_sap = models.CharField(max_length=45, blank=True, null=True)
poliza = models.CharField(max_length=45, blank=True, null=True)
observacion_cierre = models.CharField(max_length=250, blank=True, null=True)
gestion=models.ForeignKey('Gestion', models.DO_NOTHING)
resources.py
class ItemResourceResource(resources.ModelResource):
id_orden = fields.Field(column_name='id_orden', attribute='id_orden',
widget=ForeignKeyWidget(Asignacion,'id_orden'))
class Meta:
model = ItemGestion
import_id_fields = ('id_orden',)
exclude = ('idgestion', )
It is easy to do. You need to pass the gestion value into your Resource, and then link it to the instance before it is persisted:
class ItemResourceResource(ModelResource):
def __init__(self, gestion):
self.gestion = gestion
def before_save_instance(self, instance, using_transactions, dry_run):
instance.gestion = self.gestion
class Meta:
# ...
gestion = Gestion.objects.get(idgestion=obj.pk)
item_gestion = ItemResourceResource(gestion)
Obviously this means that all the instances created from the rows in your dataset will be linked to the same 'gestion' value.
btw import-export integrates with django-admin, so you can use the admin interface to import data rather than writing your own forms (if that fits your requirements). See the docs for more information.
I have been attempting to import data into my Django project using Django import-export. I have two models Ap and Job, Job has a FK relationship with Ap. Using the Admin, I can select the file and the type, CSV. So far my program seems to run, but gets hung up on the FK. I'm close, something is off and causing the import script to fail.
Models.py
class Ap(models.Model):
line_num = models.IntegerField()
vh = models.IntegerField()
vz = models.IntegerField()
status = models.CharField(
choices=statuses, default="select", max_length=40)
classified = models.BooleanField(default=False)
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
class Job(models.Model):
aplink = models.ForeignKey(Ap, related_name=(
"job2ap"), on_delete=models.CASCADE)
job_num = models.IntegerField()
description = models.CharField(max_length=200)
category = models.CharField(
choices=categories, default="select", max_length=40)
status = models.CharField(
choices=statuses, default="select", max_length=40)
dcma = models.BooleanField(default=False),
due_date = models.DateField(blank=True),
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
views.py
class ImportView(View):
def get(self, request):
form = ImportForm()
return render(request, 'importdata.html', {'form': form})
def post(self, request):
form = ImportForm(request.POST, request.FILES)
job_resource = JobResource()
data_set = Dataset()
if form.is_valid():
file = request.FILES['import_file']
imported_data = data_set.load(file.read())
result = job_resource.import_data(
data_set, dry_run=True) # Test the data import
if not result.has_errors():
job_resource.import_data(
data_set, dry_run=False) # Actually import now
else:
form = ImportForm()
return render(request, 'importdata.html', {'form': form})
resource.py
class CharRequiredWidget(widgets.CharWidget):
def clean(self, value, row=None, *args, **kwargs):
val = super().clean(value)
if val:
return val
else:
raise ValueError('this field is required')
class ForeignkeyRequiredWidget(widgets.ForeignKeyWidget):
def clean(self, value, row=None, *args, **kwargs):
if value:
print(self.field, value)
return self.get_queryset(value, row, *args, **kwargs).get(**{self.field: value})
else:
raise ValueError(self.field + " required")
class JobResource(resources.ModelResource):
aplink = fields.Field(column_name='aplink', attribute='aplink', widget=ForeignkeyRequiredWidget(Ap,'id'),
saves_null_values=False)
job_num = fields.Field(saves_null_values=False, column_name='job_num', attribute='job_num',
widget=widgets.IntegerWidget())
description = fields.Field(column_name='description', attribute='description', saves_null_values=False,
widget=CharRequiredWidget())
class Meta:
model = Job
fields = ('aplink', 'job_num', 'description',)
clean_model_instances=True
admin.py
class JobResource(resources.ModelResource):
class Meta:
model=Job
fields=('aplink','job_num','description',)
class JobAdmin(ImportExportModelAdmin):
resource_class = JobResource
admin.site.register(Job, JobAdmin)
CSV file, data to import. I have tried leaving the first column empty, as will as putting the Id of the only Ap stored in the table ie 1. I have also tried hard coding the line_num, which is 1200 the first column as well.
CSV file for importing data:
Date importing errors:
In your resources, while defining fields, you need to include id field in the list. So change JobResource to the following:
class JobResource(resources.ModelResource):
class Meta:
model = Job
fields = ('id', 'aplink', 'job_num', 'description')
If you have defined a custom id field, then you will need to provide:
import_id_fields = ('your_id_field')
i am new to this, any recommendations are accepted, my main problem is that i have some foreign keys that are getting assigned in my database.
As you can see the last 4 models are related to the patient model through a Foreign Key, these are the fields that are not getting assigned in my project.
Models
class Patient(models.Model):
Codigo = models.CharField(max_length=20,default=None,null=False)
Nombres = models.CharField(max_length=100,null=False)
Apellidos = models.CharField(max_length=100,null=False)
Fecha_Nacimiento = models.DateField()
Numero_Telefonico = models.CharField(max_length=200,default=' ')
Email = models.CharField(max_length=256,unique=True,blank=True,default=' ')
Genero = models.ForeignKey(Gender,on_delete=models.DO_NOTHING,default=None,null=True)
Nacionalidad = models.ForeignKey(Nationality,on_delete=models.DO_NOTHING,default=None,null=True)
Estado_Civil = models.ForeignKey(CivilStatus,on_delete=models.DO_NOTHING,null=True)
Ocupacion = models.CharField(max_length=200)
Lugar_de_Procedencia = models.CharField(max_length=200)
Lugar_de_Residencia = models.CharField(max_length=200)
def __str__(self):
return self.Nombres + ' ' + self.Apellidos
class MedicalInfo(models.Model):
Expediente = models.CharField(max_length=500,blank=True)
Sangre = models.ForeignKey(BloodType,on_delete=models.DO_NOTHING,default=None,null=True)
Peso = models.FloatField()
Estatura = models.FloatField()
Alergia = models.ForeignKey(Allergies,on_delete=models.CASCADE,default=None,null=True)
Observacion = models.CharField(max_length=500,default= ' ',null=True)
Paciente = models.OneToOneField(Patient,on_delete=models.CASCADE,default=None,blank=True,null=True)
class InsuranceInfo(models.Model):
Seguro = models.ForeignKey(InsuranceCompany,on_delete=models.DO_NOTHING, default=None,blank=True,null=True)
Tipo_de_Poliza = models.ForeignKey(Policy,on_delete=models.DO_NOTHING,default=None,blank=True,null=True)
Numero_Poliza = models.IntegerField(default=None,blank=True,null=True)
Vencimiento = models.DateField(default=None,blank=True,null=True)
Paciente = models.OneToOneField(Patient,on_delete=models.CASCADE,default=None,blank=True,null=True)
class Relatives(models.Model):
Parentesco = models.ForeignKey(Family_relation, on_delete=models.DO_NOTHING,default=None,blank=True,null=True)
Nombre = models.CharField(max_length=100,blank=True)
Apellido = models.CharField(max_length=100,blank=True)
Telefono = models.CharField(max_length=100,blank=True)
Correo = models.EmailField(blank=True)
Nacimiento = models.DateField(blank=True,null=True)
Pariente = models.OneToOneField(Patient,on_delete=models.CASCADE,default=None,blank=True,null=True)
def __str__(self):
return self.Nombre + ' ' + self.Apellido
class Background(models.Model):
Padecimiento = models.CharField(max_length=200)
Control = models.CharField(max_length=200)
Medicamento = models.CharField(max_length=500)
Paciente = models.OneToOneField(Patient,on_delete=models.CASCADE,default=None,blank=True,null=True)
These are my forms, you can see that i exluded the 'Paciente' or 'Pariente' field (depending on the name of the model) in some of them because i want to assigned that field a value through a view which i will show you above the forms section.
Forms
class PatientForm(forms.ModelForm):
class Meta:
model = Patient
fields = '__all__'
widgets = {
'Fecha_Nacimiento': DateInput()
}
class RelativesForm(forms.ModelForm):
class Meta:
model = Relatives
exclude = ('Pariente',)
widgets = {
'Nacimiento': DateInput()
}
class MedicalInfoForm(forms.ModelForm):
class Meta:
model = MedicalInfo
exclude = ('Paciente',)
class InsuranceInfoForm(forms.ModelForm):
class Meta:
model = InsuranceInfo
exclude = ('Paciente',)
class BackgroundForm(forms.ModelForm):
class Meta:
model = Background
exclude = ('Paciente',)
This is the view i was talking about, in here i attempted to create a view containing all those forms and show it as one, the 'Patient' i created i this form is the one i want to assign to the field i excluded in the forms, that's why i excluded it because i wanted to assigned it manually, this is my attempt, i don't know what i am doing wrong or is missing. Any recommendations or solutions are accepted. Thanks!
Views
def PatientFormView(request):
if request.method == 'POST':
patientinfo = PatientForm(data=request.POST)
medicalinfo = MedicalInfoForm(data=request.POST)
insuranceinfo = InsuranceInfoForm(data=request.POST)
backgroundinfo = BackgroundForm(data=request.POST)
first_relative = RelativesForm(data=request.POST)
if patientinfo.is_valid() and medicalinfo.is_valid() and backgroundinfo.is_valid() and insuranceinfo.is_valid() and first_relative.is_valid():
patient = patientinfo.save()
patient.save()
medicalinfo.save(commit=False)
medicalinfo.Paciente = patient
medicalinfo.save()
backgroundinfo.save(commit=False)
backgroundinfo.Paciente = patient
backgroundinfo.save()
insuranceinfo.save(commit=False)
insuranceinfo.Paciente = patient
insuranceinfo.save()
first_relative.save(commit=False)
first_relative.Pariente = patient
first_relative.save()
return HttpResponseRedirect(reverse('patients'))
else:
patientinfo = PatientForm()
medicalinfo = MedicalInfoForm()
insuranceinfo = InsuranceInfoForm()
backgroundinfo = BackgroundForm()
first_relative = RelativesForm()
return render(request,'patients/patient_form.html',context={'patientinfo':patientinfo,'backgroundinfo':backgroundinfo,'first_relative':first_relative,'medicalinfo':medicalinfo,'insuranceinfo':insuranceinfo})
You are trying to update form instances. Change them as:
insurance = insuranceinfo.save(commit=False)
insurance.Paciente = patient
insurance.save()
Apply this approach to other models.
I have a model that includes a foreign key:
class Part(models.Model):
partType = models.ForeignKey(PartType, on_delete=models.CASCADE)
brand = models.ForeignKey(Brand, on_delete=models.CASCADE)
part_name = models.CharField(max_length=60)
class QuotePart(models.Model):
quote = models.ForeignKey(Quote, on_delete=models.CASCADE)
line = models.PositiveSmallIntegerField(default=1)
partType = models.ForeignKey(PartType, on_delete=models.CASCADE)
# part can be None if the part has not been selected
part = models.ForeignKey(Part, on_delete=models.CASCADE,blank=True,null=True)
I have a form that allows parts to be added to a quote and want to want to limit the choices on the form to just the Parts that are the right PartType but my code is not working:
class QuoteBikePartForm(ModelForm):
def __init__(self, *args, **kwargs):
super(QuoteBikePartForm, self).__init__(*args, **kwargs)
self.fields['partType'].widget.attrs['disabled'] = True
self.fields['frame_part'].widget.attrs['disabled'] = True
partType = kwargs.pop('partType')
self.fields['part'].queryset = Part.objects.filter(partType=partType.pk)
class Meta:
model = QuotePart
fields = ['quote','line','partType','frame_part', 'part', 'quantity','cost_price', 'sell_price']
QuoteBikePartFormSet = inlineformset_factory(Quote, QuotePart, form=QuoteBikePartForm)
I have tried a number of different things and so far no luck.
you can use 'self.instance.key_name' to the access the value.
It's a sort of cms type application
I have an article model and some specializations in models.py
class Article(models.Model):
foo = models.CharField(max_length=50)
bar = models.CharField(max_length=100,blank=True)
DISPLAY_CHOICES = (
('N', 'None'),
('C','Carousel'),
('M','Marketing'),
('F','Featurette')
)
display = models.CharField(max_length=1, choices = DISPLAY_CHOICES)
def __unicode__(self):
return self.title
class Artist(Article):
website = models.URLField(max_length=200,blank=True)
class Venue(Article):
location = models.CharField(max_length=150)
map_link = models.URLField(max_length=200,blank=True)
class Event(Article):
time = models.DateTimeField()
venue = models.ForeignKey(Venue)
performers = models.ManyToManyField(Artist)
I want to render these in different ways depending on the value of article.display but when I call
articles.objects.all()
I still need the extra attributes form the subclasses so I wrote
#views.py
def castToSubClass(article):
try:
return Artist.objects.get(article_ptr_id = article.id)
except:
try:
return Event.objects.get(article_ptr_id = article.id)
except:
try:
return Venue.objects.get(article_ptr_id = article.id)
except:
return article
def index(request):
carousel = [castToSubClass(article) for article in Article.objects.filter(display='C']
marketing = [castToSubClass(article) for article in Article.objects.filter(display='M'[:3]]
featurettes = [castToSubClass(article) for article in Article.objects.filter(display='F']
return render_to_response('frontpage.html',
{
'carousel': carousel,
'marketing':marketing,
'featurettes': featurettes
})
to turn them all in the appropriate subclass object, this apart from seeming clunky seems to mean I'm hitting the database twice for every (or nearly every) item in the queryset.
Is there a way to do this in the initial calls to the manager instead?
Thanks.
Use one model to store everything, and add a field to distinguish the article type, so that you can render different look for every type combine with display in the template(Like tumblr do).
class Article(models.Model):
foo = models.CharField(max_length=50)
bar = models.CharField(max_length=100,blank=True)
DISPLAY_CHOICES = (
('N', 'None'),
('C','Carousel'),
('M','Marketing'),
('F','Featurette')
)
display = models.CharField(max_length=1, choices = DISPLAY_CHOICES)
ARTICLE_TYPE_CHOICES = (
('artist', 'Artist'),
('venue', 'Venue'),
('event', 'Event'),
)
type = models.CharField(max_length=32, choices = ARTICLE_TYPE_CHOICES)
website = models.URLField(max_length=200,blank=True, null=True)
location = models.CharField(max_length=150, blank=True, null=True)
map_link = models.URLField(max_length=200,blank=True, null=True)
time = models.DateTimeField(null=True)
venue = models.ForeignKey('self', null=True)
performers = models.ManyToManyField('self', null=True)
def __unicode__(self):
return self.title
#views.py
def index(request):
carousel = Article.objects.filter(display='C')
marketing = Article.objects.filter(display='M')
featurettes = Article.objects.filter(display='F')
return render_to_response('frontpage.html',{'carousel': carousel, 'marketing':marketing, 'featurettes': featurettes})