Django template able to pass parameters? Getting the current user - python

In my template, I use a method in a model as follows...
The model is defined like this:
class Category(model.Model):
title = models.CharField('title', max_length=255)
description = models.TextField('description', blank=True)
def pub_set(self):
...
return somedata
The Template is used something like this:
{{ category.pub_set }}
I want to be able to get the current user in pub_set

I'm not 100% clear what you are asking. Inside of Category.pub_set() are you trying to access the request.user? If so, you can't do that unfortunately. There might be some sort of hack that will work, but it isn't the recommended way in Django.
You might want to check out template tags, they will allow you to pass your category and user from the template, and then do what you need to do, and return your result. Here is a link to the documentation.
http://docs.djangoproject.com/en/1.2/howto/custom-template-tags/#passing-template-variables-to-the-tag
Another approach is to do what you need to do in the view, and then save your result in the page context, where it will be available in the template.
If I had a little more insight into what you are trying to do, it might make it easier to steer you in the right direction.

Related

Django 'likes' - ManyToManyField vs new model

I'm implementing likes on profiles for my website and I'm not sure which would be the best practice, a ManyToManyField like so:
class MyUser(AbstractBaseUser):
...
likes = models.ManyToManyField('self', symmetrical = False, null = True)
...
or just creating a class Like, like so:
class Like(models.Model):
liker = models.ForeignKey(MyUser, related_name='liker')
liked = models.ForeignKey(MyUser, related_name='liked')
Is one of them a better choice than the other? If so, why?
thanks
The first option should be preffered. If you need some additional fields to describe the likes, you can still use through="Likes" in your ManyToManyField and define the model Likes.
Manipulating the data entries would be also somewhat more pythonic:
# returns an object collection
likes_for_me = MyUser.objects.filter(pk=1).likes
instead of:
me = MyUser.objects.filter(pk=1)
likes_for_me = Like.objects.filter(liked=me)
The second option is basically what is done internally: a new table is created, which is used to create the links between the entities.
For the first option, you let django do the job for you.
The choice is certainly more about how you want to do the requests. On the second options, you would have to query the Like models that match you model, while on the first one, you only have to request the MyUser, from which you can access the connections.
Second option is more flexible and extensible. For example, you'll probably want to track when like was created (just add Like.date_created field). Also you'll probably want to send notification to content author when content was liked. But at first like only (add Like.cancelled boolead field and wrap it with some logic...).
So I'll go with separate model.
I think the one you choose totally depends on the one you find easier to implement or better. I tend to always use the first approach, as it is more straightforward and logical, at least to me. I also disagree with Igor on that it's not flexible and extensible, you can also initiate notifications when it happens. If you are going to use the Django rest framework, then I totally suggest using the first method, as the second could be a pain.
class Post(models.Model):
like = models.ManyToManyField(settings.AUTH_USER_MODEL, blank=True, related_name='post_like')
Then in your view, you just do this.
#api_view(['GET'])
#permission_classes([IsAuthenticated])
def like(request, id):
signed_in = request.user
post = Post.objects.get(id=id)
if signed_in and post:
post.like.add(signed_in)
# For unlike, remove instead of add
return Response("Successful")
else:
return Response("Unsuccessful", status.HTTP_404_NOT_FOUND)
Then you can use the response however you like on the front end.

Unsure about what type of Django form I should use

I have an Author model with 200k instances in a MySQL database. I want to have the user search for an Author's unique ID (which is a string) and then select an ID which will then produce a table and small graphic about that author.
Do I want to use a charfield model form? Also, is there a built in search function?
I don't think Django has a builtin function for searching. You will have to use one of its extensions for this purpose (django-search or haystack).
They may seem too complicated for your case so I would go with simplier solution (and I would give up using form):
from django.views.generic import ListView
from django.db.models import Q
from .models import Author
def SearchAuthorView(ListView):
def get_queryset(self):
name = self.request.GET['author_name']
name_tokens = name.split(' ')
matched_authors = []
authors = Author.objects.all()
for author in authors:
for name_token in author.name.split(' '):
if name_token in name_tokens:
matched_authors.append(author)
break
return matched_authors
With 200k you may hit performance problems so if you do, you should use an optimized, raw MySql query.
You may also like to order your results somehow. For example give lastname's match a bigger priority than firstname's match.
Honestly I don't understand the question. You have a table called Author with 200k instances and you want to have possibility to find one of them. This can be done by simply function in views.py
def search_author(request, author_id):
author = Author.objects.get(id=author_id)
return render_to_response('your/path/to/template', {'author': author}, RequestContext(request))
Then in your template you just simply display the informations:
<div class="author">
<p>{{author.name}}</p>
<p>{{author.image}}</p>
</div>
Of course if your models.py looks like this:
class Author(models.Model):
name = models.CharField(max_number=100)
image ....

calling python function from django template tags

How can we pass a variable from a django template tag i.e, i want to do something like this
{{emp.get_names('a')}}
emp is the object that i am passing from my views
class Emp(models.Model):
name = models.CharField(max_length=255, unique=True)
address1 = models.CharField(max_length=255)
def get_names(self,var):
logging.debug(var)
names = {}
You can not call a function that takes a parameter like that. Maybe writing a custom template tag can help, but, why do you need to do it in the template, but not in the view??
Custom template tags
Django templates are designed to prevent people from doing what you are trying to do. Use a template tag.
It seems that it is not support calling the function in the default template like this.
maybe you can use some built-in tags like {{'a'|get_names}}
You can try to use Jinja2 template,which can let you write python code in it.

quick question: clear an attribute of a model in django

i think this is a pretty easy question for you.
I want to clear an attribute of a django-model.
If i have something like this:
class Book(models.Model):
name = models.TextField()
pages = models.IntegerField()
img = models.ImageField()
In an abstract function i want to clear an attribute, but at that time i don't know what type the field has. So examples would be name="", pages=0 or img=None.. Is there a way to do it in a generic way? I search something like SET_TO_EMPTY(book,"pages")
Do you know a function like that?
many thanks in advance!
I don't think there is a clean way of doing it. However, assuming you've set a default value (which you don't have) you can do it like this:
book.img = book._meta.get_field('img').default
Do note that your current model won't allow a None value. To allow those you have to set null=True and blank=True. For pages you need a default=0.

How to agnostically link any object/Model from another Django Model?

I'm writing a simple CMS based on Django. Most content management systems rely on having a fixed page, on a fixed URL, using a template that has one or many editable regions. To have an editable region, you require a Page. For the system to work out which page, you require the URL.
The problem comes when you're no longer dealing with "pages" (be those FlatPages pages, or something else), but rather instances from another Model. For example if I have a Model of products, I may wish to create a detail page that has multiple editable regions within.
I could build those regions into the Model but in my case, there are several Models and is a lot of variance in how much data I want to show.
Therefore, I want to build the CMS at template level and specify what a block (an editable region) is based on the instance of "page" or the model it uses.
I've had the idea that perhaps I could dump custom template tags on the page like this:
{% block unique_object "unique placeholder name" %}
And that would find a "block" based on the two arguments passed in. An example:
<h1>{{ product_instance.name }}</h1>
{% block product_instance "detail: product short description" %}
{% block product_instance "detail: product video" %}
{% block product_instance "detail: product long description" %}
Sounds spiffy, right? Well the problem I'm running into is how do I create a "key" for a zone so I can pull the correct block out? I'll be dealing with a completely unknown object (it could be a "page" object, a URL, a model instance, anything - it could even be a boat</fg>).
Other Django micro-applications must do this. You can tag anything with django-tagging, right? I've tried to understand how that works but I'm drawing blanks.
So, firstly, am I mad? And assuming I not, and this looks like a relatively sane idea to persue, how should I go about linking an object+string to a block/editable-region?
Note: Editing will be done on-the-page so there's no real issue in letting the users edit the zones. I won't have to do any reverse-mumbo-jumbo in the admin. My eventual dream is to allow a third argument to specify what sort of content area this is (text, image, video, etc). If you have any comments on any of this, I'm happy to read them!
django-tagging uses Django's contenttypes framework. The docs do a much better job of explaining it than I can, but the simplest description of it would be "generic foreign key that can point to any other model."
This may be what you are looking for, but from your description it also sounds like you want to do something very similar to some other existing projects:
django-flatblocks ("... acts like django.contrib.flatpages but for parts of a page; like an editable help box you want show alongside the main content.")
django-better-chunks ("Think of it as flatpages for small bits of reusable content you might want to insert into your templates and manage from the admin interface.")
and so on. If these are similar then they'll make a good starting point for you.
You want a way to display some object-specific content on a generic template, given a specific object, correct?
In order to support both models and other objects, we need two intermediate models; one to handle strings, and one to handle models. We could do it with one model, but this is less performant. These models will provide the link between content and string/model.
from django.db import models
from django.contrib.contenttypes.models import ContentType
from django.contrib.contenttypes import generic
CONTENT_TYPE_CHOICES = (
("video", "Video"),
("text", "Text"),
("image", "Image"),
)
def _get_template(name, type):
"Returns a list of templates to load given a name and a type"
return ["%s_%s.html" % (type, name), "%s.html" % name, "%s.html" % type]
class ModelContentLink(models.Model):
key = models.CharField(max_length=255) # Or whatever you find appropriate
type = models.CharField(max_length=31, choices= CONTENT_TYPE_CHOICES)
content_type = models.ForeignKey(ContentType)
object_id = models.PositiveIntegerField()
object = generic.GenericForeignKey('content_type', 'object_id')
def get_template(self):
model_name = self.object.__class__.__name__.lower()
return _get_template(model_name, self.type)
class StringContentLink(models.Model):
key = models.CharField(max_length=255) # Or whatever length you find appropriate
type = models.CharField(max_length=31, choices= CONTENT_TYPE_CHOICES)
content = models.TextField()
def get_template(self):
return _get_template(self.content, self.type)
Now, all we need is a template tag to grab these, and then try to load the templates given by the models' get_template() method. I'm a bit pressed on time so I'll leave it at this and update it in ~1 hour. Let me know if you think this approach seems fine.
It's pretty straightforward to use the contenttypes framework to implement the lookup strategy you are describing:
class Block(models.Model):
content_type = models.ForeignKey(ContentType)
object_id = models.PositiveIntegerField()
object = generic.GenericForeignKey() # not actually used here, but may be handy
key = models.CharField(max_length=255)
... other fields ...
class Meta:
unique_together = ('content_type', 'object_id', 'key')
def lookup_block(object, key):
return Block.objects.get(content_type=ContentType.objects.get_for_model(object),
object_id=object.pk,
key=key)
#register.simple_tag
def block(object, key)
block = lookup_block(object, key)
... generate template content using 'block' ...
One gotcha to be aware of is that you can't use the object field in the Block.objects.get call, because it's not a real database field. You must use content_type and object_id.
I called the model Block, but if you have some cases where more than one unique (object, key) tuple maps to the same block, it may in fact be an intermediate model that itself has a ForeignKey to your actual Block model or to the appropriate model in a helper app like the ones Van Gale has mentioned.

Categories