Django .objects,get for merged querysets from different models - python

I have an abstract base model ('Base') from which two models inherit: 'Movie' and 'Cartoon'. I display a list of both movies and cartoons to the user (with the help of itertools.chain). Then I want to give the user the opportunity to delete any of these items, without knowing in advance whether it is a movie or a cartoon. I am trying to do it like this:
...
movies = Movie.objects.filter(user_created=userlist).order_by('title')
cartoons = Cartoon.objects.filter(user_created=userlist).order_by('title')
all_items = list(chain(movies, cartoons))
item = all_items.get(id=item_id)
item.delete()
But then PyCharm states,
Unresolved attribute reference 'get' for class 'list'
I understand why this happens but I don't know how to avoid it. Is there any way to merge two querysets from different models and apply get or filter without removing the abstract base model and creating a physical parent model?

You could use the ContentTypes framework for a generic and reusable solution to this for an arbitrary number of different models. But I also wonder why Cartoon and Movie must be different types to begin with; it may be worth spending a little time thinking about whether you can use a single model for both types of media - deletion of an arbitrary instance is just one of many cases where a single model will be more straightforward than relying on something like ContentTypes.
EDIT: For more info on ContentTypes. You could either create a base model with a generic relation (you said you didn't want to do this), or for the deletion you could include app label and model name in the request data alongside item id, enabling lookups like:
media_type = ContentType.objects.get(app_label=app_label, model=model_name)
instance = media_type.get_object_for_this_type(id=item_id)
instance.delete()
what's nice about this approach is you'd barely have to change your model structure.

you can first find the index using index() method and then can get item by all_items[given_index].delete()

Related

Dynamically generate accompanying model in django

In my project i have many models in multiple apps, all of them inherit from one abstract model. I would like to create a model that would hold the changes to the history for every one of my models, so that every model would have its own history model. Each model would also have one-to-many relation to its history model. All history models would be the same, except for the foreign key to their respective model.
My problem is that I do not want to write all the history models manually. Instead i would like to have the history model created for every model automatically, so I don't have to write all that boilerplate code. Can this be achieved?
There is a widely-used django package that I believe solves this exact problem called django-reversion with a nice API. I recommend using it if it fits your needs rather than building a custom solution.
Object version control is usually better solved by serializing your objects and storing the serialization every time they are edited (e.g. in the json format).
You may also want to keep track of when objects are deleted.
This way, you only need to store a reference to the serialized object. Versions of all objects can live in the same database table and reference their "source" object using Django's generic relations.
You can eventually create your classes dynamically with type()
There is many ways to do it, but you can do something as follows:
class SomeParentClass: pass
NewClass = type('NewClass', (SomeParentClass,), {'new_method': lambda self:
'foo' } )
new_class_instance = NewClass()
print(new_class_instance.new_method())
So you can create models dynamically, with a different name, inherit from a different class, new methods...
You can then use globals()[variable_name_to_store_class] to assign newly created classes to a dynamic variable name.
Hope its relavant for your problem.

How to define a model of episodes w a series as foreign key in django effectively

Hi and thanks for your time!
I have a model of series and a model of episodes (different apps) with a series as a ForeignKey for the episodes. I have a few issues:
Isn't a bit of a mess to have all episodes in the same model whithout taking into account the series they belong to (ofc there's the foreignkey, but they are all shuffled together)? If it is, how could I solve it?
With my current model, I don't know how to create a field that automatically adds the number of episode taking into account the episodes that already exist of a CONCRETE SERIES.
I have a DetailView of each series in my app "series" (url = series/<slug(of the series)>/, and I want to define a DetailView for each episode. Should I define the url in the episodes app or in the series app?
Once I have the url, how do I get the the episode object in the DetailView most effectively? I first thought of getting all episodes in the get_qs and then filtering in the context_data, but I don't know how to get the series out of the URL to filter, and this method seems quite long to me. How could I do it?
Thank you very much for your time, I really appreciate it!
Isn't a bit of a mess to have all episodes in the same model whithout taking into account the series they belong to (ofc there's the foreignkey, but they are all shuffled together)? If it is, how could I solve it?
If the episodes are all of a kind and you have unique fields across them, like for example you require the primary key (or ID) or the slug to be unique for all of them, independent of their series, then it's good if they are all in one table.
If, on the other hand, you want to be able to delete a complete series' episodes and reset their PK to 1 (e.g. if you import them on a regular basis and don't want to increment the PKs like crazy) or if you might have a bit different models per series, you might want to use a simple abstract model. You could share code but they would reside in different DB tables. (You could also have a look at GenericForeignKeys, but that might be over the top.)
See https://docs.djangoproject.com/en/2.0/topics/db/models/#model-inheritance
With my current model, I don't know how to create a field that automatically adds the number of episode taking into account the episodes that already exist of a CONCRETE SERIES.
You could override save() in your model (or the abstract base class) and simply increment it, depending on how many episodes for this series you already have:
def save(self, *args, **kwargs):
if not self.episode_no:
# if you are using a fkey without specific reverse name and
# self.series is configured to not allow null/blank
series_count = self.series.episode_set.count()
self.episode_no = series_count + 1
super().save(*args, **kwargs)
Note that bulk_create does not call model.save() - but in this case you should be setting the episode number for each object in the bulk beforehand, anyway. It's probably best not to automate too much in this case because you might not always add the episodes in their actual order?
I have a DetailView of each series in my app "series" (url = series//, and I want to define a DetailView for each episode. Should I define the url in the episodes app or in the series app?
Depends on what the URL of the episode should look like. Should it be at first level? More REST-like would be:
urls.py
url_pattern = [
url(r'^series/$', SeriesListView.as_view(), name='series_list'),
url(r'^series/(?P<slug>[\w_]+)/$', SeriesDetailView.as_view(), name='series_detail'),
url(r'^series/(?P<series_slug>[\w_]+)/episodes/$', EpisodeListView.as_view(), name='episodes_list'),
url(r'^series/(?P<series_slug>[\w_]+)/episodes/(?P<slug>[\w_]+)/$', EpisodeDetailView.as_view(), name='episodes_detail'),
]
With Django 2.0 you should be able to use <slug:slug> and <slug:series_slug>.
Once I have the url, how do I get the the episode object in the DetailView most effectively? I first thought of getting all episodes in the get_qs and then filtering in the context_data, but I don't know how to get the series out of the URL to filter, and this method seems quite long to me. How could I do it?
Use the generic DetailView. The following snippet together with the linked documentation should get you going.
class EpisodeDetailView(DetailView):
def get_queryset(self):
series = get_object_or_404(SeriesModel, slug=self.kwargs.get('series_slug'))
return super().get_queryset().filter(series=series)

Number of attributes in Django Models

I searched a lot and did not find what I´am looking for.
What would be the best concept for a model class in django?
To extend User, would be better to have a class with several attributes, or break this class into several classes with few attributes? I´m using the django ORM now.
Say I have a class called Person that extends User, would be better:
class Person(models.Model):
user = foreingkey(User)
attribute1 =
...
attributeN =
Or, would it be better to do this:
class PersonContac(models.Model):
user = foreingkey(User)
attribute1 =
...
attribute3 =
class PersonAddress(models.Model):
user = foreingkey(User)
attribute1 =
...
attribute3 =
class PersonHobby(models.Model):
user = foreingkey(User)
attribute1 =
...
attribute3 =
My each of my views would use the data from the smaller classes (probably).
Over time, the atrribute number can expand.
I want to do is do it once, and touch the minimum possible.
Various attributes can be unfilled by the user, they are not required.
The number of user is indefinite (can be a lot).
I´m concerned in terms of long term performance and maintaining.
If someone can explain me, what would be better for my code, and why.
And what would be better in general (less classes/more attributes, or more classes/less attributes), using the Django ORM.
It is better if my views use the data of only one model class, or it makes no (or little) difference?
Edit:
On the rush for writing I used bad names on class. None of these attributes are many-to-many fields, the User will have only one value for each attribute, or blank.
The number of atributes can expand over time, but not in a great number.
Put any data that is specific to only one User directly in the model. This would probably be things like "Name", "Birthday", etc.
Some things might be better served by a separate model, though. For example multiple people might have the same Hobby or one User might have multiple Hobby(s). Make this a separate class and use a ForeignKeyField or ManyToManyField as necessary.
Whatever you choose, the real trick is to optimize the number of database queries. The django-debug-toolbar is helpful here.
Splitting up your models would by default result in multiple database queries, so make sure to read up on select related to condense that down to one.
Also take a look at the defer method when retrieving a queryset. You can exclude some of those fields that aren't necessary if you know you won't use them in a particular view.
I think it's all up to your interface.
If you have to expose ALL data for a user in a single page and you have a single, large model you will end up with a single sql join instead of one for each smaller table.
Conversely, if you just need a few of these attributes, you might obtain a small performance gain in memory usage if you join the user table with a smaller one because you don't have to load a lot of attributes that aren't going to be used (though this might be mitigated through values (documentation here)
Also, if your attributes are not mandatory, you should at least have an idea of how many attributes are going to be filled. Having a large table of almost empty records could be a waste of space. Maybe a problem, maybe not. It depends on your hw resources.
Lastly, if you really think that your attributes can expand a lot, you could try the EAV approach.

How to define a Model with fields filled by other data sources than database in django?

Does anyone can tell me if it's possible to create a Model class, with some model fields and some other fields taking their data from external data sources. The point is that I would like this model to be exploited the same way as another model by ModelForm for instance. I mean if I redefine "objects" Manager of the model by specifying the actions to get the datas for special fields (those who may not be linked to datas from the database), would the modelForm link the input with the fields not attached to the database ? Similar question about related objects. If I have a Model that has a relation with that special Model, can I get this Model instances through the classic way to get related objects (with both the classic model fields and the non-database fields) ?
Please tell me if I'm not clear, I'll reformulate.
Thanks.
EDIT: I tried to make a Model with custom fields, and then override the default Manager and its functions: all, get, ... to get objects like it would be with classical Model and Manager, it works. However, I don't use QuerySet, and it seems that the only way to get ModelForm, related objects and the admin functionnalities, working with it, is to build the QuerySet properly and let it being returned by the manager. That's why now I'm wondering if it's possible to properly and manually build a QuerySet with data got from external sources, or tell django-admin, model forms and related objects to take care of another class than queryset on this Model.
Thanks
The way is to define custom methods:
Define custom methods on a model to add custom "row-level"
functionality to your objects. Whereas Manager methods are intended to
do "table-wide" things, model methods should act on a particular model
instance.
This is a valuable technique for keeping business logic in one place
-- the model.
I have now a partial solution. I override the Manager and in particular its all() and get() functions (because I only need those functions for now). all() returns a queryset in which I added the result of some logics that give me objects build from external datas (taken through xmlrpc in my case). I added those objects to the qs through _result_cache attribute.
I think it's not clean and in fact my Model is now a custom Model and I don't have any database field. I may use it to fill database Models... However I can use it the same way as classic models: MyModel.objects.all() for example.
If anyone has another idea I'd really appreciate.
Regards

Querying through several models

I have a django project with 5 different models in it. All of them has date field. Let's say i want to get all entries from all models with today date. Of course, i could just filter every model, and put results in one big list, but i believe it's bad. What would be efficient way to do that?
I don't think that it's a bad idea to query each model separately - indeed, from a database perspective, I can't see how you'd be able to do otherwise, as each model will need a separate SQL query. Even if, as #Nagaraj suggests, you set up a common Date model every other model references, you'd still need to query each model separately. You are probably correct, however, that putting the results into a list is bad practice, unless you actually need to load every object into memory, as explained here:
Be warned, though, that [evaluating a QuerySet as a list] could have a large memory overhead, because Django will load each element of the list into memory. In contrast, iterating over a QuerySet will take advantage of your database to load data and instantiate objects only as you need them.
It's hard to suggest other options without knowing more about your use case. However, I think I'd probably approach this by making a list or dictionary of QuerySets, which I could then use in my view, e.g.:
querysets = [cls.objects.filter(date=now) for cls in [Model1, Model2, Model3]]
Take a look at using Multiple Inheritance (docs here) to define those date fields in a class that you can subclass in the classes you want to return in the query.
For example:
class DateStuff(db.Model):
date = db.DateProperty()
class MyClass1(DateStuff):
...
class MyClass2(DateStuff):
...
I believe Django will let you query over the DateStuff class, and it'll return objects from MyClass1 and MyClass2.
Thank #nrabinowitz for pointing out my previous error.

Categories

Resources