django __unicode__: \n and manytomany? - python

Class NickName(models.Model):
name = models.CharField()
def __unicode__(self):
return unicode(self.name)
Class Bob(models.Model):
bob_nickname = models.ManyToManyField(NickName)
def __unicode__(self):
return unicode(self.bob_nickname)
Number1. How would I get the __unicode__ for class Bob to display the actual FK name, rather than the <django.db.models.fields.related.ManyRelatedFieldsManager Object at 0Xdsfjk>?
EDIT: simply doing self.bob_nickname.all() seems to work fine. It aint pretty, but it displays the info: [<NickName: Ron>,<NickName: Randy>]
Number2. Also, how can I get the def __unicode__ to not escape \n? I'd like to create a multiline unicode string
Thank you!

Why don't you use values_list to get all related nick_names as list?
class Bob(models.Model):
bob_nickname = models.ManyToManyField(NickName)
def __unicode__(self):
return u'\n'.join(self.bob_nickname.values_list('name', flat=True))

Related

Choose one no empty of two fields for __str__()

In my model I have two fields for the title, one for language. I want name the post with the title in the user language if there is, else in the other language.
My model.py:
class Post(models.Model):
title_it = Model.CharField(_('title'), max_length=64, blank=True)
title_en = Model.CharField(_('title'), max_length=64, blank=True)
def __str__(self):
name_traslated={'title_it': self.title_it, 'title_en': self.title_en}
name_verbose=_('title_it')
name=name_traslated[name_verbose]
if name=='':
name=name_traslated['title_it']
if name=='':
name=name_traslated['title_en']
if name=='':
name=ugettext('No Title')
There is some faster way to do so? For example what about this:
def __str__(self):
name_traslated={'title_it': self.title_it, 'title_en': self.title_en}
name_verbose=_('title_it')
name=self.title_it
if name_traslated[name_verbose]: #!=''
name=name_traslated[name_verbose]
elif name==''
name=ugettext('No Title')
return name
You can use the python version of a ternary operation to shorten the clauses.
class Post:
title_it = 'ciao mondo'
title_en = 'hello world'
def __str__(self):
name_translated = {'title_it': self.title_it, 'title_en': self.title_en}
name_verbose = 'title_it'
out = name_translated[name_verbose] if name_translated[name_verbose] else name_translated['title_en']
return out if out else 'No Title'
Depending on your frequency of use and desired extension to more languages, you might want to maintain a preference list. In your three-way case above, I'd generalize this with:
pref_list = [
name,
name_translated[user_language],
name_translated[default_language]
]
Now, you simply pull out the first one that has text within it. You can do this by checking string contents or length. The entire operation can be wrapped up in a single expression, if you like.

NameError in Django simple search

I have a simple search in my Django project. I want to search through documents using their type and part of factory info in addition to search by name.
Here is my models.py:
class Docs(models.Model):
Date = models.DateField(default=date.today)
Name = models.CharField(max_length=50)
Type = models.ForeignKey(DocTypes)
Part = models.ForeignKey(Parts)
Link = models.FileField(upload_to='Docs/%Y/%m/%d')
class Parts(models.Model):
Name = models.CharField(max_length=50)
def __str__(self):
return str(self.Name)
class DocTypes(models.Model):
Type = models.CharField(max_length=50)
def __str__(self):
return str(self.Type)
My forms.py:
class DocsSearchForm(ModelForm):
class Meta:
model = Docs
fields = [ 'Name', 'Type', 'Part']
And this is part of my views.py, if no search was done then all documents are given
def showdocs(request):
if request.method == 'POST':
form = DocsSearchForm(request.POST)
documents = Docs.objects.filter(Name__contains=request.POST['Name']|
Type==request.POST['Type']|
Part==request.POST['Part'])
else:
form = DocsSearchForm()
documents = Docs.objects.all()
return render(
request,
'showdocs.html',
{'documents': documents, 'form':form}
So, the problem is the following: if I try to use a search then I have
NameError at /showdocs
name 'Type' is not defined.
POST values are:Part '1', Name 'Example', Type '1'.
If I delete
Type==request.POST['Type']|
Part==request.POST['Part']
then search by name works well. So I have a guess that problem is about searching by foreign key values, but have no ideas more. Will appreciate any help.
Try replacing the line with this
Docs.objects.filter(Name__contains=request.POST['Name'],
Type=request.POST['Type'],
Part=request.POST['Part']
)
It seems you have misunderstood the syntax. I don't know why you are trying to use | operator here.
That's not how Django filters work. You can't | them because they are not actually expressions, just keyword arguments. In this case, correct syntax would be:
Docs.objects.filter(
Name__contains=request.POST['Name'],
Type_Type=request.POST['Type'],
Part_Name=request.POST['Part'],
)`

Django-admin linked column issue

Following this answer I wanted to add a linked column to my admin page,
class AnswerAdmin(admin.ModelAdmin):
list_display = ('__str__', 'link_to_question', 'time_created', 'time_updated', 'created_by', 'down_vote', 'up_vote')
def link_to_question(self, obj):
link = urlresolvers.reverse("admin:QnA_question_change",
args=[obj.question.id]) # model name has to be lowercase
text = obj.question.__str__
str = format_html("{}", text)
return mark_safe(u'%s' % (link, str))
class Meta:
model = Answer
but what I get in return is this:
<bound method Entry.__str__ of <Question: This is a question about technology?>>
I only want the "This is a question ..." part shown in my admin.
Sidenote:
when I use something like obj.question.text instead of a function it works smoothly.
It isn't clear why you are using format_html then passing the result to mark_safe. You should be able to do it in one step with format_html. This has the advantage of escaping text, in case a use has inserted malicious content.
link = urlresolvers.reverse(...)
text = obj.question
link_str = format_html('{}', link, text)
To call the __str__ method you need to call it with obj.question.__str__(). However, it's more pythonic to call str(obj.question) rather than obj.question.__str__(). In this case, I don't think you need to use str() at all, since you are using format_html.
just set the allow_tags = True property of the method.
class AnswerAdmin(admin.ModelAdmin):
list_display = ('__str__', 'link_to_question', 'time_created', 'time_updated', 'created_by', 'down_vote', 'up_vote')
def link_to_question(self, obj):
link = urlresolvers.reverse("admin:QnA_question_change",
args=[obj.question.id]) # model name has to be lowercase
return u'{1}'.format(link, obj.question)
link_to_question.short_description = u'Link'
link_to_question.allow_tags = True

Djangonic way to get second order DB-info in Django?

I'm messing around with my first Django site and so far it's going good. I am now facing the challenge of getting some information from the DB. My model looks like this:
class Countries(models.Model):
country = models.CharField(max_length=100)
def __unicode__(self):
return self.country
class OrganisationTypes(models.Model):
organisation_type = models.CharField(max_length=100)
def __unicode__(self):
return self.organisation_type
class Organisations(models.Model):
organisation_name = models.CharField(max_length=200)
organisation_type = models.ForeignKey(OrganisationTypes)
country_of_origin = models.ForeignKey(Countries)
def __unicode__(self):
return self.organisation_name
class Locations(models.Model):
organisation = models.ForeignKey(Organisations)
country_of_location = models.ForeignKey(Countries)
tel_nr = models.CharField(max_length=15)
address = models.CharField(max_length=100)
def __unicode__(self):
return '%s - %s - %s - %s' % (self.organisation, self.country_of_location, self.tel_nr, self.address)
I now want to display a list of locations of which I want to display the organisation_name and the country_of_origin. To achieve this I wrote the following function:
def organisation_locations(requests, organisation_id):
org = Organisations.objects.get(id=organisation_id)
location_list = Locations.objects.filter(organisation=organisation_id).order_by('country_of_location')
output = '<br />'.join([str(loc.organisation)+' from '+str(org.country_of_origin) for loc in location_list])
return HttpResponse(output)
This works correctly, but it doesn't seem like the correct way of doing this. Since the Location table has a foreign key in the Organisations table which in turn has a foreign key in the Countries table I have this vague feeling that Django can do this in one "query" or lookup.
Am I correct in this feeling, or is my way indeed the correct way of doing this? All tips are welcome!
Can't you do:
location_list = Locations.objects\
.filter(organisation=organisation_id)\
.order_by('country_of_location')
output = '<br />'.join([str(loc.organisation)+' from '+str(loc.organisation.country_of_origin) for loc in location_list])
The organisation query isn't necessary. You can access organisation like this: localization.organisation.
What is not Djangonic in your code is the response. You should have a template and do return render_to_response :)

Finding objects without relationship in django

I am learning Django, and want to retrieve all objects that DON'T have a relationship to the current object I am looking at.
The idea is a simple Twitter copycat.
I am trying to figure out how to implement get_non_followers.
from django.db import models
RELATIONSHIP_FOLLOWING = 1
RELATIONSHIP_BLOCKED = 2
RELATIONSHIP_STATUSES = (
(RELATIONSHIP_FOLLOWING, 'Following'),
(RELATIONSHIP_BLOCKED, 'Blocked'),
)
class UserProfile(models.Model):
name = models.CharField(max_length=200)
website = models.CharField(max_length=200)
email = models.EmailField()
relationships = models.ManyToManyField('self', through='Relationship',
symmetrical=False,
related_name='related_to')
def __unicode__ (self):
return self.name
def add_relationship(self, person, status):
relationship, created = Relationship.objects.get_or_create(
from_person=self,
to_person=person,
status=status)
return relationship
def remove_relationship(self, person, status):
Relationship.objects.filter(
from_person=self,
to_person=person,
status=status).delete()
return
def get_relationships(self, status):
return self.relationships.filter(
to_people__status=status,
to_people__from_person=self)
def get_related_to(self, status):
return self.related_to.filter(
from_people__status=status,
from_people__to_person=self)
def get_following(self):
return self.get_relationships(RELATIONSHIP_FOLLOWING)
def get_followers(self):
return self.get_related_to(RELATIONSHIP_FOLLOWING)
def get_non_followers(self):
# How to do this?
return
class Relationship(models.Model):
from_person = models.ForeignKey(UserProfile, related_name='from_people')
to_person = models.ForeignKey(UserProfile, related_name='to_people')
status = models.IntegerField(choices=RELATIONSHIP_STATUSES)
This isn't particularly glamorous, but it gives correct results (just tested):
def get_non_followers(self):
UserProfile.objects.exclude(to_people=self,
to_people__status=RELATIONSHIP_FOLLOWING).exclude(id=self.id)
In short, use exclude() to filter out all UserProfiles following the current user, which will leave the user themselves (who probably shouldn't be included) and all users not following them.
i'v been searching for a method or some way to do that for like an hour, but i found nothing.
but there is a way to do that.
you can simply use a for loop to iterate through all objects and just remove all objects that they have a special attribute value.
there is a sample code here:
all_objects = className.objects.all()
for obj in all_objects:
if obj.some_attribute == "some_value":
all_objects.remove(obj)
Solution to the implementation of get_non_followers:
def get_non_following(self):
return UserProfile.objects.exclude(to_person__from_person=self, to_person__status=RELATIONSHIP_FOLLOWING).exclude(id=self.id)
This answer was posted as an edit to the question Finding objects without relationship in django by the OP Avi Meir under CC BY-SA 3.0.
current_userprofile = current_user.get_profile()
rest_of_users = Set(UserProfile.objects.filter(user != current_userprofile))
follow_relationships = current_userprofile.relationships.filter(from_person=current_user)
followers = Set();
for follow in follow_relationships:
followers.add(follow.to_person)
non_followeres = rest_of_users.difference(followers)
Here non_followers is the list of userprofiles you desire. current_user is the user whose non_followers you are trying to find.
I haven't tested this out, but it think it should do what you want.
def get_non_followers(self):
return self.related_to.exclude(
from_people__to_person=self)

Categories

Resources