Django Rest framework + EmberJS File upload update(patch) - django

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.

Related

When and where is `Field.blank` checked by DRF?

I have a model
class SomeModel(models.Model):
emails = ArrayField(models.EmailField(), default=list)
And let's say I have the following Serializer of the model:
class SomeModelSerializer(serializers.ModelSerializer):
class Meta:
model = SomeModel
fields = ['emails']
The email field is not blank-able, i.e: It's required to set a value for it when submitting a Form of the model, or when making changes to its Admin page.
My understanding is that DRF relies as well on Django's internal machinery to validate whether emails is missing on the Serializer data or not. But the thing is that I can't find where (and when) this happens.
I've found that DRF is not calling the Model's clean() method anymore (link). But what baffles me is that changing the blank value on the field seems to have a direct impact on the Serializer. I have switched to blank=True, and then the Serializer would allow it to be saved without that field... Then I switched back to blank=False, and the Serializer would fail if emails is not present.
So do you have any idea of when and where DRF checks for a field's blank value?
Thanks!
As far as I know, it simply doesn't. Those are only used across forms and the django admin interface.
I always specify those things on the serializer level, by setting the appropiate arguments for my fields (doc), in this case it would be allow_blank.
I am building REST APIs with django, and the only case where the blank property on the model field catches me, is when fiddling around on the admin page.
However, there appears to be a package that could be of interest to you:
django-seriously.
I haven't used it, but it appears to call full_clean() on every save().
Of course, this has the disadvantage that you will probably loose DRFs nice error messages.

Django REST Framework - Change ID Format

I am currently playing around with Django + Django REST Framework to build an API layer. A question I was curious about is if it's possible to change the id layout. Currently my model looks something like this:
class Thing(models.Model):
name = models.CharField(max_length=100)
class ThingContainer(models.Model):
name = models.CharField(max_length=100)
things = models.ManyToManyField(Thing)
This means that DRF (using ModelViewSet and ModelSerializer) automatically generates API endpoints like /things/1 or /thing_containers/2.
I was wondering if there is a neat trick to change the format of the outward-facing ID. So instead of /things/1 it would be /things/YXBwOi8vdGhpbmcvMQ== which is the base64 encoding of app://things/1.
I am aware that I could change the key of the model itself into a CharField and enforce that format on the DB level. However that comes with its own set of performance issues and other caveats.
You should override method retrieve in viewset. And fix url in urlpatterns

django rest framework and forms: How to do

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

Django - Customizeable UserProfile

So I've got a UserProfile in Django that has certain fields that are required by the entire project - birthday, residence, etc. - and it also contains a lot of information that doesn't actually have any importance as far as logic goes - hometown, about me, etc. I'm trying to make my project a bit more flexible and applicable to more situations than my own, and I'd like to make it so that administrators of a project instance can add any fields they like to a UserProfile without having to directly modify the model. That is, I'd like an administrator of a new instance to be able to create new attributes of a user on the fly based on their specific needs. Due to the nature of the ORM, is this possible?
Well a simple solution is to create a new model called UserAttribute that has a key and a value, and link it to the UserProfile. Then you can use it as an inline in the django-admin. This would allow you to add as many new attributes to a UserProfile as you like, all through the admin:
models.py
class UserAttribute(models.Model):
key = models.CharField(max_length=100, help_text="i.e. Age, Name etc")
value = models.TextField(max_length=1000)
profile = models.ForeignKey(UserProfile)
admin.py
class UserAttributeInline(admin.StackedInline):
model = UserAttribute
class UserProfile(admin.ModelAdmin):
inlines = [UserAttibuteInline,]
This would allow an administrator to add a long list of attributes. The limitations are that you cant's do any validation on the input(outside of making sure that it's valid text), you are also limited to attributes that can be described in plain english (i.e. you won't be able to perform much login on them) and you won't really be able to compare attributes between UserProfiles (without a lot of Database hits anyway)
You can store additional data in serialized state. This can save you some DB hits and simplify your database structure a bit. May be the best option if you plan to use the data just for display purposes.
Example implementation (not tested)::
import yaml
from django.db import models
class UserProfile(models.Model):
user = models.OneToOneField('auth.User', related_name='profile')
_additional_info = models.TextField(default="", blank=True)
#property
def additional_info(self):
return yaml.load(self._additional_info)
#additional_info.setter
def additional_info(self, user_info_dict):
self._additional_info = yaml.dump(user_info_dict)
When you assign to profile.additional_info, say, a dictionary, it gets serialized and stored in _additional_info instead (don't forget to save the instance later). And then, when you access additional_info, you get that python dictionary.
I guess, you can also write a custom field to deal with this.
UPDATE (based on your comment):
So it appears that the actual problem here is how to automatically create and validate forms for user profiles. (It remains regardless on whether you go with serialized options or complex data structure.)
And since you can create dynamic forms without much trouble[1], then the main question is how to validate them.
Thinking about it... Administrator will have to specify validators (or field type) for each custom field anyway, right? So you'll need some kind of a configuration option—say,
CUSTOM_PROFILE_FIELDS = (
{
'name': 'user_ip',
'validators': ['django.core.validators.validate_ipv4_address'],
},
)
And then, when you're initializing the form, you define fields with their validators according to this setting.
[1] See also this post by Jacob Kaplan-Moss on dynamic form generation. It doesn't deal with validation, though.

Multiple images per Model

I'm writing a simple real-estate listing app in Django. Each property needs to have a variable number of images. Images need to have an editable order. And I need to make the admin user-proof.
So that said, what are my options?
Is there a ImageList field that I don't know about?
Is there an app like django.contrib.comments that does the job for me?
If I have to write it myself, how would I go about making the admin-side decent? I'm imagining something a lot slicker than what ImageField provides, with some drag'n'drop for re-ordering. But I'm a complete clutz at writing admin pages =(
Variable lists, also known as a many-to-one relationship, are usually handled by making a separate model for the many and, in that model, using a ForeignKey to the "one".
There isn't an app like this in django.contrib, but there are several external projects you can use, e.g. django-photologue which even has some support for viewing the images in the admin.
The admin site can't be made "user proof", it should only be used by trusted users. Given this, the way to make your admin site decent would be to define a ModelAdmin for your property and then inline the photos (inline documentation).
So, to give you some quick drafts, everything would look something like this:
# models.py
class Property(models.Model):
address = models.TextField()
...
class PropertyImage(models.Model):
property = models.ForeignKey(Property, related_name='images')
image = models.ImageField()
and:
# admin.py
class PropertyImageInline(admin.TabularInline):
model = PropertyImage
extra = 3
class PropertyAdmin(admin.ModelAdmin):
inlines = [ PropertyImageInline, ]
admin.site.register(Property, PropertyAdmin)
The reason for using the related_name argument on the ForeignKey is so your queries will be more readable, e.g. in this case you can do something like this in your view:
property = Property.objects.get(pk=1)
image_list = property.images.all()
EDIT: forgot to mention, you can then implement drag-and-drop ordering in the admin using Simon Willison's snippet Orderable inlines using drag and drop with jQuery UI
Write an Image model that has a ForeignKey to your Property model. Quite probably, you'll have some other fields that belong to the image and not to the Property.
I'm currently making the same thing and I faced the same issue.
After I researched for a while, I decided to use django-imaging. It has a nice Ajax feature, images can be uploaded on the same page as the model Insert page, and can be editable. However, it is lacking support for non-JPEG extension.
There is a package named django-galleryfield. I think it will meet your demand.