I have a django app that into the model has a json field looks like this
from json_field import JSONField
from django.db import models
class C(models.Model):
name = models.CharField(max_length=255)
jf = JSONField(null=False)
There is a form that display this as follow
class Edit(forms.Form):
name = forms.CharField()
def __init__(self, *args, **kwargs):
if 'extra' in kwargs:
extra = kwargs.pop('extra')
super(Edit, self).__init__(*args, **kwargs)
for k, v in extra.iteritems():
self.fields['%s' % k] = v
else:
super(Edit, self).__init__(*args, **kwargs)
The view will load the json field jf and send it to the Form as initial data, as well
will send all the necessary fields as extra.
def edit_model(request, pk):
obj = get_object_or_404(models.C, pk=pk)
initial = model_to_dict(obj)
form = Edit(request.POST or None, initial=initial, extra=initial['jf'])
if request.method == 'POST':
if form.is_valid():
.....
# what is the best practice here ?
# intersect cleaned data with the jf fields ?!
# have an external entity that does this ?!
# is anything built into django that can help
thanks!
If I understood you can try this custom widget's form of django It does JSON to formfields and formfields -> JSON after save
Related
I have two Models for my Project, 1. Category Model and 2. Course Model
Course Model has a Foreign Key reference with my Category Model as shown below.
class Category(models.Model):
categoryname = models.CharField(max_length=200,null=True,blank=True, default="")
class Courses(models.Model):
coursename = models.CharField(max_length=200,null=True,blank=True, default="")
course_category = models.ForeignKey(Category, related_name="courses", blank=True,null=True,on_delete=models.CASCADE)
logo = models.ImageField(upload_to='courselogos', null=True, blank=True)
Initially I was using HTML form and will be able to save the Course data under a Particular Category to the database as:
def add_course(request):
if request.method == 'POST':
course_name = request.POST.get('coursname')
categoryid = request.POST.get('category_id')
category = Category.object.get(id=category_id)
course_logo = request.FILES.get('logo')
course = Courses(coursename=course_name, course_category=category, logo= course_logo)
course.save()
return redirect('/all_category')
Later I decided to move on using Django Model forms and I tried to implement the code as follows
class AddCourseForm(forms.ModelForm):
class Meta:
model = Courses
fields = ('coursename', 'course_category', 'logo')
widgets = {
'coursename' : forms.TextInput(attrs={'class':'form-control'}),
}
def __init__(self, *args, **kwargs):
category_id = kwargs.pop('category_id',1)
super(AddCourseForm, self).__init__(*args, **kwargs)
self.fields['course_category']=forms.ModelChoiceField(widget=forms.TextInput(), queryset=Category.objects.filter(id=category_id))
Later in the view I have saved the data as
def add_course(request):
if request.method == 'POST':
addcourse = AddCourseForm(request.POST, request.FILES)
if addcourse.is_valid():
addcourse.save()
return redirect('/all_category')
On my HTML page I am passing the input to the 'course_category' inputfield as 1,2,3....etc as the category_id value
I have rendered the field in the form as
{{form.course_category}}
On Submitting the form when my 'course_category' inputfield has value as 1, it saves the data to the database but when the inputfield value is 2 then it is not even entering to the if condition of addcourse.is_valid() in the view function.
As I'm new the Django I'm not able to find the right way to get the ForeignKey value dynamically save the data in reference to that Category. Also I want to populate the same data back to the form in case of edit.
Please guide, thanks in advance.
After debugging the Code a little bit, I modified the init function in the AddCourseForm class as mentioned below that solved my issue but I am not it is the right way to do this or not
def __init__(self, *args, **kwargs):
category_id = None
for key in args[0:1]:
category_id = args[0].get('course_category')
super(AddCourseForm, self).__init__(*args, **kwargs)
self.fields['course_category']=forms.ModelChoiceField(widget=forms.TextInput(), queryset=Category.objects.filter(id=category_id))
I don't think doing this should be that difficult, here is how you would set the course_category options in the form normally:
# forms.py
class AddCourseForm(forms.ModelForm):
...
def __init__(self, *args, **kwargs):
self.course_categories = Category.objects.all()
super(AddCourseForm, self).__init__(*args, **kwargs)
self.fields['course_category'].queryset = self.course_categories
If you want to set a particular category in the form the you can pass an initial value in your view:
# views.py
def add_course(request, pk):
# note: you can pass the category primary key to your view, you need to
# specify this in your URLs and then your template
course_category = Category.objects.get(pk=pk)
form = AddCourseForm(initial={'course_category': course_category})
If you then want to kill all other options entirely, you can use the initial value to set your filter:
# forms.py
class AddCourseForm(forms.ModelForm):
...
def __init__(self, *args, **kwargs):
super(AddCourseForm, self).__init__(*args, **kwargs)
self.fields['course_category'].queryset = Category.objects.filter(
pk=self.fields['course_category'].initial)
I am building REST API which stores name, salary and expenses of people. How can I POST data of multiple people at the same time, like an array?
This is my serializers.py file
from rest_framework import serializers
from .models import Bucketlist
class BucketlistSerializer(serializers.ModelSerializer):
class Meta:
model = Bucketlist
fields = ('id','name', 'date_created', 'salary','Expenditure')
read_only_fields = ('date_created',)
This is my views.py file
Django provides many=True attribute to pass while building queryset in your view. Please have a look on :
Multiple objects in serializer
you should use (many=True) in the serializer while saving
data = BucketlistSerializer(data = your_post_array,many=True)
if data.is_valid():
data.save()
add this to your view
def get_serializer(self, *args, **kwargs):
if isinstance(kwargs.get('data', {}), list):
kwargs['many'] = True
return super("your view class name ", self).get_serializer(*args, **kwargs)
for function base view
#api_view(['GET','POST'])
def somefunction(request):
if request.method == 'POST':
data = BucketlistSerializer(data = request.data["key_for_data"], many=True)
if data.is_valid():
data.save()
return(data.data)
return(data.errors)
post data will be : {"key_for_data":[{},{}]
In django, how can I make a selectible formField to access the db for every time it is being calld?
Right now the line :
status = forms.ChoiceField(choices=FormsTools.StatusesToTuples(Status.objects.all()))
is executed once django is loaded and not every time the form is being showed.
How can I make the field dynamic ? so every time the form is being showed the selectible field will have values from db?
UPDATE:
POST data:
.
status: u'4'
.
.
in the Model, the field looks like this: status = models.IntegerField()
The View:
def edit_call(request, call_id):
c = Call.objects.get(id=call_id)
if request.POST:
form = CallForm(request.POST, instance=c)
print form.errors
if form.is_valid():
form.save()
return HttpResponseRedirect('/ViewCalls/')
else:
form = CallForm(instance=c)
args = {}
args.update(csrf(request))
args["form"] = form
args["id"] = call_id
t = get_template('edit_call.html')
cont = RequestContext(request, args)
html = t.render(cont)
return HttpResponse(html)
The form:
simple as:
class CallForm (forms.ModelForm):
employee_id = forms.ModelChoiceField(queryset=Employee.objects.all())
status = forms.ModelChoiceField(queryset=Status.objects.all())
class Meta():
model = Call
You need to call the contructor each time you load the form to update the choices. So the form should be:
class CallForm(forms.ModelForm):
...
status = forms.ChoiceField()
def __init__(self, data=None, files=None, auto_id='id_%s', prefix=None,
initial=None, error_class=ErrorList, label_suffix=None,
empty_permitted=False):
super(CallForm, self).__init__(data, files, auto_id, prefix, initial, error_class,
label_suffix, empty_permitted)
self.fields['status'].choices = FormsTools.StatusesToTuples(Status.objects.all())
Have you looked at forms.ModelChoiceField?
UPDATED ANSWER FOLLOWING UPDATED QUESTION:
You now need to get your models and your forms to match:
Your model has an IntegerField, your form has a ModelChoiceField. The latter returns a pk string, not an integer ID.
Given that you're using a modelform, why not just let it do the work of creating the fields for you?
class CallForm(forms.ModelForm):
class Meta:
model = Call
fields = ('employee', 'status') # assuming these are what the field names are
I have a model for adding entries of Mobile apps:
class MobileApp(models.Model):
name = models.CharField(max_length=255)
description = models.TextField()
images = models.ManyToManyField(Image, blank=True)
In Django Admin, what i am trying to do is filter the images that are listed in the list to prevent django from loading all images in that table which are quite alot.
So what i currently do is the following:
class MobileAppAdmin(admin.ModelAdmin):
def get_form(self, request, obj=None, **kwargs):
form = super(MobileAppAdmin, self).get_form(request, obj, **kwargs)
if obj:
form.base_fields['images'].queryset = Image.objects.filter(pk__in=obj.images.all())
else:
form.base_fields['images'].queryset = Image.objects.filter(pk=0)
return form
But when submitting the form, adding a new image, what happens is the following:
Select a valid choice. XYZ is not one of the available choices.
On the images field.
How can i make this work? i have lots of fields that need the same move as django keeps loading all the records to populate the lists for relations.
Thanks
Don't limit options when form being submitted.
class MobileAppAdmin(admin.ModelAdmin):
def get_form(self, request, obj=None, **kwargs):
form = super(MobileAppAdmin, self).get_form(request, obj, **kwargs)
if request.method == 'GET':
if obj:
form.base_fields['images'].queryset = Image.objects.filter(pk__in=obj.images.all())
else:
form.base_fields['images'].queryset = Image.objects.filter(pk=0)
return form
I know this seems to be an over-asked question in the Django circles but I'm afraid to say that i've not yet found the solution to this.
My Model -
from djago.... import User
class InfoPersonal(models.Model):
...
person = models.OneToOneField(User)
I've tried overriding the save_model() in the admin definition and also overriding the save() in the Form but nothing seems to work.
If you were to auto add data into a ForeignKey or OneToOneField column to a Model how would you do it?
def profile_creation_personal(request):
if request.method == 'POST': # If the form has been submitted...
form = PersonalForm(request.POST) # A form bound to the POST data
# form.person = request.user
if form.is_valid(): # All validation rules pass
# Process the data in form.cleaned_data
# ...
form.save()
return HttpResponseRedirect('/done') # Redirect after POST
else:
form = PersonalForm() # An unbound form
return render_to_response('info/personal/profile_create.html', { 'form': form,})
class PersonalForm(ModelForm):
#hometown_id = ModelChoiceField(queryset=InfoReferenceCities.objects.all(),empty_label=None)
def save(self, *args, **kwargs):
self.person = request.user
super(PersonalForm, self).save(*args, **kwargs)
class Meta:
model = InfoPersonal
exclude = ('person',)
widgets = {'dateofbirth' : SelectDateWidget()}
I got the answer!!! I feel good!
personal = form.save(commit = False)
personal.person = request.user
personal.save()
This goes into the view much like Ignacio said, only commit = False being a critical statement for it to save an instance without throwing an exception. Thanks all who helped!!
Cheers
In your PersonalForm, you can subclass your save() function, so the appropriate data is added, something like this:
class PersonalForm(ModelForm):
def save(self, *args, **kwargs):
self.person = request.user
super(PersonalForm, self).save(*args, **kwargs)
class Meta:
model = Personal
see this
parent = models.ForeignKey('self', blank=True, null=True, verbose_name=_("parent"))
this ok but have problem with sqlite , change it to postgresql its ok. ( its for my code , change it to your status )