I'm using MultiSelectField and it works perfect, the problem is when I need to do migrations after my models...
class Title(models.Model):
name = models.TextField(null = True)
degree = models.TextField(null = True)
class Person(models.Model):
name = models.TextField(null = True)
title = MultiSelectField(choices=Title.objects.values_list('name','degree'), max_choices=4, max_length=255, null = True, blank= True)
The trick here is Person is trying to use Title before migrations happens, so it crashes. Instead of models.ForeignKey that actually take care about the dependent model.
I've already tried to handle it with migration dependencies but it doesn't work.
Any workaround?
Related
I am trying to create a Django app where there are two main models - Team and Person.
A Person can use the app as an User or can belong to a Team, and, in that case, the User will be the Team.
class Team(models.Model):
name = models.CharField(max_length=50)
team_user = models.ForeignKey(
User,
on_delete = models.CASCADE,
null = True,
blank = True )
class Person(models.Model):
person_user = models.ForeignKey(User, on_delete = models.CASCADE, null = True, blank = True)
team = models.ForeignKey(
Team,
on_delete = models.CASCADE,
null = True,
blank = True )
I am trying to develop a File structure like this:
/root
/Team_01
/Person_01 (non-User)
/files.csv
/Person_02 (non-User)
/files.csv
/Person_03 (User)
/files.csv
I have read the documentation and I was trying to do something with the comment from Evgeni Shudzel in this post, but my problem is that I don't know how to set the file's path for the Person model so that if the Person is member of a Team, the path is "/team_id/person_id" and if not, the "/team_id" part is excluded. The pseudocode I have in mind:
if Person.team exists:
files = models.FileField(upload_to="TEAM_ID/PERSON_ID/")
else:
files = models.FileField(upload_to="PERSON_ID/")
How can I implement this pseudocode? Thank you!
You are on correct path. upload_to can point to a function.
def user_directory_path(instance: Person, filename):
# file will be uploaded to MEDIA_ROOT / your path
if instance.team: #
return f"team_{instance.team.id}/user_{instance.id}"
else:
return f"person_{instance.id}"
# ...
class Person(models.Model):
files = models.FileField(upload_to = user_directory_path)
I need to design a model Card that should expect a request like following:
{"thing":"Book","responsibilities":["Name","ISBN"],"collaborators":[""]}
So far I designed my model like following:
class Responsibility(models.Model):
name = models.CharField(max_length=50, blank=True, null = True, )
class Collaborator(models.Model):
name = models.CharField(max_length=50, blank=True, null = True, )
class Card(models.Model):
thing = models.CharField(max_length=50, blank=True, null = True, )
responsibilities = models.ForeignKey(Responsibility, related_name='res_cards', blank=True, )
collaborators = models.ForeignKey(Collaborator, related_name='col_cards', blank=True, )
but somehow having name attribute on other two models seems unnecessary for such a simple case. Can I design my model better to accept request like above?
Sorry to say this, but Django doesn't have ArrayField when if DB is MySql.
It has ArrayField if DB is Postgresql.
Here you can see the docs
Something that has worked perfectyle until recently has stopped working. A model that has a foreignkey to another object isn't editable as expected in the standard django admin. The problem is this: ForeignKeys to some model aren't editable in de admin interface, though they should be, although a label does appear in the admin page.
It looks like this:
The HTML-code for the bit where the foreignkey to the Story-model should be edited:
<div class="form-row field-story">
<div>
<label for="id_story" class="required">Story:</label>
</div>
</div>
2 relevant models with their respective unicode defs:
class Question(models.Model):
question = models.CharField(max_length = 200)#the Actual question
correct_answer = models.ForeignKey(Answer, verbose_name = 'Correct Answer', related_name = 'Correct answer')
incorrect_answers = models.ManyToManyField(Answer, verbose_name = 'Distractor options', related_name = 'Incorrect answers')
story = models.ForeignKey(Story)
def __unicode__(self):
try:
return self.question.decode('latin-1') + '(%i)'%(self.id)
except:
return str(self.id)
class Story(models.Model):
class Meta:
verbose_name_plural = 'Stories'
author = models.ForeignKey(User, blank = True, null = True, on_delete = models.SET_NULL, editable = False)
name = models.CharField(max_length = 150, verbose_name = 'Name/Summary')
story = models.TextField(verbose_name = 'Story', max_length = 13 * 54)#the actual story
publish = models.BooleanField(default = False, help_text = 'If this is published, it will be uneditable.')
date_added = models.DateTimeField (auto_now_add = True, editable = False)#date of reply
ready = models.BooleanField(default = False, help_text = 'Whether the author thinks this is ready')
erf = models.CharField(max_length = 20, verbose_name = 'ERF label', editable = False, blank = True, null = True)
def __unicode__(self):
try:
return "'"+self.name.encode( 'latin-1') + "'"
except:
return "Story with unicode name or something: %i" %(self.id)
In admin.py:
admin.site.register(Question, )
Looking at what works and what doesn't, I'm beginning to feel it has got something to do with the Story-model. Other foreignkey relationships are functioning fine. Of course, the fact that the foreignkey isn't editable means the object can't be saved from the admin, even though MySQL shows that there is a valid story_id in the question table.
I remember having used this and that this worked fine. I suspect unicode-problems somewhere, but I can't imagine what exactly, let alone how to fix them. Can anybody help?
PS. What happens at ForeignKey field will not appear in Django admin site isn't the case here, I think.
Urgh.. looking for other foreignfield problems, I encountered ForeignKey field problem in Django. In the comments to the question, it is stated by Daniel Roseman that the unicode defs on models should return unicode. Tried that, and my problem was solved.
Grrr.. Unicode... You win this time!
I have 4 models in my project. Which are :
class Company(Group):
address_1 = models.CharField(max_length = 300, blank = True, null = True)
web_site = models.URLField(blank = True, null = True)
office_number = models.CharField(max_length = 20, blank = True, null = True)
class Person(models.Model):
user = models.ForeignKey(User)
company = models.ForeignKey(Company)
class Project(models.Model):
name = models.CharField(max_length = 100)
person = models.ManyToManyField(User, through = 'UserProject')
class UserProject(models.Model):
user = models.ForeignKey(User)
project = models.ForeignKey(Project)
is_owner = models.BooleanField(default = False)
In a view I would want to get
All the projects related to the request.user
The companies that are working on those projects
and the employees of those companies
I have tried writing some code but the queries are not precise. Help would be appreciated!
All projects related to request.user is easy, of course:
Project.objects.filter(person=request.user)
The companies working on those projects necessarily requires you to loop through the projects:
for p in projects:
p.company_set.all()
You have no relationship between User and Company, or any other foreign key on Company for that matter, so I have no idea where the concept of "employee" comes from or how to get that.
Since, this is pretty basic stuff, I'm assuming your issue is with the fact 1*N queries that are generated. In the current version of Django (1.3.1), there's no way to optimize this futher. In Django 1.4, there's prefetch_related that will allow you to select all the companies (and employees) with the Projects. However, it still requires a unique query for each relationship, so 3 total to get projects, companies, and employees. It works like this:
Project.objects.filter(person=request.user).prefetch_related('company')
In the mean time, I've had some success with using django-batch-select, which basically tries to emulate the behavior of prefetch_related.
OK some bugs in your models:
Project has a M2M on User through UserProject, which is fine, except I think you mean for it to have a M2M on Person which has a FK to User
Secondly, you haven't set up any relations to Company. there is no way to do item 2 on your list until that bug is fixed.
Why is Company extending Group? I must be missing something.
There is no Employee model
Example:
class Company(models.Model):
address_1 = models.CharField(max_length = 300, blank = True, null = True)
web_site = models.URLField(blank = True, null = True)
office_number = models.CharField(max_length = 20, blank = True, null = True)
class Employee(models.Model):
user = models.ForeignKey(User)
company = models.ForeignKey(User)
class Project(models.Model):
name = models.CharField(max_length = 100)
employees = models.ManyToManyField(Employee, through = 'EmployeeProject')
companies = models.ManyToManyField(Company)
class EmployeeProject(models.Model):
employee = models.ForeignKey(Employee)
project = models.ForeignKey(Project)
is_owner = models.BooleanField(default = False)
and in the view
# all of the projects for a user (assuming employee field is supposed to M2M to the Employee model
projects = Project.objects.filter(employees__user=request.user)
for project in projects :
# assuming that there was some connection between project and company (there isnt currently, see me list of bugs with your models)
for company in project.companies_set.all() :
# There is no employee model, but if there was
employees = company.employees_set.all()
I have pondered and used some of the solutions enlisted above, but nothing was exact to what I was looking for. For me the following piece of code works well
projects = Project.objects.filter(person = request.user)
user_projects = UserProject.objects.filter(project__in = projects)
for user_project in user_projects:
person = user_project.user.get_profile()
company.append(person.company)
people.append(person)
company = set(company)
Here are the model definitions:
class ItemBrand(models.Model):
name = models.CharField(max_length = 30, unique = True)
def __unicode__(self):
return self.name
class WantedItem(models.Model):
name = models.CharField(max_length = 120)
description = models.TextField()
created = models.DateTimeField(auto_now = False, auto_now_add = True)
expires = models.DateTimeField(auto_now = False, auto_now_add = False)
type = models.ForeignKey(ItemType, related_name = "type wanted")
GENDER_CHOICES = (
(1, 'Male'),
(2, 'Female')
)
gender = models.IntegerField(choices = GENDER_CHOICES)
brands = models.ManyToManyField(ItemBrand, related_name = "wantedbrands", symmetrical = False)
colors = models.ManyToManyField(ItemColor)
sizes = models.ManyToManyField(ItemSize)
creator = models.ForeignKey(User, related_name = "wishlist creator")
def __unicode__(self):
return self.name
Here is the AdminModel code:
class BrandsInline(admin.TabularInline):
model = WantedItem.brands.through
class WantedItemAdmin(admin.ModelAdmin):
list_display = ('name', 'created', 'expires', 'type', 'gender', 'creator')
search_fields = ('name', 'description')
list_filter = ('created', 'brands',)
ordering = ('-created',)
inlines = [
BrandsInline,
]
exclude = ('brands',)
This is pulled basically right from the Django docs, and here's the error I am getting:
'ReverseManyRelatedObjectsDescriptor' object has no attribute 'through'
I am at a total loss... any ideas? Even if I literally create a linker table and set the "through" attribute in the Model I get the same error.
Broken?
You need to upgrade Django to the trunk.
Using inlines with many-to-many fields is new in the django development version (see docs).
Using a simplified version of your models, I get the same error as you for Django 1.1.1, but it works on the trunk (revision 11785).
As an aside, you don't need to specify symmetrical = False on your ItemBrand ManyToMany field. The symmetrical option is only intended for recursive relationships eg User <-> User.
You may want to have a look at the documentation on related names, and think about renaming them to something more logical as well. If creator is a User object, and want to get the set of wishlists they have created, the default when related_name is not specified is
creator.wishlist_set.all()
with your choice for related_name (when you add the underscore), this changes to
creator.wishlist_creator.all()
but I would recommend related_name='wishlists', in which case you would use
creator.wishlists.all()
While it may not be the cause of your error, spaces in the related_name attribute are invalid so I'd try removing those first.
"type wanted" => "type_wanted"
"wishlist creator" => "wishlist_creator"