Obfuscated Django URL for model objects - django

I have a Django model that looks something like this:
class Person(models.Model):
name = models.CharField(max_length=32)
place = models.ForeignKey(Place, related_name='people')
approved = models.BooleanField()
objects = PersonManager()
#models.permalink
def get_absolute_url(self):
return('deal_details', (), {
'person_slug': slugify(self.name),
})
As you could see, I already have an absolute URL for the object. However, I want to create a difficult-to-guess URL to keep track of the approval process of the object. Anyone done something similar and/or have any suggestions on how I should proceed?
My first thought was creating a model field like obfuscated_key that is generated randomly via the save function of the model. Then the URL would look something like /people/status/<id>/<obfuscated_key>/. But perhaps there's a better way to go about this?

A good way to do this would be to hash the object's ID with the installation's secret key (from settings.py). This is what the password reset email form does - there's some useful code in django.contrib.auth.tokens - and, in the very latest SVN versions, django.contrib.auth.crypto.

Something like a URL shortener (read: obfuscating) might work.
http://djangosnippets.org/snippets/1323/

I've used UUIDField to do something similar.
In the model:
uuid = UUIDField(auto=True)
then in the view check the id and uuid:
item = get_object_or_404(Item, id=id, uuid__exact=uuid)
The UUIDField is from http://djangosnippets.org/snippets/335/

Related

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

In Django, can I create an extra custom manager for a reverse ManyToMany relationship?

I want to create an extra manager for fetching a filtered version of a reverse ManyToMany relationship. I have these models:
class Photo(models.Model):
# ...
is_public = models.BooleanField()
albums = models.ManyToManyField('Album')
class Album(models.Model):
# ...
I can get all the photos in an album with album.photo_set.all(). I'd like to provide a way to get only the public photos in an album by doing album.photo_set.public() (which would, somewhere, do a .filter(is_public=True)).
I guess I'm wanting to provide an extra Related manager, but I'm not sure that's possible. I don't want, or need, to replace the default related manager (which sounds like a bad idea anyway). I don't need a custom through model for the relationship, unless that's the only way to achieve this.
Sure, you could make a related manager but that seems a bit overkill for this.
Why not just simply add a function to your model that returns only the public photos in the album?
def get_public(self):
return self.photo_set.filter(is_public = True)
You can create manager like this:
class PublicManager(models.Manager):
use_for_related_fields = True
def public(self, *args, **kwargs):
kwargs.update({
'is_public': True
})
return self.get_queryset().filter(*args, **kwargs)

Django check if object in ManyToMany field

I have quite a simple problem to solve. I have Partner model which has >= 0 Users associated with it:
class Partner(models.Model):
name = models.CharField(db_index=True, max_length=255)
slug = models.SlugField(db_index=True)
user = models.ManyToManyField(User)
Now, if I have a User object and I have a Partner object, what is the most Pythonic way of checking if the User is associated with a Partner? I basically want a statement which returns True if the User is associated to the Partner.
I have tried:
users = Partner.objects.values_list('user', flat=True).filter(slug=requested_slug)
if request.user.pk in users:
# do some private stuff
This works but I have a feeling there is a better way. Additionally, would this be easy to roll into a decorator, baring in mind I need both a named parameter (slug) and a request object (user).
if user.partner_set.filter(slug=requested_slug).exists():
# do some private stuff
If we just need to know whether a user object is associated to a partner object, we could just do the following (as in this answer):
if user in partner.user.all():
#do something

Advice on returning a single object in django

I am working on an online food ordering service and i have worked on most of the functionality. At the moment on request, i want the app to be able to return the menu of a given restaurant as requested by user. Am thinking the logic has something to do with the Primary Key but i don't know how to go about this.
Thank you in advance and have a blessed christmas..
you can use the get() method to get a single object from the model if you know it's id (or primary key). Look at the documentation on how to retrieve a single object with get.
For Example
#models.py
class Menu(models.Model):
title = models.CharField(max_length=50)
#views.py
def get_menu(request, menu_id):
menu = get_object_or_404(models.Menu, pk=menu_id)
data = {'menu' : menu}
return render_to_response('menu.html', data, context_instance=RequestContext(request))
#urls.py
url(r'^menu/(?P<menu_id>\d+)/$', 'yourappname.views.get_menu')

Django save image using upload_to instance keeps instance properties None

I Am trying to give an uploaded image a nicer path, using this code (in models.py):
def get_image_path_photos(instance, filename):
return os.path.join('photos', str(instance.someproperty), filename)
and the model
class Photo(models.Model):
someproperty = models.CharField(max_length=17, blank=False, null=False, default="something")
photo = models.ImageField(upload_to=get_image_path_photos, blank=True, null=True)
When I save this after a new insert, it saves it in the path /photos/something/ (it keeps using the default value).
When I edit it, add a photo and save it, it will save it to the correct path.
So it must have something to do that while saving the new object, it doesn't exist yet.
I tried the same with instance.id and this keeps being None as well (I read using auto increment on the id solves this, but this sounds as using the default value as well, and using the default pk/id is auto increment).
I found some simular questions, but none with the answer that solves my problem.
I thought of going to use the pre_save signal.... but somehow my guts says this isn't the right way.
The solution of my problem I found out myselve, please see my answer... A good lesson, don't use slugname definitions the same as the field name.....
Sorry about this. The problem is a bit more complicated. I use the field someproperty also in the url as a slug on the posts....
I just found out something I didn't expected.
i did my post (using django rest framework) from the url using the default value in the url... but I filled in the field with something else.
than, because I define the slugname the same as the fieldname, it overwrites anything you fill in in the field with the value from the url....
This isn't exactly what I meant to be done, but makes sence.
Probably the solution is to call the slug name not the same as the field name......
I keep this question and answer anyway, because for me it was quite a puzzle..... (might be of help to somebody)
as an addition to the answer of jpic:
I used the urls in django rest framwwork, lets say; http:\someurl\api\photos\\
and post there the photo.
posting the photo avatar_big.png using someproperty=bar:
saved the photo in photos\something\ when using the url http\someurl\api\photos\something
and saved the photo in photos\bar\ when using the url http:\someurl\api\photos\bar
the problem is (i guess, still have to check this) that the slug name I use for the url is the same as the fieldname.
this is the code I use in views.py (class based view I use in the django-rest-framework):
class PhotoBySomePropertyListOrCreateModelView(ListOrCreateModelView):
permissions = (IsAuthenticated, )
form = PhotoForm
def get_queryset(self):
someproperty=self.kwargs['someproperty']
return Photo.objects.filter(someproperty=someproperty)
and in urls.py:
url(r'^api/photos/(?P<someproperty>[\w:]+)/$', PhotoBySomePropertyListOrCreateModelView.as_view(resource=PhotoResource)),
here you see the problem, it doesn't listen to the field in 'someproperty', but to the value in the url ....
changing it in
url(r'^api/photos/(?P[\w:]+)/$', PhotoBySomePropertyListOrCreateModelView.as_view(resource=PhotoResource)),
should do the trick.... also adjust the view of course