Django elasticsearch-dsl updating M2M on pre_save - python

I am using the django-elasticsearch-dsl package and am having a little bit of a dilemma. Here is my code:
models.py
class Source(models.model):
name = models.CharField(max_length=50)
class Posting(models.Model):
title = models.CharField(max_length=250)
sources = models.ManyToMany(Sources, related_name="postings", through="PostingSource")
class PostingSource(models.Model):
posting = models.ForeignKey(Posting, related_name="posting_sources", on_delete=models.CASCADE)
source = models.ForeignKey(Source, related_name="posting_sources", on_delete=models.CASCADE)
documents.py
class PostingDocument(Document):
sources = fields.ObjectField(properties={"name": fields.KeywordField()})
class Index:
name = "posting"
settings = {"all the settings stuff"}
class Django:
model = Posting
fields = ["title"]
related_models = [PostingSource]
def get_queryset(self):
return super().get_queryset().select_related("sources")
def get_instance_from_related(self, related_instance):
if isinstance(related_instance, PostingSource):
return related_instance.posting
My issue is, when I update the sources on the posting, for some reason, the elasticsearch index is updated pre_save and not post_save. I basically have to do a put request 2 times with the same sources in order for the changes to reflect in my index. I added a def prepare_sources(self, instance): as part of my document and it seems to work, but it feels like it will cause performance issues later. Any help or guidance will be greatly appreciated.

After a couple months of testing, I solved my first question by adding a def prepare_sources(self, instance): where I denormalize my many to many relationship. I also sort of solved my second question by simply having the .select_related("sources") which helps with performance.

Related

Django's Inline Admin: a 'pre-filled' field

I'm working on my first Django project, in which I want a user to be able to create custom forms, in the admin, and add fields to it as he or she needs them. For this, I've added a reusable app to my project, found on github at:
https://github.com/stephenmcd/django-forms-builder
I'm having trouble, because I want to make it so 1 specific field is 'default' for every form that's ever created, because it will be necessary in every situation (by the way my, it's irrelevant here, but this field corresponds to a point on the map).
An important section of code from this django-forms-builder app, showing the use of admin.TabularInline:
#admin.py
#...
class FieldAdmin(admin.TabularInline):
model = Field
exclude = ('slug', )
class FormAdmin(admin.ModelAdmin):
formentry_model = FormEntry
fieldentry_model = FieldEntry
inlines = (FieldAdmin,)
#...
So my question is: is there any simple way to add default (already filled fields) for an admin 'TabularInline' in the recent Django versions? If not possible, I would really appreciate a pointer to somewhere I could learn how to go about solving this.
Important: I've searched for similar questions here and even googled the issue. I've found some old questions (all from 2014 or way older) that mention this possibility not being directly provided by Django. The answers involved somewhat complex/confusing suggestions, given that I'm a Django begginer.
There are a couple of ways to achieve this.
1: Set a default on the field in the model.
Django's dynamic admin forms and inlines are smart enough to detect this and display it automatically as a default choice or entry.
class Book(models.Model):
rating = models.IntegerField(default=0)
2: Use a custom form in your TabularInline class.
class BookInlineForm(models.ModelForm):
class Meta:
model = Book
fields = ('rating', )
def __init__(self, *args, **kwargs):
initial = kwargs.pop('initial', {})
# add a default rating if one hasn't been passed in
initial['rating'] = initial.get('rating', 0)
kwargs['initial'] = initial
super(BookInlineForm, self).__init__(
*args, **kwargs
)
class BookTabularInline(admin.TabularInline):
model = Book
form = BookInlineForm
class ShelfAdmin(admin.ModelAdmin):
inlines = (BookAdmin,)

Django multiple tag field

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

django ModelForm override field has no effect

I have a ForeignKey field in a model of mine, and I'm using ModelForm with it to generate the HTML. The thing is, I want to add an Other option as well - I plan to add JavaScript with it so that a textbook appears when that's selected.
I'm looking at http://docs.djangoproject.com/en/1.2/topics/forms/modelforms/#overriding-the-default-field-types-or-widgets, and started off with trying something like
class Event(models.Model):
name = models.CharField(max_length=200)
time = models.DateField()
.
.
.
cost = models.CharField(max_length=200)
affiliation = models.ForeignKey('Affiliation')
def __unicode__(self):
return self.name
class EventForm(ModelForm):
cost = models.TextField()
class Meta:
model = Event
cost should become a text field instead of char field, so the output should be textarea instead of input[type=text]. This doesn't change, however, no errors are printed, and nothing really happens. I was hoping to proceed by doing
class EventForm(ModelForm):
affiliations = list(Affiliation.objects.all()).append('Other')
affiliation = forms.CharField(choices=affiliations)
class Meta:
model = Event
I'm using django-nonrel on GAE if it helps, but this isn't really an issue with the Model (or so I think...) so I don't think it should change anything. Any help would be much appreciated!
I haven't used django-nonrel, so take this tip with a grain of salt (YMMV).
In your EventForm definition, you're setting cost to be a model.TextField - but you actually want it to be a forms.CharField, with a textarea widget.
Your problem is that EventForm is overriding cost with a models.TextField() when it should be forms.CharField(widget=forms.Textarea())
Can a CharField have choices? Django docs show a 'ChoiceField' which would seem to be what you want...
http://docs.djangoproject.com/en/1.2/ref/forms/fields/#charfield

Django model manager didn't work with related object when I do aggregated query

I'm having trouble doing an aggregation query on a many-to-many related field.
Here are my models:
class SortedTagManager(models.Manager):
use_for_related_fields = True
def get_query_set(self):
orig_query_set = super(SortedTagManager, self).get_query_set()
# FIXME `used` is wrongly counted
return orig_query_set.distinct().annotate(
used=models.Count('users')).order_by('-used')
class Tag(models.Model):
content = models.CharField(max_length=32, unique=True)
creator = models.ForeignKey(User, related_name='tags_i_created')
users = models.ManyToManyField(User, through='TaggedNote',
related_name='tags_i_used')
objects_sorted_by_used = SortedTagManager()
class TaggedNote(models.Model):
"""Association table of both (Tag , Note) and (Tag, User)"""
note = models.ForeignKey(Note) # Note is what's tagged in my app
tag = models.ForeignKey(Tag)
tagged_by = models.ForeignKey(User)
class Meta:
unique_together = (('note', 'tag'),)
However, the value of the aggregated field used is only correct when the model is queried directly:
for t in Tag.objects.all(): print t.used # this works correctly
for t in user.tags_i_used.all(): print t.used #prints n^2 when it should give n
Would you please tell me what's wrong with it? Thanks in advance.
I have figured out what's wrong and how to fix it now :)
As stated in the Django doc:
Django interprets the first Manager defined in a class as the "default" Manager, and several parts of Django will use that Manager exclusively for that model.
In my case, I should make sure that SortedTagManager is the first Manager defined.
2.I should have count notes instead of users:
Count('notes', distinct=True)

admin template for manytomany

I have a manytomany relationship between publication and pathology. Each publication can have many pathologies. When a publication appears in the admin template, I need to be able to see the many pathologies associated with that publication. Here is the model statement:
class Pathology(models.Model):
pathology = models.CharField(max_length=100)
def __unicode__(self):
return self.pathology
class Meta:
ordering = ["pathology"]
class Publication(models.Model):
pubtitle = models.TextField()
pathology = models.ManyToManyField(Pathology)
def __unicode__(self):
return self.pubtitle
class Meta:
ordering = ["pubtitle"]
Here is the admin.py. I have tried variations of the following, but always
get an error saying either publication or pathology doesn't have a foreign key
associated.
from myprograms.cpssite.models import Pathology
class PathologyAdmin(admin.ModelAdmin):
# ...
list_display = ('pathology', 'id')
admin.site.register(Pathology, PathologyAdmin)
class PathologyInline(admin.TabularInline):
#...
model = Pathology
extra = 3
class PublicationAdmin(admin.ModelAdmin):
# ...
ordering = ('pubtitle', 'year')
inlines = [PathologyInline]
admin.site.register(Publication,PublicationAdmin)
Thanks for any help.
Unless you are using a intermediate table as documented here http://docs.djangoproject.com/en/dev/ref/contrib/admin/#working-with-many-to-many-intermediary-models, I don't think you need to create an Inline class. Try removing the line includes=[PathologyInline] and see what happens.
I realize now that Django is great for the administration (data entry) of a website, simple searching and template inheritance, but Django and Python are not very good for complex web applications, where data is moved back and forth between a database and an html template. I have decided to combine Django and PHP, hopefully, applying the strengths of both. Thanks for you help!
That looks more like a one-to-many relationship to me, tho I'm somewhat unclear on what exactly Pathologies are. Also, so far as I understand, Inlines don't work on manytomany. That should work if you flip the order of the models, remove the manytomany and add a ForeignKey field to Publication in Pathology.
class Publication(models.Model):
pubtitle = models.TextField()
def __unicode__(self):
return self.pubtitle
class Meta:
ordering = ["pubtitle"]
class Pathology(models.Model):
pathology = models.CharField(max_length=100)
publication = models.ForeignKey(Publication)
def __unicode__(self):
return self.pathology
class Meta:
ordering = ["pathology"]

Categories