django rest framework and forms: How to do - django

I have a model in my Django App as below. I am using ReactJs as frontend and pass data using Django Rest Framework.
class Ingredient(models.Model):
MUNITS_CHOICES = (
('kg', 'Kilogram'),
('ltr', 'Liter'),
('pcs', 'Pieces'),
)
name = models.CharField(max_length=200,unique=True,null=False)
slug = models.SlugField(unique=True)
munit = models.CharField(max_length=10,choices=MUNITS_CHOICES,default=KILOGRAM)
rate = models.DecimalField(max_digits=19, decimal_places=2,validators=[MinValueValidator(0)],default=0)
typeofingredient = models.ForeignKey(TypeOfIngredient, related_name='typeof_ingredient',null=True, blank=True,on_delete=models.PROTECT)
density_kg_per_lt = models.DecimalField(max_digits=19, decimal_places=2,verbose_name='Density (kg/lt)',null=True,blank=True,validators=[MinValueValidator(0)])
updated = models.DateTimeField(auto_now=True, auto_now_add=False)
timestamp = models.DateTimeField(auto_now=False, auto_now_add=True)
As you see the model fields have lot of parameters like max_length, choices, ForeignKey(which is also kind of choices), DecimalField, CharField, DateTimeField etc
I was creating and rendering forms using Django Forms. Also the validaton is done in the Form class.
The advantage of this is the form is inserted very easily in the template using {{ form }}. and it takes care of all the parameters like max_length, choices, fieldtypes etc. Also we can validate the form and the errors are send back etc. So most the job is done automatically.
But since i am using DRF i created a serializer class to create or update:
class IngredientCreateUpdateSerializer(ModelSerializer):
class Meta:
model = Ingredient
fields = [
'name',
'munit',
'rate',
'typeofingredient',
'density_kg_per_lt',
]
Here again i have to write the validation logic which i have done in the form.
Now to create the HTML form in the reactjs i have to manually look at each form parameter (like fieldtype, required etc) and create the form, and then link the api endpoint to create/update on submit button.
Also the choices for select field have to passes as seperate endpoints.
Solution 1 Needed: Create form api
So is there a form api which will pass all the fields and their parameters like max_length, required, choices for select field, choices for foreignfields to the reactjs. So that i get some blueprint to create the form in reactJs. Later even if i change the model or parameters everything can be taken care of by the api.
Solution 2 Needed: Can validation logic be common for serializer and
forms
Will i have to write the validation code for serializer class also or is there a way i can link with the form class which i have already used.
I am mainly looking for Solution 1
: Because solution 2 is more of typing the validation twice which is fine.

I read through your solution scenarios. I work with Django-reactjs. To make things simple for yourself,.
Make do with this templating https://github.com/Frojd/django-react-templatetags
You mention of model class parameters. It can suffix, since you are interested in passing the model parameters to the frontend.
Another option is : React, with the help of Webpack (module bundler) & Babel (transpiler), will bundle and transpile your Javascript into single or multiple files that will be placed in the entry HTML page. Learn Webpack, Babel, Javascript and React and Redux (a state container). I believe you won't use Django templating but
instead allow React to render the front-end.
Should you have anyother questions do let me know

Related

Serializing and storing JSON array in Django REST Framework

I'm trying to make a demo website for job applications using Angular 6 and Django Rest Framework. One of my application fields involve listing your interests in a chip input field like this one.
The JSON being sent to my API would look something like this:
{
...
'firstname': 'Firstname',
'lastname': 'Lastname'
...
'interests': ['hobby1', 'hobby2', 'hobby3', 'hobby4'],
...
}
Now as far as I know Django REST Framework supplies a serializer field that is written something like this:
interests = serializers.ListField(
item = serializers.CharField(min_value=xx, max_value=xx)
)
My question is, how do I proceed from here? What model fields do I use, or do I have to create my own save function that iterates through the interests and saves every single one?
Many to many relationship is the thing you are looking for.
You can even have nested serializer so the output of the parent objects would include the serialized interests in the JSON.
class ParentSerializer(serializers.ModelSerializer):
child_set = ChildSerializer(many=True)
class Meta:
depth = 1
model = Parent
fields = ('id', 'other_atributes', 'child_set')
Also you can easily edit those relationship in Django Admin, can post a snippet of that also if you would be interested.
'interests': ['hobby1', 'hobby2', 'hobby3', 'hobby4']
This is basically valid JSON, so you can parse this easily on your end.

Django rest framework: automatically create a url for each field of a model

I have large table of data (~30 Mb) that I converted into into a model in Django. Now I want to have access to that data through a REST API.
I've successfully installed the Django REST framework, but I'm looking for a way to automatically create a URL for each field in my model. My model has about 100 fields, and each field has about 100,000 entries.
If my model is named Sample,
models.py
class Sample(models.Model):
index = models.IntegerField(primary_key=True)
year = models.IntegerField(blank=True, null=True)
name = models.TextField(blank=True, null=True)
...97 more fields...
then I can access the whole model using Django REST framework like this:
urls.py
class SampleSerializer(serializers.HyperlinkedModelSerializer):
class Meta:
model = Sample
fields = ( **100 fields**)
class SampleViewSet(viewsets.ModelViewSet):
queryset = Sample.objects.all()
serializer_class = SampleSerializer
router = routers.DefaultRouter()
router.register(r'sample', SampleViewSet)
But of course my browser can't load all of that data in a reasonable amount of time. I could manually make a different class and URL for each field, but there must be a better way... I want to be able to go to my_site.com/sample/year (for example) and have it list all of the years in JSON format, or my_site.com/sample/name and list all the names, etc.
Please help me figure out how to do this, thanks!
You might be able to do that using a custom viewset route.
You have this:
class ModelViewSet(ModelViewSet):
#list_route()
def sample_field(self, request):
desired_field = request.data.get('field', None)
if not desired_field:
return response # pseudocode
values = Model.objects.all().values_list(desired_field, flat=True)
# serialize this for returning the response
return Response(json.dumps(values)) # this is an example, you might want to do something mode involved
You will be able to get this from the url:
/api/model/sample_field/?field=foo
This extra method on the viewset will create a new endpoint under the samples endpoint. Since it's a list_route, you can reach it using /sample_field.
So following your code, it would be:
mysite.com/sample/sample_field/?field='year'
for example.
There are many interesting details in your question, but with this sample I think you might able to achieve what you want.
Try to use pagination. You can do it in almost the same way as in you question. Pagination in django lets you divide the results into pages. You don't have to display all the entries in the same page. I think this is the best option for you.
Refer django documentation on pagination:
Pagination in django

Specifying specific form format in Django

I am using materializecss to give my django site some material elements. I have put together a form (the 'old' way using html) but now realised I need to use a django form instead. The problem is, these forms don't play well with materialises built in column system (they use classes to determine rows and column spacing). Here is an example of the layout I set up so far. However when defining the form through form.py, it spits out one input per layer.
My question is: what can I do to either a) get django to work with the html-defined form or b) make a 'form template' to give the input fields the appropriate classes?
If you want to see the code I can post some but I'm quite a new coder so it's messy.
Thanks!
There are three ways I can think of off the top of my head.
If you want full control over the HTML form, in a Django template or HTML form, simply map the names of your fields to match the underlying field names in the Django form. This way, when POSTed back to your view, Django will automatically link up the POSTed fields with the Django form fields.
For example, if you have a field username in your Django form (or Django model if using ModelForm), you could have an element <input type="text" name="username" maxlength="40"> (that you can style any way you need) on your HTML form that Django will happily parse into your Django form field, assuming your view is plumbed correctly. There is an example of this method in the Django documentation.
Another way is to customize the Django form field widgets in your Django form definition. The Django documentation talks a little bit about how to do this. This is great for one offs, but is probably not the best approach if you expect to reuse widgets.
The final approach would be to subclass Django form field widgets to automatically provide whatever attributes you need. For example, we use Bootstrap and have subclassed nearly all of the widgets we use to take advantage of Bootstrap classes.
class BootstrapTextInput(forms.TextInput):
def __init__(self, attrs=None):
final_attrs = {'class': 'form-control'}
if attrs is not None:
final_attrs.update(attrs)
super().__init__(attrs=final_attrs)
Then it's simply a matter of letting the Django form know which widget to use for your form field.
class UsernameForm(forms.ModelForm):
class Meta:
model = auth.get_user_model()
fields = ['username']
widgets = {'username': BootstrapTextInput()}
Hope this helps. Cheers!

Django 1.9: How to make a dynamic form?

I have a model called Course:
class Course(models.Model):
number_of_semesters = models.PositiveIntegerField()
field = models.CharField(max_length=30)
qualification = models.ForeignKey(Qualification, on_delete=models.CASCADE)
I am trying to get a form in which you can input as many courses as the user wants from the webpage. How will I do this?
I know this is an old one, but I would recommend you to use Django Rest Framework. Although it is kind of tricky at first, you can use the ViewSets and Serializers to get multiple objects and save them in your database at once. (BTW, even though it is used for API's you can easily substitute the normal Django views with the ViewSets and use them as a standard).
I know this is not actually what you asked, but I have been developing in Django for a while now and I haven't been able to use the formsets in a clean way to save N objects without knowing N at first.
If you decide to go with my proposal, I would recommend you to read the following:
Viewsets
Serializers (they are basically the same as the DjangoForms)
Nested Serializers (for rendering/creating/linking your ForeignKey instance)
# SERIALIZER
from rest_framework import serializers
class QualificationSerializer(serializers.ModelSerializer):
class Meta:
model = Qualification
fields = (
# Insert the fields here, just like a form
)
class CourseSerializer(serializers.ModelSerializer):
qualification = QualificationSerializer() # Nested serializer
class Meta:
model = Course
fields = (
'number_of_semesters', 'field', 'qualification',
)
One way you could do this is to not use formsets but to get creative with the prefix that you use to load a form with. For example the + button loads an empty form with a prefix based on a counter posted to the view (including a tag, something like "course-4", so you get the form with SomeForm(request.POST, prefix="course-4")). When it's time to validate/save the view you simply parse the prefixes (with a regex) from the POST and save a form for every one of them.
It seems like a bit more work than to simply use formsets but every time I've tried to use them I had to abandon them at some point because they didn't provide enough flexibility.

Django Rest framework + EmberJS File upload update(patch)

I have a model like this:
// models.py
class MyModel(models.Model):
name = models.CharField(max_length=30, null=True, blank=True)
someboolean = models.BooleanField(default=False)
someotherBoolean = models.BooleanField(default=False)
myfilefield = models.FileField(upload_to='/files/')
Then i have a serializer like this:
// serializers.py
class MyModelSerializer(serializers.ModelSerializer):
class Meta:
model = MyModel
Then i have a View which inherit from RetrieveUpdateDestroyAPIView
This Django Rest setup is connected to the EmberJS and is running ok. The data from the server is retrived without any problem and the myfilefield content is represented like a string in ember which is a url to the actual file. When i think of uploading a file to the field on the Django Rest side it seems that i have to play a little with FileUploadParser to make it right and i think this is not much more lines of code into it.
But the issue is that my model on the Ember side should be updated in parts. Sometimes i need to update only the value of someboolean and do not send any files to myfilefield either because the file is already there or because this is done in the other UI iteration (separately). When in Ember i call this.get('model').save(); after some change to the someboolean is made it sends the whole model data back to django rest and the myfilefield in this json request is represented as a string and not as file thus the server returns an error.
As i understand there could be some workarounds to this situation:
The first would be to create custom serializers.CustomFileField which checks whether the provided string is equal to the url which is generated by the serializer on the output and if it is just leaves the file intact.
Second option would be to somehow implement the quick and dirty patch on the ember side which as i understand is still thing under development according to This Link. But this option seems to be quite hard as i have a lot of models with filefields and i should implement the patch method in ember for each and every one of them.
The third option as i forsee would be to create a special File model like so:
//models.py
class File(models.Model):
filebody = models.FileField(upload_to='/files/')
and make the myfilefield on the MyModel read_only so it won't validate at any time. I could also implement some method on the File model which would recieve the model and instance for which this file really belongs and after upload and validation would make the myfilefield = filebody
This method also seems very dirty but at least keeps some concepts abstracts so i wouldn't need to worry how many models with FileFields i actually have in my project.
My UI expects the user to do the change to one model field at a time and then save the model - i.e.
1. change the name field, save the model.
2. change the boolean field, save the model.
3. upload file, save the model.
Any suggestions on what would be the best way in terms of django rest to accomplish this considering the fact that ember still does not support PATCH requests.