I am working on creating a widget so clients can easily modify model's Json field in django admin.
Env Info:
django-version: 3.1.14
Before drive into the widget, this is a simplify version of my model:
class Property(PolymorphicModel):
"""Basic information about property"""
...
address = models.JSONField(blank=True, null=True, default=dict,)
...
And this how I am declaring the form:
class PropertyForm(forms.ModelForm):
class Meta:
model = Property
fields = [
"address",
]
widgets = {
'address': JSONEditorWidget(),
}
I've already manage to convert json file into django admin inputs by using the following code:
class JSONEditorWidget(forms.widgets.Input):
def as_field(self, name, key, value):
""" Render key, value as field """
new_name = name + '__' + key
self.attrs = self.build_attrs({new_name:key})
self.attrs['value'] = utils.encoding.force_text(value)
return u'%s: <input%s />' % (new_name, forms.utils.flatatt(self.attrs))
def to_fields(self, name, json_obj):
"""Get list of rendered fields for json object"""
inputs = []
for key, value in json_obj.items():
inputs.append(self.as_field(name, key, value))
return inputs
def value_from_datadict(self, data, files, name):
"""I've been trying to get new values in this function but nothing successful"""
return json.dumps(prev_dict)
def render(self, name, value, attrs=None, renderer = None):
# TODO: handle empty value (render text field?)
if value is None or value == '':
value = '{}'
json_obj = json.loads(value)
inputs = self.to_fields(name, json_obj)
# render json as well
inputs.append(value)
return utils.safestring.mark_safe(u"<br />".join(inputs))
with this I could go from this:
To this:
My problem now is to catch the new values when user clicks on save/save and continue, so I can convert them into json file to save new records on postgres.
Ive tried with the function value_fromdatadict() but couldn't manage a way to get new values in the input box...
If anyone can helps me I will be so glad, I've been dealing with this a while and this is driving me crazy
Related
Here checkout form open but problem is data entered do not save in database. I have used post method in checkout.html and model of form is created in database. But data put by user do not save in database.
views.py
class CheckoutView(View):
def get(self,*args,**kwargs):
form = CheckoutForm()
context = {
'form': form
}
print("get is working")
return render(self.request,"checkout.html",context)
def post(self,*args,**kwargs):
form = CheckoutForm(self.request.POST or None)
print("Now post is also working")
#NOT WORKING
if form.is_valid():
street_address = form.cleaned_data.get('street_address')
apartment_address = form.cleaned_data.get('apartment_address')
country = form.cleaned_data.get('country')
zip = form.cleaned_data.get('zip')
billing_address = BillingAddress(
user = self.request.user,
street_address = street_address,
apartment_address = apartment_address,
country = country,
zip = zip
)
billing_address.save()
return redirect('core:checkout')
messages.warning(self.request,"failed checkout")
return redirect('core:checkout')
I'm struggling to get my Delete operation working.
My Create, Read and Update are working fine, but a Delete has nothing to return.
class DeleteEmployeeInput(graphene.InputObjectType):
"""Arguments to delete an employee."""
id = graphene.ID(required=True, description="Global Id of the employee.")
class DeleteEmployee(graphene.Mutation):
"""Delete an employee."""
employee = graphene.Field(
lambda: Employee, description="Employee deleted by this mutation.")
class Arguments:
input = DeleteEmployeeInput(required=True)
def mutate(self, info, input):
data = utils.input_to_dictionary(input)
#data['edited'] = datetime.utcnow()
employee = db_session.query(
EmployeeModel).filter_by(id=data['id'])
employee.delete(data['id'])
db_session.commit()
#employee = db_session.query(
#EmployeeModel).filter_by(id=data['id']).first()
#return DeleteEmployee(employee=employee)
What is the best way to delete an entry?
I assume I have to return an OK or an Error.
When I run my mutation:
mutation {
deleteEmployee (input: {
id: "RW1wbG95ZWU6MQ=="
})
}
I get the error Field \"deleteEmployee\" of type \"DeleteEmployee\" must have a sub selection."
Note the commented out lines
Try replacing employee = graphene.Field... with ok = graphene.Boolean() and then make the last line of your mutate method return DeleteEmployee(ok=True)
Your mutate method will then look something like:
def mutate(self, info, input):
... skipping deletion code ...
db_session.commit()
return DeleteEmployee(ok=True)
To make it short:
I have a serializer (django rest framework) that has two custom fields which do not directly correspond to a field of my model and also have a different name. The to_internal_value() method (probably) works, but I don't know how to access the post data of these fields.
And in case you need more details on my case:
I have a django model that looks like this:
class Requirement(models.Model):
job = models.ForeignKey('Job', related_name = 'requirements')
description = models.CharField(max_length = 140)
is_must_have = models.BooleanField() # otherwise is of type b
class Job(models.Model):
...
I want to serialize it in a manner that a job object will look like this:
{ "must_have": [must have requirements], "nice:to_have": [nice to have requirements] }
Therefore, I have custom fields in my serializer for jobs:
class JobSerializer(serializers.Serializer):
nice_to_have = NiceToHaveField(source = 'requirements', allow_null = True)
must_have = MustHaveField(source = 'requirements', allow_null = True)
The NiceToHaveField and the MustHaveField classes simpy override the to_representation() and the to_internal_value() methods, the to_representation also sorts the requirements after type.
But the validated_data in JobSerializer.create never contain these cutom fields. I know the to_internal_value gets called and does its work, but the results are not accessable.
What is the way to solve this?
I found a solution I don't like, there is probably a better way to do this. Anyways, the data is available in the view.request.data. So I used the perform_create hook like this:
def perform_create(self, serializer):
nice_to_have = None
must_have = None
if 'nice_to_have' in self.request.data and self.request.data['nice_to_have'] != None:
field = NiceToHaveField()
nice_to_have = field.to_internal_value(self.request.data['nice_to_have'])
if 'must_have' in self.request.data and self.request.data['must_have'] != None:
field = MustHaveField()
must_have = field.to_internal_value(self.request.data['must_have'])
serializer.save(owner = self.request.user, nice_to_have = nice_to_have, must_have = must_have)
Is there a way I can reference a list containing data from my database (item_list = inventory.objects.order_by('name')) in my jquery AJAX call?
This is my code:
/models.py:
class phonebook(models.Model):
name = models.Charfield(max_length=200)
phone_number = models.CharField(max_length=100)
/views.py:
def phonebook_home(request):
global phonebook
phonebook = phonebook.objects.order_by('name')
def get_next_3_contacts(request):
returnedContacts = phonebook[contactIndex:contactIndex+3]
return HttpResponse(phonebook)
/main.js:
var = ajax_call {
type: 'GET'
url: DEFINED_URL
data: {
index: contactIndex
},
dataType: 'html'
success: function (returned, textStatus_ignored, jqXHR_ignored) {
var contactIndex = 0
function phonebook_list(name, phone_number) {
"<li>" + name + " : " + phone_number + "</li>"
}
for(var index=0; index < 3; index++) {
var name = phonebook[index].name
var phone_number = phonebook[index].phone_number
$("ul").append(phonebook_list(name, phone_number))
}
contactIndex += 3
}
The phonebook[index].name / .phone_number returns "undefined" on my page. I want to keep my js file separate from my template file as it will be easier for me to debug, but unfortunately, this problem has stumped me. I also inputted an alert to test out if any data was being returned from the data base, which only returns a string containing the names of the contacts with no spacing in between contact names. Ex: "JaredSarahJohn".
All help and any bit of advice is appreciated!
A couple of things need to be cleaned up in order for this solution to work:
Your idea that global phonebook will be available from within get_next_3_contacts() is incorrect. When you make the AJAX call that will ultimately invoke get_next_3_contacts() the variable phonebook is no longer available. It went out of scope when the call to phonebook_home() completed.
What's the solution? Change phonebook_home() to accept an offset and count parameters. Have it hit the database and return the requested quantities. This is called pagination and is something you should get familiar with!
def phonebook_home(request, offset, count):
phonebook = phonebook.objects.all()[offset:offset+count]
But how do we get those results down to your AJAX handler? You can't just "return" a list of objects to the HTTPResponse() function - it's looking for text to render, not Model objects.
import json
from django.http import JsonResponse
def phonebook_home(request, offset, count):
status = "OK"
return_data = ""
try:
phonebook = phonebook.objects.all()[offset:offset+count]
return_data = json.dumps(phonebook)
exception:
status = "UH OH"
return JsonResponse({'data': return_data, 'status': status)
I have this model:
class Product(ndb.Model):
title = ndb.StringProperty()
description = ndb.TextProperty()
img = ndb.BlobKeyProperty(indexed=False)
I need a html form that reads the values of fields (title and description) and read the image (from a file field), and keeps the values NDB object, the image in the Blobstore and updates the field BlobKeyProperty correctly.
As I work with wtforms, I tried to do it with a form like the following:
class ProductForm(Form):
title = fields.TextField('Title', [validators.Required(), validators.Length(min=4, max=25)])
description = fields.TextAreaField('Description')
img = fields.FileField('img')
The form shows the file field correctly but in the POST, it does not work because I don't know how to read the file, save the file to Blobstore and update the BlobKeyProperty.
My handler is this:
class ProductHandler(BaseHandler):
def new(self):
if self.request.POST:
data = ProductForm(self.request.POST)
if data.validate():
model = Product()
data.populate_obj(model)
model.put()
self.add_message("Product add!", 'success')
return self.redirect_to("product-list")
else:
self.add_message("Product not add!", 'error')
params = {
'form': ProductForm(),
"kind": "product",
}
return self.render_template('admin/new.html', **params)
Error is Expected str, got u'image.jpg'
If someone can help me, I would appreciate it!
The only solution I found is to use a deprecated low-level API described in https://developers.google.com/appengine/docs/python/blobstore/#Python_Writing_files_to_the_Blobstore
I make a wtform validator for the FileField.
I changed:
img = fields.FileField('img')
To:
img = fields.FileField('img', [create_upload_file])
And I write this validator:
def create_upload_file(form, field):
file_name = files.blobstore.create(mime_type=field.data.type, _blobinfo_uploaded_filename=field.data.filename)
with files.open(file_name, 'a') as f:
f.write(field.data.file.read())
files.finalize(file_name)
blob_key = files.blobstore.get_blob_key(file_name)
field.data = blob_key
The validator create the blob in blobstore, and then it change the field data from FieldStorage to blob_key.
I don't think that is the best solution but it works for now.