get new value in django admin widget - django-rest-framework

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

post method of class based view is not working.while get method is responding.form is launched using get method but post is not

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')

Best way to do a delete operation with GraphQL + graphene

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)

Get post data from CustomField in django rest framework

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)

Django AJAX call: Referencing Table in JS

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)

wtforms, ndb and blobstore

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.

Resources