I am wondering if the following is the correct way to create tagging system for images and being able to render a tag cloud:
from django.db import models
class Tag(models.Model):
word = models.CharField(max_length=35)
slug = models.CharField(max_length=250)
created_at = models.DateTimeField(auto_now_add=False)
def __unicode__(self):
return self.word
class Photo(models.Model):
slug = models.CharField(max_length=250)
filename = models.CharField(max_length=200)
extension = models.CharField(max_length=4)
size = models.IntegerField()
...
tags = models.ManyToManyField(Tag)
def __unicode__(self):
return self.slug
Note that my database table will include millions of rows and each image will have 4-8 tags.
Please advise.
If all you want to do is create a tag cloud, than that data model should be sufficient. I would make one modification:
tags = models.ManyToManyField(Tag,related_name='photos')
That will make reverse lookups in you photo views cleaner to read and easier to remember.
However, I would consider other use cases for your tags. Is a tag cloud the only thing you want to use the tagging for? Is there any meta data that the relationship should contain?
If you're planning on having millions of rows, then caching is going to be as important as the data model.
Also, to avoid reinventing the wheel, see if anyone else has built a library that serves your purposes: http://www.djangopackages.com/grids/g/tagging/
Handling tags youself could be a hard job.
You can easily use django library. Install it with pip
pip install django-taggit
Related
class Cities(models.Model):
city_main_image = models.FileField()
city_name = models.CharField(max_length=200)
city_info = models.CharField(max_length=1000)
city_images = models.FileField()
In my models.py I have Cities class and I want to upload several images for this class variable, to be clearly for city_images variable how can I do this? Are there any way to do this or not?
Few notes about your code before answering your question.
1) Stick to singular model names, City rather than Cities.
2) Don't repeat the model name in every field, so you get "main_image",
"name", "info", "images".
3) Use ImageField for images rather than FileField.
4) No need to have 2 fields for main_image and images. You can add an extra field to make the image a main image or not.
Now, to answer your question, you need to read about relations in an SQL database.
To use relations between your models with django's ORM, look at https://docs.djangoproject.com/en/2.0/ref/models/fields/#django.db.models.ForeignKey
You have 2 options: ForeignKey or ManyToManyField. Stick with the ForeignKey as you don't need a many to many relation.
So you'll have something like the following:
class City(models.Model):
...
class CityImage(models.Model):
image = models.ImageField(...)
city = models.ForeignKey(City) # you might need to add on_delete parameter depending on your django version.
or
class CityImage(models.Model):
image = models.ImageField(...)
class City(models.Model):
...
images = models.ManyToManyField(CityImage)
class Cities(models.Model):
city_main_image = models.FileField()
city_name = models.CharField(max_length=200)
city_info = models.CharField(max_length=1000)
class CityImages(models.Model):
city_id = models.ForeignKey(Cities)
city_images = models.FileField()
Now each of your city in Cities can have one or more images in another model called CityImages. If we talk in terms of tables then the primary key for a row in table Cities would be associated to one or more rows in table city_images. I will strongly suggest you to go through official introductory tutorial of django. Also I personally find this tutorial very helpful for beginners. Just in case it helps.
One way you could do this is to make a CityImage model, which would allow you to make a ForeignKey to the City model, with a related_name=images for the reverse lookup.
class City(models.Model):
name = models.CharField(max_length=200)
info = models.CharField(max_length=1000)
#property
def main_image(self):
try:
return self.images.get(primary=True)
except CityImage.DoesNotExist:
pass
except CityImage.MultipleObjectsReturned:
# Handle this case, the application should ensure only one is set to `True` at a time...
class CityImage(models.Model):
city = models.ForeignKey(City, related_name='images')
primary = models.BooleanField(default=False)
image = models.FileField()
this question might get a bit large,i will try to explain perrty much everything whats going on.below is my heading model which fills the slug field itself by whatever is the title:
class Heading(models.Model):
category = models.ForeignKey(Category)
title = models.CharField(max_length=5000)
content =RichTextUploadingField ()
image= models.ImageField(null=True,blank=True)
date = models.DateField(default=datetime.now())
time = models.TimeField(default=datetime.now())
slug = models.SlugField(unique=True, null=True, blank=True)
def save(self, *args, **kwargs):
self.slug = slugify(self.title)
super(Heading, self).save(*args, **kwargs)
my title is in a foreign language(nepali language to be specific)
below is the image of my admin panel to fill up the heading class
as you can see my title is in foreign language but my slug field is filled automatically by converting that title in english language which is not what i want,i want my slug field to be filled in the same language as my title field.i did some search and a module called unidecode might be the solution to it,i tried using it too but since its documentation is not well i couldn't get hook of it.so if there is any other solution or how to make proper use of unidecode?any kind of help or clue would be greatly appreciated
The problem is, slugification happens in JavaScript (at least in the standard Django admin), before it reaches the server (you can look up urlify.js in the admin contrib package).
There's a new option on SlugField called allow_unicode, which might do what you want, but it's been introduced in Django 1.9.
If you cannot upgrade to 1.9 yet, you could in theory set up some endpoint on your server that would take a string, run unidecode on it, and return it, and then cook up some custom JavaScript code that would override the default slugification in the admin, but that sounds like quite a lot of work.
Another option would be to hide the slug field from the admin altogether, and do something similar to that snippet of code you posted in your question, except you should probably do this in the ModelAdmin class instead of the model itself (and you probably want to use unidecode there before passing the string to slugify).
Firstly you have to import "SLUGIFY" [from django.utils.text import slugify].
Secondly, In model,
slug = models.SlugField(allow_unicode=True, unique=True, null=True,
blank=True)
After that:
def save(self, *args, **kwargs):
self.slug = slugify(self.title)
if not self.slug:
slug_str = f"{self.title}"
self.slug = slugify(slug_str, allow_unicode=True)
super(Blog, self).save(*args, **kwargs)
Finally Don't forget to add
[ALLOW_UNICODE_SLUGS = True]
in settings.py.
I've got this Post model at the moment:
class Post(models.Model):
title = models.CharField(max_length = 140)
body = models.TextField()
date = models.DateTimeField()
def __unicode__(self):
return self.title
If I've got different parts of a website (or a forum rather) that contain different posts, e.g. Discussion about basketball, and Discussion about football, if I wanted to return just posts concerning basketball or just posts concerning football, is the easiest way to just make a specific basketball_post model/football_post model or is there a more efficient way? Should I perhaps be storing the values differently?
Thanks
Django has a really good tutorial. It is about making a Poll app. In the first chapter the thing you want is discussed. It is about a Question that can have multiple Choices.:
class Question(models.Model):
question_text = models.CharField(max_length=200)
pub_date = models.DateTimeField('date published')
class Choice(models.Model):
question = models.ForeignKey(Question)
choice_text = models.CharField(max_length=200)
votes = models.IntegerField(default=0)
The foreignKey creates a relation between two models. The same can be done for a blog:
class Category(models.Model):
title = models.CharField(max_length=200)
class Post(models.Model):
category = models.ForeignKey(Category) # This is the important part.
title = models.CharField(max_length=200)
body = models.TextField()
date = models.DateTimeField()
def __unicode__(self):
return self.title
The ForeignKey relation lets you do really nice things:
basketball_posts = Post.objects.filter(category_title='Basketball')
But before we all tell you how it is done, I really recommend to do the tutorial. It introduces you to all important Django concepts: https://docs.djangoproject.com/en/1.7/intro/tutorial01/
Update
If you have a fixed set of categories that are not likely to change, than you can hardcode them and use field choices:
class Post(models.Model):
FOOTBALL = 'F' # Variable name and db_value
CRICKET = 'C'
INTRODUCTION = 'I'
CATEGORY_CHOICES = (
(FOOTBALL, 'Soccer'), # Variable name and display value
(CRICKET, 'Cricket'),
(INTRODUCTION, 'Hello my name is'),
)
category = models.CharField(max_length=1,
choices=CATEGORY_CHOICES,
default=INTRODUCTION)
...
https://docs.djangoproject.com/en/dev/ref/models/fields/#choices
One of the advantages of this 'choice machinery' over a CharField without pre defined choices is that you are sure what values end up in your database. This lets you query them, without worrying if your data is sane:
Post.objects.filter(category=Post.CRICKET)
Use the extra table if you need the freedom to create new categories in the future. Use field choices if you don't want (or need) that freedom.
I would suggest to just add a field which makes the post relevant to that certain topic:
class Post(models.Model):
title = models.CharField(max_length = 140)
body = models.TextField()
date = models.DateTimeField()
type = models.CharField(max_length=20) #<--- new field: e.g 'basketball','hockey'..
def __unicode__(self):
return self.title
example query:
#basketball posts
qs = Post.objects.filter(type__icontains="basketball")
then you dont need to have multiple models which also would be redundant.
Assuming all of the posts are in the same format, you could add another field to your model like "type". Different discussion forums could send a different values for that field when the post is added.
type = models.CharField(max_length=140, choices=['Football', 'Basketball', 'Baseball'])
Storing this would make it easy to filter which posts are which.
Post.objects.filter(type = 'Football')
Assuming that one post can be about only one sport, the better approach would be to have a foreign key relation between a model that stores data about a post with another model that stores the data about sports.
Something like this
class Sport(models.Model):
name = models.CharField(max_length = 200)
description = models.TextField()
def __unicode__(self):
return self.name
class Post(models.Model):
title = models.CharField(max_length = 140)
body = models.TextField()
date = models.DateTimeField()
sport = models.ForeignKey(Sport)
def __unicode__(self):
return self.title
This gives you the advantage of isolating the 'Sport' and the 'Post' models.You can add as many sports as you want, without any posts referring to it.
One more advantage is that you can add relevant information to the relevant models.
Eg:Suppose you want to add the information about "how many players are there in a team for sport x?". You can easily achieve this by adding a field "number_of_players" in the 'Sport' model without affecting the 'Post' model.
If you had to do this in one model, 'Post', then it would create lot of issues in terms of data consistency and other undesirable things.
Also, the query will look something like this:
posts = Post.objects.filter(sport__name = "Basketball")
PS:If your requirement is that a post can be tagged to multiple sports, then you can use ManyToMany field instead of a simple foreign key.
https://docs.djangoproject.com/en/dev/topics/db/examples/many_to_many/
You could assign your posts tags or category, and filter on those.
If you use the model approach what happens when you add more sports? You'll need manually add the sports in your code, using a tags or category approach allows you to handle it in the db, and would then allow you to filter on the tags/categories in your system
Which is the best option for urls on a news page:
Dynamically generate slugs. Load the page from the object id. If the slug doesn't match, permanent redirect to the correct slug.
myweb.com/542/my-news-item
Cons i see: If the news title is changed the slug changes, but the old slug will redirect to the new one, so i dont know if it is a problem for lookups.
OR:
Static slug that will never change, even if the news title is changed.
myweb.com/my-news-item
Cons i see: One more field on the db. If i change the news title radically, the slug will be very different
If you want slugs to update, without breaking the old urls, you could separate slugs and link the latest in your list views, something along these lines should do it:
class Article(models.Model):
title = models.CharField() # etc
class ArticleSlug(models.Model):
article = models.ForeignKey(Article)
slug = models.SlugField(unique=True)
date_created = models.DateTime(auto_now_add=True, editable=False)
class Meta:
get_latest_by = "date_created"
In your enlisting template you could simply call the latest slug, but you'll probably want to have some M/Y/D hierarchy in the urls aswell
{{ article.title }}
If your site gets a lot of traffic, you might want to add a celery task that retrieves the latest slug and copies it to a field on your article model now and then. That will save you some SQL JOINs.
How about a combination of using the redirects app and a post save signal like what this guy wrote.
I'm trying to find a good tutorial for django how to create multiple tags in a model.
For example:
class Tag(models.Model):
name = models.CharField()
class Sample(models.Model):
name = models.CharField()
urlA = models.CharField()
urlB = models.CharField()
tagA = models.ManyToManyField(Tag)
tagB = models.ManyToManyField(Tag)
I would like to display the tags as an input field and separate by ',' and split in the save method. So I'd like to see 2 different input for the 2 tag field.
If you have an easy way to do or know a good tutorial, please tell me! :)
Thank you guys!
Edit: you do not have to have the actual table sets over laid. You can generate any queryset you want to inn your views. Your url conf can be set up to display the detail view from multiple url. If i am still not understanding then please refine your question.
For having multiple anything tags categories your either going m21 or m2m. So when you create your tags you can add them one by one. Are you familiar with what the Django ORM has to offer with some of its admin functionality? Please give the documentation a good look through. Your approach to this problem is anything but reasonable. Not trying to rub you the wrong way I'm no genius. You would do something like so.
class Tag(models.Model):
title = models.CharField(max_length=250, blank=True)
slug = models.SlugField(blank=True
class Meta:
verbose_name = "tag"
verbose_name_plural = "tags"
ordering = ['title']
#models.permalink
def get_absolute_url(self):
return "/tags/%s/" % self.slug
class Entry(models.Model):
title = models.CharField(max_length=250, blank=True)
body = models.TextField()
tags = models.ManyToMany('Tag')
slug = models.SlugField()
#models.permalink
def get_absolute_url(self):
return "/blog/%s/" % self.slug
There's a little more code to be done for the EntryAdmin and the TagAdmin models, Many other things that can be done as well. I am not sure what you are trying to achieve with that if you could be more clear? Thank you, the above is a rough illustration of how I would approach it.
I found a solution from here:
https://dev.to/thepylot/how-to-add-tags-to-your-models-in-django-django-packages-series-1-3704
django-taggit is very useful for tagging.
It is
a reusable application that primarily offers you a Tag model, and a manager for easily adding tags to any model.
pip install django-taggit
After that, open settings.py and edit the installed apps section:
INSTALLED_APPS = [
...
'taggit'
]
After that, edit your model and add tags like this:
tags = TaggableManager()
The TaggableManager will show up automatically as a field in a ModelForm or in the admin.
Documentation: https://django-taggit.readthedocs.io/en/latest/index.html