How to specify what value is passed using a choice form field in Symfony2 - doctrine-orm

I have the following code which displays all the available main pages that can be used when adding sub pages in my project:
$builder->add('subtocontentid',
'entity',
array(
'class'=>'Shout\AdminBundle\Entity\Content',
'property'=>'title',
'query_builder' => function (EntityRepository $repository)
{
return $repository->createQueryBuilder('s')
->where('s.mainpage = ?1')
->setParameter(1, '1')
->add('orderBy', 's.created ASC');
}
));
In the form, it works alright. It displays the proper title of the mainpage. However, when the form is passed to the database, the page ID is passed to the database. This isn't how I want it to work, I need it to pass on a slug to the database instead.
I understand that the code I'm using retrieves all of the fields in the database. How could I select just the Title field and the Slug field, and then in the form pass the Slug field to the database?
Cheers

You will have to change the Transformer used by EntityType, And it isnt the id being passed to the database it is the entity as the Transformer takes the id and looks up the entity in its list. So in your case it would be an instance of Shout\AdminBundle\Entity\Content

Related

django - dynamic query on form field

Lets say I have a form with some fields. I was wondering if it is possible to do dynamic query where I could do a string match while the user is typing into a field. Like when typing into google it returns a list of choices when you type into the search bar. Can someone give me an example on how and where to implement it?
If what you're looking to achieve is fields for a ForeignKey then you can provide a Queryset on the form field then use an app like django_select2 which can then provide a widget which will allow a user to search for items in the Queryset for the field. e.g.
city = forms.ModelChoiceField(
queryset=City.objects.all(),
label=u"City",
widget=ModelSelect2Widget(
model=City,
search_fields=['name__icontains'],
dependent_fields={'country': 'country'},
max_results=500,
)
)
Then in the form, as you started to type into the city field it'd start to search on City.name using an icontains lookup. The docs for this are here.
If that's not what you're looking for then you could just write some Javascript which detected input to a field, then sent an ajax request to a view with the contents of your field. That could then return a response which displayed content in the page related to the input.

How to add auto id to django model form

My django model by default has an auto generated id field as primary key which is named 'id' by default on my db.
As such my model has a lot of other fields that I am selectively displaying using a Django model form. While doing so I specify 'id' for this auto generated id field but my form does not display or generate this field on HTML at all even though it seems to recognize this as a valid field.
I have also checked by doing an 'all' for fields but this is also not bringing in that specific field. The funny thing is django does seem to recognize this field as 'id' because if I change it to 'Id' or anything else random it immediately gives me an error for example "Unknown field(s) (Id) specified for....." on my forms.py
This 'id' is important as I am using it to link and retrieve related objects using Ajax on client side. If this does not work then I will be forced to use another field as primary key. Any suggestions?
I ended up using a workaround as suggested by 'mastazi' for passing this id as a hidden field.
All I did is access this hidden field and generate it as an html element. Since I am using crispy_forms layout I was able to use an HTML element under Layout.
form_id= self.instance.id
id_hidden = '<input type="hidden" id="form_id" value=' + str(form_id) +' />'
I am not sure if this is a perfect solution but it works.

what field type to use for model field in form in django?

I need to make a model field read only in my form. I do this with the following:
class ActivityEntryForm(forms.ModelForm):
activity = forms.CharField(widget=forms.TextInput(attrs={'readonly':'readonly'}))
duration = forms.IntegerField()
class Meta:
model = CustomerActivity
fields = ('activity', 'duration',)
Activity is an actual model foreign key field to the CustomerActivity model.
This currently displays the Activity Id number. I want it to print the name of the activity.
What field type do I use or how can I show the name instead of the id?
First of all, note that the readonly attribute is not safe to prevent changes. Any nitwit can change the html code nowadays with inspect element etc. built into any browser. For security reasons it's better to exclude the field from the form and present the data in another way, or to have a server-side check to prevent people from changing data.
That's also a good way to solve your question. As an instance of a ModelForm, your form has an instance attribute which holds the actual data related to the object, given that this data exists. Instead of going through an unused form field, use the data form the instance as-is:
<input type="text" readonly="readonly">{% firstof form.instance.activity.name "<default>" %}</input>

How to render django form differently based on what user selects?

I have a model and a form like this:
class MyModel(models.Model):
param = models.CharField()
param1 = models.CharField()
param2 = models.CharField()
class MyForm(forms.ModelForm):
class Meta:
model = MyModel
fields = ('param', 'param1', 'param2')
Then I have one drop down menu with different values and based on what value is selected I'm hiding and showing fields of MyForm. Now I have to take one step further and render param2 as a CheckboxInput widget if user selects a certain value from a drop down but in other cases it should be standard text field. So how would I do that?
I know this post is almost a year old, but it took me multiple hours to even find a post related to this topic (this is the only one I found, which came up as related when submitting my own question), so I felt the need to share my solution.
I wanted to have a form that would show and require a text field if an option from a dropdown menu matched a value stored in another model. I had a foreignKey relation between two models and I passed an instance of Model1 into the ModelForm for Model2. If a value chosen for a variable in Model2 matched a variable already set in Model1, I wanted to show and require a textfield. It was basically a "choose Other and then enter your own description" scenario.
I did not want the page to reload (I was trying to have this work in both mobile and desktop browsers with the least delay/reloads and using the same code for both), so I could not use the mentioned multiple forms loading in a view option. I started trying to do it with AJAX as suggested above when I realized I was over thinking the problem.
The answer was using JS and clean methods in the form. I added a non-required field (field1) that was not in Model2 to my Model2Form. I then hid this using jQuery and only displayed it (using jQuery) if the value of another field (field2) matched the value of the variable from Model1. To make that work, I did decide to have a hidden < span > in my template with the pk of the variable so I could easily grab it with jQuery. This jQuery worked perfectly for hiding and showing the field correctly so the user could choose the "other" value and then decided to choose a different one instead (and go back and forth endlessly).
I then used a clean method in my Model2Form for field1 that raised a ValidationError if no value was entered when the value in field2 matched my Model1 variable. I accessed that variable by using "self.other = Model1.variable" in my __ init __ method and then referencing that in the clean_field1 method.
I would have liked to have been able to accomplish this without having to hide and show a field with JS, but I think the only solutions for doing so with views or ajax caused delays/reloads that I did not want. Also, I liked the general simplicity of the method I used, rather than having to figure out how to pass partial forms back and forth through the HTTPRequest.
Update:
In my situation, I was creating entries for lost and found items and if the location where the item was found was not a provided option, then I wanted to show a textbox for the user to enter the location. I created a location object that was set as the "other" location and then displayed the textbox when that object was selected as the "found" location.
In forms.py, I added an extra CharField and use a clean method to check if the field is required and then throw a ValidationError if it wasn't filled in:
class Model2Form(forms.ModelForm):
def __init__(self, Model1, *args, **kwargs):
self.other = Model1.otherLocation
super(Model2Form, self).__init__(*args, **kwargs)
...
otherLocation = forms.CharField(
label="Location Description",
max_length=255,
required=False
)
def clean_otherLocation(self):
if self.cleaned_data['locationFound'] == self.other and not self.cleaned_data['otherLocation']:
raise ValidationError("Must describe the location.")
return self.cleaned_data['otherLocation']
Then in my JavaScript, I checked if the value of the "found" location was the "other" location (the value of which I had in a hidden span on my html page). I then used .show() and .hide() on the textbox's parent element as necessary:
$("#id_locationFound").change( function(){
if ($("#id_locationFound").val() == $("#otherLocation").attr("value")){ //if matches "other" location, display textbox; otherwise, hide textbox
$("#id_otherLocation").parent().show();
}else
$("#id_otherLocation").parent().hide();
});
Your best guess would be to trigger a "POST" request when you select something from your drop down menu.
The Value of that "POST" has to correspond your values you use to determine which field you would like to output.
Now you will actually need two forms:
class MyBaseForm(forms.ModelForm):
class Meta:
model = MyModel
fields = ('param', 'param1', 'param2')
class MyDropDownForm(MyBaseForm):
class Meta:
widgets = {
'param2': Select(attrs={...}),
}
So as you can see the DropDownForm has been derived from MyBaseForm to make sure it will have all the same properties. But we have modified the widget of one of the fields.
Now you can update your view. Please note, this is untested Python + Pseudocode
views.py
def myFormView(request):
if request.method == 'POST': # If the form has been submitted...
form = MyBaseForm(request.POST)
#submit button has not been pressed, so the dropdown has triggered the submission.
#Hence we won't safe the form, but reload it
if 'my_real_submitbotton' not in form.data:
if 'param1' == "Dropdown":
form = MyDropDownForm(request.POST)
else:
#do your normal form saving procedure
else:
form = ContactForm() # An unbound form
return render(request, 'yourTemplate.html', {
'form': form,
})
This mechanism does the following:
When the form is submitted it checks if you have pressed the "submit" button or have used a dropdown onChange to trigger a submission. My solution doesn't contain the javascript code you need to trigger the submission with an onChange. I just like to provide a way to solve it.
To use the 'my_real_submitbutton' in form.data construct you will be required to name your submit button:
<input type="submit" name="my_real_submitbutton" value="Submit" />
Of course you can choose any string as Name. :-)
In case of a submit by your dropdown field you must check which value has been selected in this drop down menu. If this value satisfies the condition you want to return a Dropdown Menu you create an instance of DropDownForm(request.POST) otherwise you can leave everything as it is and rerender your template.
On the downside this will refresh your page.
On the upside it will keep all the already entered field values. So no harm done here.
If you would like to avoid the page refresh you can keep my proposed idea but you need to render the new form via AJAX.

How to get the ID of a just created record in Django?

I'm using Django 1.3 for one of my projects and I need to get the ID of a record just saved in the database.
I have something like the code below to save a record in the database:
n = MyData.objects.create(record_title=title, record_content=content)
n.save()
The ID of the record just saved auto-increments. Is there a way to get that ID and use it somewhere else in my code?
Use n.id after the save.
See "Auto-incrementing primary keys".
It would be n.pk.
To quote "Model.pk":
Regardless of whether you define a
primary key field yourself, or let
Django supply one for you, each model
will have a property called pk. It
behaves like a normal attribute on the
model, but is actually an alias for
whichever attribute is the primary key
field for the model. You can read and
set this value, just as you would for
any other attribute, and it will
update the correct field in the model.
The ID will be automatically updated in your model, so immediately after your n.save() line you can read n.id and it will be populated.
Remove save() and get pk directly:
n = MyData.objects.create(record_title=title, record_content=content)
n.pk
If someone reading this question and after check the other answers still having problems accessing the id after the creation of the object.
Be sure you don't define id as an Integer in your model. If you decide to declare it anyways, use Autofield but you don't need to, It is for free with models.Model
#No
class TestModel(models.Model):
id = models.IntegerField(primary_key=True)
something...
#Ok
class TestModel(models.Model):
id = models.AutoField(primary_key=True)
something...
#Ok
class TestModel(models.Model):
something...
if you do define id as Integer, TestModel.objects.create( or with save() will return None.
I had a similar issue with accessing the id. In Django 3.0.5, this is how I accessed the id. Using your example and variable name, see below:
instance = n.save()
# return the id
instance[0].id
The variable 'instance' above is a list. Accessing id in the methods described above returns an AttributeError ("object has no attribute 'id'") in Django 3.
This answer applies when using modelformset_factory. This is true when creating a Form class from a Django model as described in the Django docs