I have a simple userprofile class in django such that
class Profile(models.Model):
user = models.OneToOneField(User,unique=True)
gender = models.IntegerField(blank=True, default=0, choices=UserGender.USER_GENDER,db_column='usr_gender')
education = models.IntegerField(blank=True, default=0, choices=UserEducation.USER_EDU,db_column='usr_education')
mail_preference = models.IntegerField(blank=True, default=1, choices=UserMailPreference.USER_MAIL_PREF,db_column='usr_mail_preference')
birthyear = models.IntegerField(blank=True, default=0,db_column='usr_birthyear')
createdate = models.DateTimeField(default=datetime.datetime.now)
updatedate = models.DateTimeField(default=datetime.datetime.now)
deletedate = models.DateTimeField(blank=True,null=True)
updatedBy = models.ForeignKey(User,unique=False,null=True, related_name='%(class)s_user_update')
deleteBy = models.ForeignKey(User,unique=False,null=True, related_name='%(class)s_user_delete')
activation_key = models.CharField(max_length=40)
key_expires = models.DateTimeField()
You can see that deletedBy and updatedBy are foreign key fields to user class. If I don't write related_name='%(class)s_user_update' it gives me error (I don't know why).
Although this works without any error, it doesn't push the user id's of deletedBy and updatedBy fields although I assign proper user to them.
Could give me any idea and explain the related_name='%(class)s_user_update' part ?
Thanks
'%(class)s_user_update' implies that it is a string awaiting formatting. You would normally see it in the context:
'%(foo)s other' % {'foo': 'BARGH'}
Which would become:
'BARGH other'
You can read more about python string formatting in the python docs. String Formatting Operations
I can't see how the code you have would ever work: perhaps you want:
class Profile(models.Model):
# other attributes here
updated_by = models.ForeignKey('auth.User', null=True, related_name='profile_user_update')
deleted_by = models.ForeignKey('auth.User', null=True, related_name='profile_user_deleted')
# other attributes here
If it does work, it is because django is doing some fancy magic behind the scenes, and replacing '%(class)s' by the class name of the current class.
Notes on the above:
The consistent use of *snake_case* for attributes. If you must use camelCase, then be consistent for all variables. Especially don't mix *snake_case*, camelCase and runwordstogethersoyoucanttellwhereonestartsandtheotherends.
Where you have two attributes that reference the same Foreign Key, you must tell the ORM which one is which for the reverse relation. It will default to 'profile_set' in this case for both, which will give you the validation error.
Use 'auth.User' instead of importing User into the models.py file. It is one less import you'll need to worry about, especially if you don't use the User class anywhere in your models.py file.
You can read more about the related_name stuff here:
https://docs.djangoproject.com/en/1.3/topics/db/queries/#following-relationships-backward
Related
I really don't understand all the ways to build the right query.
I have the following models in the code i'm working on. I can't change models.
models/FollowUp:
class FollowUp(BaseModel):
name = models.CharField(max_length=256)
questions = models.ManyToManyField(Question, blank=True, )
models/Survey:
class Survey(BaseModel):
name = models.CharField(max_length=256)
followup = models.ManyToManyField(
FollowUp, blank=True, help_text='questionnaires')
user = models.ManyToManyField(User, blank=True, through='SurveyStatus')
models/SurveyStatus:
class SurveyStatus(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE)
survey = models.ForeignKey(Survey, on_delete=models.CASCADE)
survey_status = models.CharField(max_length=10,
blank=True,
null=True,
choices=STATUS_SURVEY_CHOICES,
)
models/UserSurvey:
class UserSurvey(BaseModel):
user = models.ForeignKey(User, null=True, blank=True,
on_delete=models.DO_NOTHING)
followups = models.ManyToManyField(FollowUp, blank=True)
surveys = models.ManyToManyField(Survey, blank=True)
questions = models.ManyToManyField(Question, blank=True)
#classmethod
def create(cls, user_id):
user = User.objects.filter(pk=user_id).first()
cu_quest = cls(user=user)
cu_quest.save()
cu_quest._get_all_active_surveys
cu_quest._get_all_followups()
cu_quest._get_all_questions()
return cu_quest
def _get_all_questions(self):
[[self.questions.add(ques) for ques in qstnr.questions.all()]
for qstnr in self.followups.all()]
return
def _get_all_followups(self):
queryset = FollowUp.objects.filter(survey__user=self.user).filter(survey__user__surveystatus_survey_status='active')
# queryset = self._get_all_active_surveys()
[self.followups.add(quest) for quest in queryset]
return
#property
def _get_all_active_surveys(self):
queryset = Survey.objects.filter(user=self.user,
surveystatus__survey_status='active')
[self.surveys.add(quest) for quest in queryset]
return
Now my questions:
my view sends to the create of the UserSurvey model in order to create a questionary.
I need to get all the questions of the followup of the surveys with a survey_status = 'active' for the user (the one who clicks on a button)...
I tried several things:
I wrote the _get_all_active_surveys() function and there I get all the surveys that are with a survey_status = 'active' and then the _get_all_followups() function needs to call it to use the result to build its own one. I have an issue telling me that
a list is not a callable object.
I tried to write directly the right query in _get_all_followups() with
queryset = FollowUp.objects.filter(survey__user=self.user).filter(survey__user__surveystatus_survey_status='active')
but I don't succeed to manage all the M2M relationships. I wrote the query above but issue also
Related Field got invalid lookup: surveystatus_survey_status
i read that a related_name can help to build reverse query but i don't understand why?
it's the first time i see return empty and what it needs to return above. Why this notation?
If you have clear explanations (more than the doc) I will very appreciate.
thanks
Quite a few things to answer here, I've put them into a list:
Your _get_all_active_surveys has the #property decorator but neither of the other two methods do? It isn't actually a property so I would remove it.
You are using a list comprehension to add your queryset objects to the m2m field, this is unnecessary as you don't actually want a list object and can be rewritten as e.g. self.surveys.add(*queryset)
You can comma-separate filter expressions as .filter(expression1, expression2) rather than .filter(expression1).filter(expression2).
You are missing an underscore in surveystatus_survey_status it should be surveystatus__survey_status.
Related name is just another way of reverse-accessing relationships, it doesn't actually change how the relationship exists - by default Django will do something like ModelA.modelb_set.all() - you can do reverse_name="my_model_bs" and then ModelA.my_model_bs.all()
I am trying to get all fields to display but im only getting a few of my fields. I am unsure why so here is my views
my view imports
def switchingowners(request):
ownersofcar = Owner.objects.filter(CarID = request.user['CarID'])
for owner in ownersofcar :
addingOwner = models.Owner(CarID=form['CarID'],Owner_Date=ownerofcar['Owner_Date']
)
ok my models look like
class Owner(models.Model):
carID = models.ForeignKey(Car)
Owner_Entry_Number = models.IntegerField()
Owner_Date = models.DateField('Proprietor start date', null=True, blank=True)
Owner_Last_Name = models.CharField(max_length=50, null=True, blank=True)
Owner_First_Name = models.CharField(max_length=50, null=True, blank=True)
Owner_Middle_Initial = models.CharField(max_length=6, null=True, blank=True)
Owner_Address = models.CharField(max_length=80, null=True, blank=True)
my database backend has information in all fields
ownersofcar = Owner.objects.filter(CarID = request.user['CarID'])
it tells me TypeError
and the filtered objects i see are
self
[<Owner: 1248612 MALCOLM DESRIVIERES >, <Owner: 1248612 JULIETTA REMY >, <Owner: 1248B612 THERESA DESIR >, <Owner: 1248B612 ALEXANDER JEAN>]
where on earth are the other fields? i dont see any documentation on secifying which fields i want to receive cause i want them all!
each field has important information
im basically switching all the names from one car to another car/ multiple cars
but filter is not giving back all the fields
I assume you are getting a type error because you are doing request.user['CarId']. Unless you using a custom user class this is not valid.
The fields are all there, what you see is just a string representation of your result as defined by the __str__ or __unicode__ method of Owner.
Either change this method or print the field that you want, e.g.:
for owner in ownersofcar:
logger.error(owner.Owner_Address)
thanks to one of your guys suggestion i realize the error while fields were missing my coworker overrided the str() method and wasnt paying attention to that
and the override is doign exactly what it needs to. not include the other fields
thanks guys
I would like to create a view with a table that lists all changes (created/modified) that a user has made on/for any object.
The Django Admin site has similar functionality but this only works for objects created/altered in the admin.
All my models have, in addition to their specific fields, following general fields, that should be used for this purpose:
created_by = models.ForeignKey(User, verbose_name='Created by', related_name='%(class)s_created_items',)
modified_by = models.ForeignKey(User, verbose_name='Updated by', related_name='%(class)s_modified_items', null=True)
created = CreationDateTimeField(_('created'))
modified = ModificationDateTimeField(_('modified'))
I tried playing around with:
u = User.objects.get(pk=1)
u.myobject1_created_items.all()
u.myobject1_modified_items.all()
u.myobject2_created_items.all()
u.myobject2_modified_items.all()
... # repeat for >20 models
...and then grouping them together with itertool's chain(). But the result is not a QuerySet which makes it kind of non-Django and more difficult to handle.
I realize there are packages available that will do this for me, but is it possible to achieve what I want using the above models, without using external packages? The required fields (created_by/modified_by and their timefields) are in my database already anyway.
Any idea on the best way to handle this?
Django admin uses generic foreign keys to handle your case so you should probably do something like that. Let's take a look at how django admn does it (https://github.com/django/django/blob/master/django/contrib/admin/models.py):
class LogEntry(models.Model):
action_time = models.DateTimeField(_('action time'), auto_now=True)
user = models.ForeignKey(settings.AUTH_USER_MODEL)
content_type = models.ForeignKey(ContentType, blank=True, null=True)
object_id = models.TextField(_('object id'), blank=True, null=True)
object_repr = models.CharField(_('object repr'), max_length=200)
action_flag = models.PositiveSmallIntegerField(_('action flag'))
change_message = models.TextField(_('change message'), blank=True)
So, you can add an additional model (LogEntry) that will hold a ForeignKey to the user that changed (added / modified) the object and a GenericForeignKey (https://docs.djangoproject.com/en/1.7/ref/contrib/contenttypes/#generic-relations) to the object that was modified.
Then, you can modify your views to add LogEntry objects when objects are modified. When you want to display all changes by a User, just do something like:
user = User.objects.get(pk=1)
changes = LogEntry.objects.filter(user=user)
# Now you can use changes for your requirement!
I've written a nice blog post about that (auditing objects in django) which could be useful: http://spapas.github.io/2015/01/21/django-model-auditing/#adding-simple-auditing-functionality-ourselves
I have the following models:
class Sked(models.Model):
pass
class Class(models.Model):
class_key = models.CharField(max_length=20, null=True)
name = models.CharField(max_length=150)
class Sked_class(models.Model):
class_room = models.CharField(max_length=100, null=True)
sked = models.ForeignKey(Sked)
class_took = models.ForeignKey(Class)
class User(djmodels.User):
sked = models.ForeignKey(Sked, null=True)
I want to make a query that selects all the classes that a specific user is taking, but i still can't get the idea of how to do it without using SQL, I already read this document https://docs.djangoproject.com/en/dev/topics/db/queries/ , but I still don't get it, How can I span multi-valued relationships through this models?
You're looking for two things - how to span foreign keys, and how to only return a unique set of classes that doesn't include duplicates.
You span foreign keys using __ to separate the relationships, and use distinct() on the query set to filter out duplicates. Remember that foreign key relationships work both ways with Django syntax, as the ORM will recognize reverse relationships. This should work:
user = User.objects.get(id=1)
Class.objects.filter(sked_class__user=user).distinct()
It's unclear to me if you data model makes sense, however. I think this makes more sense:
class Class(models.Model):
key = models.CharField(max_length=20, null=True)
name = models.CharField(max_length=150)
class Schedule(models.Model):
student = models.ForeignKey(User)
classes = models.ManyToManyField(Class)
Then you'd say:
user = User.objects.get(id=1)
Class.objects.filter(schedule__student=user)
I've got Django tables like the following (I've removed non-essential fields):
class Person(models.Model):
nameidx = models.IntegerField(primary_key=True)
name = models.CharField(max_length=300, verbose_name="Name")
class Owner(models.Model):
id = models.IntegerField(primary_key=True)
nameidx = models.IntegerField(null=True, blank=True) # is Person.nameidx
structidx = models.IntegerField() # is PlaceRef.structidx
class PlaceRef(models.Model):
id = models.IntegerField(primary_key=True)
structidx = models.IntegerField() # used for many things and not equivalent to placeidx
placeidx = models.IntegerField(null=True, blank=True) # is Place.placeidx
class Place(models.Model):
placeidx = models.IntegerField(primary_key=True)
county = models.CharField(max_length=36, null=True, blank=True)
name = models.CharField(max_length=300)
My question is as follows. If in my views.py file, I have a Person referenced by name and I want to find out all the Places they own as a QuerySet, what should I do?
I can get this far:
person = Person.objects.get(name=name)
owned_relations = Owner.objects.filter(nameidx=nameidx)
How do I get from here to Place? Should I use database methods?
I'm also not sure if I should be using ForeignKey for e.g. Owner.nameidx.
Thanks and apologies for this extremely basic question. I'm not sure how to learn the basics of database queries except by trying, failing, asking SO, trying again... :)
The whole point of foreign keys is for uses like yours. If you already know that Owner.nameidx refers to a Person, why not make it a foreign key (or a OneToOne field) to the Person table? Not only do you get the advantage of referential integrity - it makes it impossible to enter a value for nameidx that isn't a valid Person - the Django ORM will give you the ability to 'follow' the relationships easily:
owned_places = Place.objects.filter(placeref__owner__person=my_person)
will give you all the places owned by my_person.
Incidentally, you don't need to define the separate primary key fields - Django will do it for you, and make them autoincrement fields, which is almost always what you want.
If u could redesign.Then
In owner nameidx can be a foreign key to Person(nameidx)
Placeref(structidx) could be a foreign key to Owner(structidx) and
Place(placeidx) could be a foreign key Place ref(placeidx)
Then u could deduce the place value easily..