I have a model named File which contains a field named 'url'.
class File(models.Model):
"""
Generic File model
"""
filename = models.CharField(max_length=500)
url = models.URLField()
Now if I pass this URL :
https://s3.us-east-2.amazonaws.com/xyz/2018-09-25_17:39:16.80 (1).pdf
Note the space in the url before (1). The model serializer gives an error stating that the url is invalid.
Do I need to encode the url myself by replacing the space with '%20'
First of all, generate files without whitespaces if possible. That would be a better solution.
If it's not possible, change the URLField() to CharField(), which will compromise the URL Validation. But, it's possible to use as a valid url.
If you still want to use URLField(), write a custom validator and add it via validator parameter
def custom_url_validator(value):
# your validation
class File(models.Model):
"""
Generic File model
"""
filename = models.CharField(max_length=500)
url = models.URLField(validators=[custom_url_validator,])
Related
If I wanted to send the blogpost id to the url pattern, and have the url automatically turn into something like www.blog.com/post/2/this-is-my-second-blogpost, how might I do that?
Inside of urls.py I have a url pattern that accepts the blogpost id, and its title. It doesn't seem to be working, and once it does, would be tedious to add the title for every page in this manner.
urls.py:path('post/<int:post_id>/<str:post_title>', views.view_post, name='view_post'),
blogposts.html template:
Read More
views.py: def view_post(request, post_id, post_title):.
Simply, add the default argument of post_title to be None. If you are wishing to get the post_title directly from the post_id, neclect the post_title, doing this won't give you error as functions already got all the satisfied argument values.
So:
def view_post(request, post_id, post_title=None):
Edit
Okay, what user wanted was about slug field. Slug field is the field type in django model. Basically, it is used for the url type. In above problem, what pyknight202 wanted was the url patter for the post_title. So, you could not use tilte directly as url as they contain spaces, so for that you have to add post_title in hyphens or underscore to be readable. Therefore, you need slug field in Post model.
https://helloworld.com/1/this-is-example
So, 1 is post_id as slug could not be unique, so you could not only retrieve from post_title therefore you need post_id too. Refs
Maybe you should use a slug field for the url instead of the combination of id and title, your url will look like example.org/title-to-object-2/.
Now you have a unique slug field with the title and the id.
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
I have model UserProfile:
class UserProfile(models.Model):
user = models.OneToOneField(User)
and serializer:
email = serializers.CharField(source='user.email', required=False,
validators=[UniqueValidator(queryset=User.objects.all())])
Serialization works fine, but deserialization doesn't — it tries to file 'user.email' field in User model, and, of course, fails.
If I change User to UserProfile in the queryset, it fails with another error:
invalid literal for int() with base 10: 'admin#localhost'
Is it possible to set different sources for serialization and deserialization?
By default, the UniqueValidator expects that the source (or field name, if no source is given) can be used in the queryset that is provided to filter out the existing object. So by using a source that spans a relation (and has a dot), it will try to use that name when filtering the queryset which fails, as you've noticed.
You can fix this by subclassing UniqueValidator to override the filter_queryset method to filter it differently.
class CustomUniqueValidator(UniqueValidator):
def filter_queryset(self, value, queryset):
"""
Filter the queryset to all instances matching the given attribute.
"""
filter_kwargs = {"email": value}
return queryset.filter(**filter_kwargs)
This hard codes email as the filter, one possible option for not hard coding it would be to split self.field_name and get the last part of the dotted source.
I'm using Mongodb with mongoengine as a backend for a API in Django.
The framework I'm using to create the api is Django Rest Framework.
I need to store a dictionary in a field in Mongo and the best I've done when the method post is called is to use a charfield and parse the dictionary in the function restore_object.
There is a better way to achieve this goal?
It's better to create a dict field? I don't know how hard this could be.
Thank you.
edited to show some code, notice that I store the dictionary as a dict (DictField) and it's content could change from one object to other.
my mongoengine model is something like:
class MyDoc(mongoengine.Document):
name = mongoengine.StringField(max_length=200)
context = mongoengine.DictField()
and my serializer something like:
class MyDocSerializer(serializers.Serializer):
name = serializers.CharField(max_length=200)
context = serializers.CharField()
url = serializers.HyperlinkedIdentityField(
view_name="drf:mydoc-detail",)
def __init__(self,*args,**kwargs):
super(MyDocSerializer,self).__init__(*args,**kwargs)
def restore_object(self, attrs, instance=None):
# Parse string to dict
# this is so ugly, notice I had to repace ' for " to
# avoid an error parsing the json
context = JSONParser().parse(
StringIO.StringIO(
attrs['context'].replace("'","\"")
)
)
attrs['context'] = context
if instance is not None:
instance.name = attrs['name']
instance.context = context
return instance
return MyDoc(**attrs)
Rather than deal with the dictionary field in the Serializer's restore_object, you'll probably end up with something slightly cleaner, if instead you use a custom field for the dictionary field, that manages converting between the dictionary representation and internal char based storage.
You'll want to subclass serializers.WritableField and override the to_native() and from_native methods.
Relevant docs here.
Note: WritableField class that was present in version 2.x no longer exists. You should subclass Field and override to_internal_value() if the field supports data input.
Update: As of 3.0.4 you can now use serializers.DictField... http://www.django-rest-framework.org/api-guide/fields/#dictfield
I am using django 1.4 and using django model's filefield to upload some document via modelform. I am having following issues:
When I submit form it says:
Data truncated for column 'file_name' at row 1
Following is my model for this:
class App(models.Model):
user_name=models.CharField(max_length=50)
email=models.CharField(max_length=50)
status=models.CharField(max_length=10,choices=APPLICATIONSTATUSCHOICE)
archived=models.BooleanField()
mark_spam=models.BooleanField()
date=models.DateField()
file_name=models.FileField(upload_to=PATH+"/")
def getPath(self):
return PATH
def __unicode__(self):
return self.user_name
def send_email(self):
pass
Here is the code for model form:
class AppForm(ModelForm):
class Meta:
model=App
exclude=('status','archived','mark_spam')
email=forms.EmailField()
def save(self,commit=True):
app=super(AppForm,self).save(commit=False)
app.status='sent'
app.save()
Also it is storing file with its original name,can I have it with something unique name as I am from PHP background and in PHP I normally save it like <mysql auto id>.<filextension>, so how can I do it in django. My first impression was that all this will be automatically done via django while it just save it with name of its own choice but I need to save names into db also so want to name them according to my choice. How can it be done and what is problem in my code that is giving above mentioned error?
How long is the file_name you are trying to store?
By default, FileField instances are created as varchar(100) columns in your database. As with other fields, you can change the maximum length using the max_length argument. That might be resulting the data truncation error.
Also you can rename your file whatever you want. the upload_to can be a callable that takes the instance and the name of the uploaded file as input and then you can specify the exact name and path you want to store.
Eg.
def get_file_name(instance, filename):
return '/'.join(['blah', instance.user.username, filename])
...
file_name=models.FileField(upload_to=get_file_name)
...