My first question helped me a LOT, so I figured I'd go ahead and ask a second one.
My current (practice) project is to create a generalized model. Here's what I've written so far:
from django.db import models
from django.contrib.auth.models import User
# Create your models here.
class Block(models.Model):
title = models.CharField(man_length=50)
#Make sure child classes have content defined!
#content = models.BooleanField(default=False)
owner = models.ForeignKey('User')
access = models.ManytoManyField('User', null=True)
links = models.ManytoManyField('self', null=True)
class Meta:
abstract = True
def __unicode__(self):
return self.title
class Text(Block)
content = models.TextField(max_length=100)
class URL(Block)
content = models.URLField()
class Email(Block)
content = models.EmailField()
Please note I haven't actually tested this yet - I don't think my logic on this so far is going to work.
A few goals:
1) owner there points to the creator of the block. I think that should work.
2) access should point to Users (other than the owner) who can edit the block. I think this should work too. (with proper views of course)
3) links should allow linking between blocks - so I can retrieve a block and any related blocks (and so on up if need be)
4) content should of course be the content of the block(I have the three sample simple data types here), which ideally can be any number of things (implemented here via the abstract base class).
5) For the classes Email, URL, and Text, I'd like to be able to write a (generalized) view which from one url input, returns an appropriate block of any of the three types. I think this may require an autoincrementing field which guarantees a unique value between the three models. Honestly, I'm not sure how to do this at all.
6) Of course ideally this should be readily extensible if at all possible.
I'm of course very unsure if this is the best way to go about achieving what I'm trying to do. Any suggestions, help, tips, tricks, or bad jokes accepted!
Thank you very much for your help!
EDIT: relating to number 5, I have a rough view (with a syntax error) that I think might do the trick:
def getblock(request, block, no):
data = get_object_or_404(%s,%s) % (block,no)
return render_to_response('single.html',{'data':data})
Thoughts?
Your code seems correct to me. I also worked on a generic class for my project and it was similar to this one. One remark, when you get a block, you should do some type checking to retrieve the class data so, I recommend you to add a field to store its type. e.g:
class Block(models.Model):
title = models.CharField(max_length=50)
type = models.IntegerField()# 1 for text, 2 for email and 3 for url
#Make sure child classes have content defined!
#content = models.BooleanField(default=False)
owner = models.ForeignKey('User')
access = models.ManytoManyField('User', null=True)
links = models.ManytoManyField('self', null=True)
Then in your view:
def getblock(request, block, no):
if block.type == 1:
data = get_object_or_404(Block,id=no).text
elif block.type == 2:
data = get_object_or_404(Block,id=no).email
elif block.type == 3:
data = get_object_or_404(Block,id=no).url
return render_to_response('single.html',{'data':data})
You can access the subclasses with lower case representation of that child class. I think that will work nicely. Also I don't get the dictionary type arguments you wrote and that gave a syntax error when I executed. Anyway, I also corrected some of the syntax errors, too.
Related
Please help me. There is a Django project with circular import. Project's applications are connected only one side. But there are functions that use other models without params (for using in template) and that makes it impossible to move the function.
I have found two solutions:
First way is to import model inside function.
And another way it to move two models into one file.
Both solutions work without problem, but which one is better?
class InitialArticle(models.Model):
by = models.ForeignKey(get_user_model(), null=True, on_delete = models.SET_NULL)
category = models.ForeignKey(ArticleCategory, null=True, on_delete=models.CASCADE)
keywords = models.CharField(max_length = 110, unique = True)
def get_articles_of_initialarticle(self):
from article.models import Article
return Article.objects.filter(initial = self)
Please help me find a better way. Maybe there is another solution?
You can add related_name in Article.initial like so:
class Article(...):
initial = models.ForeignKey(to='InitialArticle', related_name='articles')
After that you can use it like so:
initial_article = InitialArticle.objects.filter(...).first()
initial_article.articles.all() # return all articles which have foreign key to this article
Also in models.ForeignKey you can use string instead of importing the model like I have written
Or you can do it without adding related_name.
Default related name will be like so: article_set
And if you do not set related_name you can write like so:
initial_article = InitialArticle.objects.filter(...).first()
initial_article.article_set.all() # return all articles which have foreign key to this article
Consider these three models:
class Statement(models.Model):
statement_id = models.CharField(max_length=200)
title = models.CharField(max_length=200)
statement-keywords = ?
statement-contexts = ?
class Keyword(models.Model):
word = models.CharField(max_length=200)
statement = models.ManyToManyField(Statement)
def __str__(self):
return self.word
#python_2_unicode_compatible
class Context(models.Model):
context_word = models.CharField(max_length=200)
keyword = models.ManyToManyField(Keyword)
statement = models.ManyToManyField(Statement)
def __str__(self):
return self.context_word
Every Statement is supposed to have a set of associated Keywords and Contexts. I am also working mainly on the admin interface of this website, and wanted to ensure that someone could enter in keywords and contexts on the same page for updating or submitting a new page.
It would be ideal if I could make statement-keywords hold a set of all Keywords's, and statement_contexts hold a set of all associated keywords to that statement instance, and statement-context hold a set of all Context's associated with that statement. But there are two issues that come up for me:
Because Statement is above Keyword and Context, I can't reference Keyword and Context as objects in a manytomany relationship. If I do so, I get an error message. If I move Statement below Keyword and Context, then Keyword and Context would both be unable to make a reference Statement (I would get an error message).
I do not know the if there's a fieldtype that could say "this field is going to hold a set of objects," or an alternative to that.
You don't need either of those fields. You already have them: they are the reverse relations from the ManyToManyFields on Keyword and Context.
I'm really having a difficult time grasping the concept of Django's content types. It feels very hackish and, ultimately, against how Python tends to do things. That being said, if I'm going to use Django then I have to work within the confines of the framework.
So I'm coming here wondering if anyone can give a practical real world example of how a content type works and how you would implement it. Almost all the tutorials (mostly on blogs) I have reviewed don't do a great job really covering the concept. They seem to pick up where the Django documentation left off (what seems like nowhere).
So you want to use the Content Types framework on your work?
Start by asking yourself this question: "Do any of these models need to be related in the same way to other models and/or will I be reusing these relationships in unforseen ways later down the road?" The reason why we ask this question is because this is what the Content Types framework does best: it creates generic relations between models. Blah blah, let's dive into some code and see what I mean.
# ourapp.models
from django.conf import settings
from django.db import models
# Assign the User model in case it has been "swapped"
User = settings.AUTH_USER_MODEL
# Create your models here
class Post(models.Model):
author = models.ForeignKey(User)
title = models.CharField(max_length=75)
slug = models.SlugField(unique=True)
body = models.TextField(blank=True)
class Picture(models.Model):
author = models.ForeignKey(User)
image = models.ImageField()
caption = models.TextField(blank=True)
class Comment(models.Model):
author = models.ForeignKey(User)
body = models.TextField(blank=True)
post = models.ForeignKey(Post)
picture = models.ForeignKey(Picture)
Okay, so we do have a way to theoretically create this relationship. However, as a Python programmer, your superior intellect is telling you this sucks and you can do better. High five!
Enter the Content Types framework!
Well, now we're going to take a close look at our models and rework them to be more "reusable" and intuitive. Let's start by getting rid of the two foreign keys on our Comment model and replace them with a GenericForeignKey.
# ourapp.models
from django.contrib.contenttypes.fields import GenericForeignKey
from django.contrib.contenttypes.models import ContentType
...
class Comment(models.Model):
author = models.ForeignKey(User)
body = models.TextField(blank=True)
content_type = models.ForeignKey(ContentType)
object_id = models.PositiveIntegerField()
content_object = GenericForeignKey()
So, what happened? Well, we went in and added the necessary code to allow for a generic relation to other models. Notice how there is more than just a GenericForeignKey, but also a ForeignKey to ContentType and a PositiveIntegerField for the object_id. These fields are for telling Django what type of object this is related to and what the id is for that object. In reality, this makes sense because Django will need both to lookup these related objects.
Well, that's not very Python-like... it’s kinda ugly!
You are probably looking for air-tight, spotless, intuitive code that would make Guido van Rossum proud. I get you. Let's look at the GenericRelation field so we can put a pretty bow on this.
# ourapp.models
from django.contrib.contenttypes.fields import GenericRelation
...
class Post(models.Model):
author = models.ForeignKey(User)
title = models.CharField(max_length=75)
slug = models.SlugField(unique=True)
body = models.TextField(blank=True)
comments = GenericRelation('Comment')
class Picture(models.Model):
author = models.ForeignKey(User)
image = models.ImageField()
caption = models.TextField(blank=True)
comments = GenericRelation('Comment')
Bam! Just like that you can work with the Comments for these two models. In fact, let's go ahead and do that in our shell (type python manage.py shell from your Django project directory).
>>> from django.contrib.auth import get_user_model
>>> from ourapp.models import Picture, Post
# We use get_user_model() since we are referencing directly
User = get_user_model()
# Grab our own User object
>>> me = User.objects.get(username='myusername')
# Grab the first of our own pictures so we can comment on it
>>> pic = Picture.objects.get(author=me)
# Let's start making a comment for our own picture
>>> pic.comments.create(author=me, body="Man, I'm cool!")
# Let's go ahead and retrieve the comments for this picture now
>>> pic.comments.all()
[<Comment: "Man, I'm cool!">]
# Same for Post comments
>>> post = Post.objects.get(author=me)
>>> post.comments.create(author=me, body="So easy to comment now!")
>>> post.comments.all()
[<Comment: "So easy to comment now!"]
It's that simple.
What are the other practical implications of these "generic" relations?
Generic foreign keys allow for less intrusive relations between various applications. For example, let's say we pulled the Comment model out into its own app named chatterly. Now we want to create another application named noise_nimbus where people store their music to share with others.
What if we want to add comments to those songs? Well, we can just draw a generic relation:
# noise_nimbus.models
from django.conf import settings
from django.contrib.contenttypes.fields import GenericRelation
from django.db import models
from chatterly.models import Comment
# For a third time, we take the time to ensure custom Auth isn't overlooked
User = settings.AUTH_USER_MODEL
# Create your models here
class Song(models.Model):
'''
A song which can be commented on.
'''
file = models.FileField()
author = models.ForeignKey(User)
title = models.CharField(max_length=75)
slug = models.SlugField(unique=True)
description = models.TextField(blank=True)
comments = GenericRelation(Comment)
I hope you guys found this helpful as I would have loved to have come across something that showed me the more realistic application of GenericForeignKey and GenericRelation fields.
Is this too good to be true?
As with anything in life, there are pros and cons. Anytime you add more code and more abstraction, the underlying processes becomes heavier and a bit slower. Adding generic relations can add a little bit of a performance dampener despite the fact it will try and smart cache its results. All in all, it comes down to whether the cleanliness and simplicity outweighs the small performance costs. For me, the answer is a million times yes.
There is more to the Content Types framework than I have displayed here. There is a whole level of granularity and more verbose usage, but for the average individual, this is how you will be using it 9 out of 10 times in my opinion.
Generic relationizers(?) beware!
A rather large caveat is that when you use a GenericRelation, if the model which has the GenericRelation applied (Picture) is deleted, all related (Comment) objects will also be deleted. Or at least as of the time of this writing.
Ok well the direct answer to your question: ( from the django source code ) is:
Media Types parsing according to RFC 2616, section 3.7.
Which is the tears way of saying that it reads/allows-you-to-modify/passes along the 'Content-type' httpd header.
However, you are asking for a more practice usage example. I have 2 suggestions for you:
1: examine this code
def index(request):
media_type='text/html'
if request.META.has_key('CONTENT_TYPE'):
media_type = request.META['CONTENT_TYPE'].split(';')[0]
if media_type.lower() == 'application/json':
return HttpResponse("""{ "ResponseCode": "Success"}""", content_type="application/json; charset=UTF-8")
return HttpResponse("<h1>regular old joe</h1>");
2: remember django is python, and as such it wields the power of the python community.
There are 2 awesome RESTFul plugins to django. So if you want to see how deep the rabbit whole goes you can check out.
django rest framework
tastypie
I suggest going through the django-rest-framework tutorial which will address 'acting on different content/types' specifically.
Note: It is common practice to use the content-type header to 'version' restful API's.
I am trying to get rate of the user who has written the comment.
this is the scenario:
I hold the comment about Something in my hand, I hold the user in my hand who wrote this comment Something. Now I need to know the rate which is given by the user to this Something.
these are my models:
class Rate(models.Model):
of_user_r = models.ForeignKey(User)
of_something_r = models.ForeignKey(Something)
rate = models.IntegerField()
class Comment(models.Model):
of_user_c = models.ForeignKey(User)
of_something_c = models.ForeignKey(Something)
i did: {{comment.of_user_c.of_user_r.rate}}, but I getting nothing in template.
this is the vusual:
I need the rate of this Something which is given by this User.
Yes, your attempt doesn't work because the relationship from User to Rate is backwards. This means you can't do that query directly in the template: you'd need a model method or a template filter that accepts arguments. The basic query syntax would be:
Rate.objects.filter(user=comment.user)
Let's say that I have two teams, "red" and "black". And let's say that I have a Story class, which presents similar information in two very different ways, depending on your team:
class Story(models.Model):
red_title = models.CharField()
black_title = models.CharField()
red_prologue = models.TextField()
black_prologue = models.TextField()
# ... and so on ...
def get_field(self, genericName, team):
"""Return the field with suffix genericName belonging to the given team.
>>>self.get_field("prologue", "red") is self.red_prologue
True
>>>self.get_field("title", "black") is self.black_title
True
"""
assert(team in ["red", "black"])
specificName = "{}_{}".format(team, genericName)
return self.__dict__[specificName]
I'm happy with the getter function, but I feel like I should be able to refactor the code which created the fields in the first place. I'd like a function that looks something like this:
def make_fields(self, genericName, fieldType, **kwargs):
"""Create two fields with suffix genericName.
One will be 'red_{genericName}' and one will be 'black_{genericName}'.
"""
for team in ["red", "black"]:
specificName = "{}_{}".format(team, genericName)
self.__dict__[specificName] = fieldType(**kwargs)
But self and __dict__ are meaningless while the class is first defined, and I think Django requires that database fields be class variables rather than instance variables.
So... is there some way to create this make_fields function within Django, or am I out of luck?
Not sure why you're even doing this. A much more sane model would be:
TEAMS = (
("r","red"),
("b","black"),
)
class Story(models.Model):
team = models.CharField(max_length=1, choices=TEAMS)
title = models.CharField()
prologue = models.TextField()
Your current model is creating lots of duplicate columns (for red and black) that should just be defined by a column itself. Using the model above, you queries would be like Story.objects.filter(team="r").
You then wouldn't need your get_field function at all.
No. A Django model shouldn't be treated as something that can be dyamically constructed; it's a Python representation of a database table. For instance, what would be the semantics of changing the format of specificName after you had already run syncdb? There's no definitive, obvious answer - so Django doesn't try to answer it. You columns are defined at the class level, and that's that.
(At some level, you can always drill into the internal ORM data structures and set up these fields - but all you're doing is opening yourself up to a world of ambiguity and not-well-defined problems. Don't do it.)